|  | /* | 
|  | *  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 |