diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index 452f0bf445..a6204281e0 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -244,6 +244,7 @@ rtc_static_library("webrtc_vp8") { "codecs/vp8/screenshare_layers.h", "codecs/vp8/simulcast_rate_allocator.cc", "codecs/vp8/simulcast_rate_allocator.h", + "codecs/vp8/temporal_layers.cc", "codecs/vp8/temporal_layers.h", "codecs/vp8/vp8_impl.cc", "codecs/vp8/vp8_impl.h", diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.cc b/modules/video_coding/codecs/vp8/default_temporal_layers.cc index 98306bb6a8..e2e5488bd7 100644 --- a/modules/video_coding/codecs/vp8/default_temporal_layers.cc +++ b/modules/video_coding/codecs/vp8/default_temporal_layers.cc @@ -469,7 +469,8 @@ std::vector> GetTemporalDependencies( DefaultTemporalLayersChecker::DefaultTemporalLayersChecker( int num_temporal_layers, uint8_t initial_tl0_pic_idx) - : num_layers_(std::max(1, num_temporal_layers)), + : TemporalLayersChecker(num_temporal_layers, initial_tl0_pic_idx), + num_layers_(std::max(1, num_temporal_layers)), temporal_ids_(GetTemporalIds(num_layers_)), temporal_dependencies_(GetTemporalDependencies(num_layers_)), pattern_idx_(255) { @@ -482,6 +483,13 @@ DefaultTemporalLayersChecker::DefaultTemporalLayersChecker( bool DefaultTemporalLayersChecker::CheckTemporalConfig( bool frame_is_keyframe, const TemporalLayers::FrameConfig& frame_config) { + if (!TemporalLayersChecker::CheckTemporalConfig(frame_is_keyframe, + frame_config)) { + return false; + } + if (frame_config.drop_frame) { + return true; + } ++pattern_idx_; if (pattern_idx_ == temporal_ids_.size()) { // All non key-frame buffers should be updated each pattern cycle. diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.cc b/modules/video_coding/codecs/vp8/screenshare_layers.cc index dac16ebe70..9ea9ac9f7f 100644 --- a/modules/video_coding/codecs/vp8/screenshare_layers.cc +++ b/modules/video_coding/codecs/vp8/screenshare_layers.cc @@ -16,6 +16,7 @@ #include "modules/video_coding/include/video_codec_interface.h" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" #include "system_wrappers/include/clock.h" #include "system_wrappers/include/metrics.h" #include "vpx/vp8cx.h" @@ -62,8 +63,8 @@ ScreenshareTemporalLayersFactory::CreateChecker( uint8_t initial_tl0_pic_idx) const { webrtc::TemporalLayersChecker* tlc; if (simulcast_id == 0) { - tlc = new webrtc::ScreenshareTemporalLayersChecker(temporal_layers, - initial_tl0_pic_idx); + tlc = + new webrtc::TemporalLayersChecker(temporal_layers, initial_tl0_pic_idx); } else { TemporalLayersFactory rt_tl_factory; return rt_tl_factory.CreateChecker(simulcast_id, temporal_layers, @@ -474,17 +475,4 @@ void ScreenshareLayers::UpdateHistograms() { } } } - -ScreenshareTemporalLayersChecker::ScreenshareTemporalLayersChecker( - int /*num_temporal_layers*/, - uint8_t /*initial_tl0_pic_idx*/) {} - -// TODO(ilnik): Implement layers dependency checks here. Keep track of -// last/golden/arf buffers and sync bits. -bool ScreenshareTemporalLayersChecker::CheckTemporalConfig( - bool /*frame_is_keyframe*/, - const TemporalLayers::FrameConfig& /*frame_config*/) { - return true; -} - } // namespace webrtc diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.h b/modules/video_coding/codecs/vp8/screenshare_layers.h index 9d7dbd2e04..81db90abe6 100644 --- a/modules/video_coding/codecs/vp8/screenshare_layers.h +++ b/modules/video_coding/codecs/vp8/screenshare_layers.h @@ -122,15 +122,6 @@ class ScreenshareLayers : public TemporalLayers { int64_t tl1_target_bitrate_sum_ = 0; } stats_; }; - -class ScreenshareTemporalLayersChecker : public TemporalLayersChecker { - public: - ScreenshareTemporalLayersChecker(int number_of_temporal_layers, - uint8_t initial_tl0_pic_idx); - bool CheckTemporalConfig( - bool frame_is_keyframe, - const TemporalLayers::FrameConfig& frame_config) override; -}; } // namespace webrtc #endif // MODULES_VIDEO_CODING_CODECS_VP8_SCREENSHARE_LAYERS_H_ diff --git a/modules/video_coding/codecs/vp8/temporal_layers.cc b/modules/video_coding/codecs/vp8/temporal_layers.cc new file mode 100644 index 0000000000..cf6c5fc2ae --- /dev/null +++ b/modules/video_coding/codecs/vp8/temporal_layers.cc @@ -0,0 +1,135 @@ +/* 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 +#include +#include +#include + +#include "modules/include/module_common_types.h" +#include "modules/video_coding/codecs/vp8/include/vp8_common_types.h" +#include "modules/video_coding/include/video_codec_interface.h" +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { + +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) { + 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)) { + 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)) { + 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)) { + 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)) { + LOG(LS_ERROR) << "Error in the Arf buffer"; + return false; + } + + if (lowest_sequence_referenced < last_sync_sequence_number_ && + !frame_is_keyframe) { + 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) { + 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 diff --git a/modules/video_coding/codecs/vp8/temporal_layers.h b/modules/video_coding/codecs/vp8/temporal_layers.h index 6a164f1319..dad718cd0f 100644 --- a/modules/video_coding/codecs/vp8/temporal_layers.h +++ b/modules/video_coding/codecs/vp8/temporal_layers.h @@ -171,12 +171,34 @@ class TemporalLayersListener { // each UpdateLayersConfig() of a corresponding TemporalLayers class. class TemporalLayersChecker { public: - TemporalLayersChecker() {} + TemporalLayersChecker(int num_temporal_layers, uint8_t initial_tl0_pic_idx); virtual ~TemporalLayersChecker() {} virtual bool CheckTemporalConfig( bool frame_is_keyframe, - const TemporalLayers::FrameConfig& frame_config) = 0; + const TemporalLayers::FrameConfig& frame_config); + + private: + struct BufferState { + BufferState() : is_keyframe(true), temporal_layer(0), sequence_number(0) {} + bool is_keyframe; + uint8_t temporal_layer; + uint32_t sequence_number; + }; + bool 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); + BufferState last_; + BufferState arf_; + BufferState golden_; + int num_temporal_layers_; + uint32_t sequence_number_; + uint32_t last_sync_sequence_number_; + uint32_t last_tl0_sequence_number_; }; } // namespace webrtc