/* * 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 #include "modules/video_coding/codecs/interface/common_constants.h" #include "modules/video_coding/codecs/vp8/default_temporal_layers.h" #include "rtc_base/logging.h" namespace webrtc { std::unique_ptr TemporalLayersChecker::CreateTemporalLayersChecker(Vp8TemporalLayersType type, int num_temporal_layers) { switch (type) { case Vp8TemporalLayersType::kFixedPattern: return std::make_unique( num_temporal_layers); case Vp8TemporalLayersType::kBitrateDynamic: // Conference mode temporal layering for screen content in base stream. return std::make_unique(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