| /* 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 "absl/memory/memory.h" |
| #include "modules/include/module_common_types.h" |
| #include "modules/video_coding/codecs/vp8/default_temporal_layers.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 "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 != VideoCodecMode::kScreensharing) { |
| return false; |
| } |
| return NumTemporalLayers(codec, 0) == 2; |
| } |
| } // namespace |
| |
| std::unique_ptr<TemporalLayers> TemporalLayers::CreateTemporalLayers( |
| const VideoCodec& codec, |
| size_t spatial_id) { |
| if (IsConferenceModeScreenshare(codec) && spatial_id == 0) { |
| // Conference mode temporal layering for screen content in base stream. |
| return absl::make_unique<ScreenshareLayers>(2, Clock::GetRealTimeClock()); |
| } |
| |
| return absl::make_unique<DefaultTemporalLayers>( |
| NumTemporalLayers(codec, spatial_id)); |
| } |
| |
| std::unique_ptr<TemporalLayersChecker> |
| TemporalLayers::CreateTemporalLayersChecker(const VideoCodec& codec, |
| size_t spatial_id) { |
| if (IsConferenceModeScreenshare(codec) && spatial_id == 0) { |
| // Conference mode temporal layering for screen content in base stream, |
| // use generic checker. |
| return absl::make_unique<TemporalLayersChecker>(2); |
| } |
| |
| return absl::make_unique<DefaultTemporalLayersChecker>( |
| NumTemporalLayers(codec, spatial_id)); |
| } |
| |
| TemporalLayersChecker::TemporalLayersChecker(int num_temporal_layers) |
| : 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 |