| /* | |
| * Copyright (c) 2018 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/include/temporal_layers_checker.h" | |
| #include <cstdint> | |
| #include <memory> | |
| #include "api/video_codecs/vp8_frame_config.h" | |
| #include "api/video_codecs/vp8_temporal_layers.h" | |
| #include "modules/video_coding/codecs/interface/common_constants.h" | |
| #include "modules/video_coding/codecs/vp8/default_temporal_layers.h" | |
| #include "rtc_base/checks.h" | |
| #include "rtc_base/logging.h" | |
| namespace webrtc { | |
| std::unique_ptr<TemporalLayersChecker> | |
| TemporalLayersChecker::CreateTemporalLayersChecker(Vp8TemporalLayersType type, | |
| int num_temporal_layers) { | |
| switch (type) { | |
| case Vp8TemporalLayersType::kFixedPattern: | |
| return std::make_unique<DefaultTemporalLayersChecker>( | |
| num_temporal_layers); | |
| case Vp8TemporalLayersType::kBitrateDynamic: | |
| // Conference mode temporal layering for screen content in base stream. | |
| return std::make_unique<TemporalLayersChecker>(num_temporal_layers); | |
| } | |
| RTC_CHECK_NOTREACHED(); | |
| } | |
| 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, | |
| Vp8FrameConfig::BufferFlags flags, | |
| uint32_t sequence_number, | |
| uint32_t* lowest_sequence_referenced) { | |
| if (flags & Vp8FrameConfig::BufferFlags::kReference) { | |
| if (state->temporal_layer > 0 && !state->is_keyframe) { | |
| *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 & Vp8FrameConfig::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 Vp8FrameConfig& frame_config) { | |
| if (frame_config.drop_frame || | |
| frame_config.packetizer_temporal_idx == kNoTemporalIdx) { | |
| 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_; | |
| } | |
| // Ignore sync flag on key-frames as it really doesn't matter. | |
| if (need_sync != frame_config.layer_sync && !frame_is_keyframe) { | |
| 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 |