As the rate allocation has been moved into entirely into SimulcastRateAllocator, and the listeners are thus no longer needed, this class doesn't fill any other purpose than to determine if ScreenshareLayers or TemporalLayers should be created for a given simulcast stream. This can however be done just from looking at the VideoCodec instance, so changing this into a static factory method. Due to dependencies from upstream projects, keep the class name and field in VideoCodec around for now. Bug: webrtc:9012 Change-Id: I028fe6b2a19e0d16b35956cc2df01dcf5bfa7979 Reviewed-on: https://webrtc-review.googlesource.com/63264 Commit-Queue: Erik Språng <sprang@webrtc.org> Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Stefan Holmer <stefan@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22529}
188 lines
6.7 KiB
C++
188 lines
6.7 KiB
C++
/* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "modules/video_coding/codecs/vp8/temporal_layers.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include "modules/include/module_common_types.h"
|
|
#include "modules/video_coding/codecs/vp8/default_temporal_layers.h"
|
|
#include "modules/video_coding/codecs/vp8/include/vp8_common_types.h"
|
|
#include "modules/video_coding/codecs/vp8/screenshare_layers.h"
|
|
#include "modules/video_coding/include/video_codec_interface.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
#include "rtc_base/ptr_util.h"
|
|
#include "system_wrappers/include/clock.h"
|
|
#include "system_wrappers/include/field_trial.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
uint8_t NumTemporalLayers(const VideoCodec& codec, int spatial_id) {
|
|
uint8_t num_temporal_layers =
|
|
std::max<uint8_t>(1, codec.VP8().numberOfTemporalLayers);
|
|
if (codec.numberOfSimulcastStreams > 0) {
|
|
RTC_DCHECK_LT(spatial_id, codec.numberOfSimulcastStreams);
|
|
num_temporal_layers =
|
|
std::max(num_temporal_layers,
|
|
codec.simulcastStream[spatial_id].numberOfTemporalLayers);
|
|
}
|
|
return num_temporal_layers;
|
|
}
|
|
|
|
bool IsConferenceModeScreenshare(const VideoCodec& codec) {
|
|
if (codec.mode != kScreensharing) {
|
|
return false;
|
|
}
|
|
return NumTemporalLayers(codec, 0) == 2;
|
|
}
|
|
} // namespace
|
|
|
|
std::unique_ptr<TemporalLayers> TemporalLayers::CreateTemporalLayers(
|
|
const VideoCodec& codec,
|
|
size_t spatial_id,
|
|
uint8_t initial_tl0_pic_idx) {
|
|
if (IsConferenceModeScreenshare(codec) && spatial_id == 0) {
|
|
// Conference mode temporal layering for screen content in base stream.
|
|
return rtc::MakeUnique<ScreenshareLayers>(2, initial_tl0_pic_idx,
|
|
Clock::GetRealTimeClock());
|
|
}
|
|
|
|
return rtc::MakeUnique<DefaultTemporalLayers>(
|
|
NumTemporalLayers(codec, spatial_id), initial_tl0_pic_idx);
|
|
}
|
|
|
|
std::unique_ptr<TemporalLayersChecker>
|
|
TemporalLayers::CreateTemporalLayersChecker(const VideoCodec& codec,
|
|
size_t spatial_id,
|
|
uint8_t initial_tl0_pic_idx) {
|
|
if (IsConferenceModeScreenshare(codec) && spatial_id == 0) {
|
|
// Conference mode temporal layering for screen content in base stream,
|
|
// use generic checker.
|
|
return rtc::MakeUnique<TemporalLayersChecker>(2, initial_tl0_pic_idx);
|
|
}
|
|
|
|
return rtc::MakeUnique<DefaultTemporalLayersChecker>(
|
|
NumTemporalLayers(codec, spatial_id), initial_tl0_pic_idx);
|
|
}
|
|
|
|
TemporalLayersChecker::TemporalLayersChecker(int num_temporal_layers,
|
|
uint8_t /*initial_tl0_pic_idx*/)
|
|
: num_temporal_layers_(num_temporal_layers),
|
|
sequence_number_(0),
|
|
last_sync_sequence_number_(0),
|
|
last_tl0_sequence_number_(0) {}
|
|
|
|
bool TemporalLayersChecker::CheckAndUpdateBufferState(
|
|
BufferState* state,
|
|
bool* need_sync,
|
|
bool frame_is_keyframe,
|
|
uint8_t temporal_layer,
|
|
webrtc::TemporalLayers::BufferFlags flags,
|
|
uint32_t sequence_number,
|
|
uint32_t* lowest_sequence_referenced) {
|
|
if (flags & TemporalLayers::BufferFlags::kReference) {
|
|
if (state->temporal_layer > 0) {
|
|
*need_sync = false;
|
|
}
|
|
if (!state->is_keyframe && !frame_is_keyframe &&
|
|
state->sequence_number < *lowest_sequence_referenced) {
|
|
*lowest_sequence_referenced = state->sequence_number;
|
|
}
|
|
if (!frame_is_keyframe && !state->is_keyframe &&
|
|
state->temporal_layer > temporal_layer) {
|
|
RTC_LOG(LS_ERROR) << "Frame is referencing higher temporal layer.";
|
|
return false;
|
|
}
|
|
}
|
|
if ((flags & TemporalLayers::BufferFlags::kUpdate)) {
|
|
state->temporal_layer = temporal_layer;
|
|
state->sequence_number = sequence_number;
|
|
state->is_keyframe = frame_is_keyframe;
|
|
}
|
|
if (frame_is_keyframe)
|
|
state->is_keyframe = true;
|
|
return true;
|
|
}
|
|
|
|
bool TemporalLayersChecker::CheckTemporalConfig(
|
|
bool frame_is_keyframe,
|
|
const TemporalLayers::FrameConfig& frame_config) {
|
|
if (frame_config.drop_frame) {
|
|
return true;
|
|
}
|
|
++sequence_number_;
|
|
if (frame_config.packetizer_temporal_idx >= num_temporal_layers_ ||
|
|
(frame_config.packetizer_temporal_idx == kNoTemporalIdx &&
|
|
num_temporal_layers_ > 1)) {
|
|
RTC_LOG(LS_ERROR) << "Incorrect temporal layer set for frame: "
|
|
<< frame_config.packetizer_temporal_idx
|
|
<< " num_temporal_layers: " << num_temporal_layers_;
|
|
return false;
|
|
}
|
|
|
|
uint32_t lowest_sequence_referenced = sequence_number_;
|
|
bool need_sync = frame_config.packetizer_temporal_idx > 0 &&
|
|
frame_config.packetizer_temporal_idx != kNoTemporalIdx;
|
|
|
|
if (!CheckAndUpdateBufferState(
|
|
&last_, &need_sync, frame_is_keyframe,
|
|
frame_config.packetizer_temporal_idx, frame_config.last_buffer_flags,
|
|
sequence_number_, &lowest_sequence_referenced)) {
|
|
RTC_LOG(LS_ERROR) << "Error in the Last buffer";
|
|
return false;
|
|
}
|
|
if (!CheckAndUpdateBufferState(&golden_, &need_sync, frame_is_keyframe,
|
|
frame_config.packetizer_temporal_idx,
|
|
frame_config.golden_buffer_flags,
|
|
sequence_number_,
|
|
&lowest_sequence_referenced)) {
|
|
RTC_LOG(LS_ERROR) << "Error in the Golden buffer";
|
|
return false;
|
|
}
|
|
if (!CheckAndUpdateBufferState(
|
|
&arf_, &need_sync, frame_is_keyframe,
|
|
frame_config.packetizer_temporal_idx, frame_config.arf_buffer_flags,
|
|
sequence_number_, &lowest_sequence_referenced)) {
|
|
RTC_LOG(LS_ERROR) << "Error in the Arf buffer";
|
|
return false;
|
|
}
|
|
|
|
if (lowest_sequence_referenced < last_sync_sequence_number_ &&
|
|
!frame_is_keyframe) {
|
|
RTC_LOG(LS_ERROR) << "Reference past the last sync frame. Referenced "
|
|
<< lowest_sequence_referenced << ", but sync was at "
|
|
<< last_sync_sequence_number_;
|
|
return false;
|
|
}
|
|
|
|
if (frame_config.packetizer_temporal_idx == 0) {
|
|
last_tl0_sequence_number_ = sequence_number_;
|
|
}
|
|
|
|
if (frame_is_keyframe) {
|
|
last_sync_sequence_number_ = sequence_number_;
|
|
}
|
|
|
|
if (need_sync) {
|
|
last_sync_sequence_number_ = last_tl0_sequence_number_;
|
|
}
|
|
|
|
if (need_sync != frame_config.layer_sync) {
|
|
RTC_LOG(LS_ERROR) << "Sync bit is set incorrectly on a frame. Expected: "
|
|
<< need_sync << " Actual: " << frame_config.layer_sync;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
} // namespace webrtc
|