From 8abd56cfdf898923ba9ac3a17ec07eabff2324ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Spr=C3=A5ng?= Date: Mon, 1 Oct 2018 18:47:03 +0200 Subject: [PATCH] Split TemporalLayers and TemporalLayers checker, clean up header. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL is a step towards making the TemporalLayers landable in api/ : * It splits TemporalLayers from TemporalLayersChecker * It initially renames temporal_layer.h to vp8_temporal_layers.h and moved it into the include/ folder * It removes the dependency on VideoCodec, which was essentially only used to determine if screenshare_layers or default_temporal_layers should be used, and the number of temporal temporal layers to use. Subsequent CLs will make further cleanup before attempting a move to api Bug: webrtc:9012 Change-Id: I87ea7aac66d39284eaebd86aa9d015aba2eaaaea Reviewed-on: https://webrtc-review.googlesource.com/94156 Commit-Queue: Erik Språng Reviewed-by: Ilya Nikolaevskiy Reviewed-by: Stefan Holmer Reviewed-by: Rasmus Brandt Cr-Commit-Position: refs/heads/master@{#24920} --- ...oder_software_fallback_wrapper_unittest.cc | 2 +- .../vp8_encoder_simulcast_proxy_unittest.cc | 2 +- modules/video_coding/BUILD.gn | 6 +- .../codecs/vp8/default_temporal_layers.h | 3 +- .../vp8/include/temporal_layers_checker.h | 63 +++++ .../codecs/vp8/include/vp8_temporal_layers.h | 188 +++++++++++++++ .../codecs/vp8/libvpx_vp8_encoder.cc | 66 +++--- .../codecs/vp8/libvpx_vp8_encoder.h | 7 +- .../codecs/vp8/screenshare_layers.h | 2 +- .../video_coding/codecs/vp8/temporal_layers.h | 220 +----------------- ...l_layers.cc => temporal_layers_checker.cc} | 84 ++----- .../codecs/vp8/test/vp8_impl_unittest.cc | 2 +- .../codecs/vp8/vp8_temporal_layers.cc | 42 ++++ .../simulcast_rate_allocator_unittest.cc | 2 +- .../video_coding/utility/simulcast_utility.cc | 27 +++ .../video_coding/utility/simulcast_utility.h | 3 + .../video_codec_initializer_unittest.cc | 7 +- modules/video_coding/video_sender_unittest.cc | 2 +- test/fake_encoder.cc | 2 +- test/fake_vp8_encoder.cc | 30 +-- test/fake_vp8_encoder.h | 6 +- video/video_stream_encoder_unittest.cc | 6 +- 22 files changed, 420 insertions(+), 352 deletions(-) create mode 100644 modules/video_coding/codecs/vp8/include/temporal_layers_checker.h create mode 100644 modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h rename modules/video_coding/codecs/vp8/{temporal_layers.cc => temporal_layers_checker.cc} (61%) create mode 100644 modules/video_coding/codecs/vp8/vp8_temporal_layers.cc diff --git a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc index a1a43b4202..98ebed2305 100644 --- a/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc +++ b/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc @@ -15,7 +15,7 @@ #include "api/video/i420_buffer.h" #include "api/video/video_bitrate_allocation.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/utility/simulcast_rate_allocator.h" diff --git a/media/engine/vp8_encoder_simulcast_proxy_unittest.cc b/media/engine/vp8_encoder_simulcast_proxy_unittest.cc index 47e57aa85e..d1dc9a31df 100644 --- a/media/engine/vp8_encoder_simulcast_proxy_unittest.cc +++ b/media/engine/vp8_encoder_simulcast_proxy_unittest.cc @@ -15,7 +15,7 @@ #include "api/test/mock_video_encoder_factory.h" #include "media/engine/webrtcvideoencoderfactory.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/video_codec_interface.h" #include "test/gmock.h" #include "test/gtest.h" diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn index f000f41f8a..c992da5302 100644 --- a/modules/video_coding/BUILD.gn +++ b/modules/video_coding/BUILD.gn @@ -393,15 +393,18 @@ rtc_static_library("webrtc_vp8") { sources = [ "codecs/vp8/default_temporal_layers.cc", "codecs/vp8/default_temporal_layers.h", + "codecs/vp8/include/temporal_layers_checker.h", "codecs/vp8/include/vp8.h", + "codecs/vp8/include/vp8_temporal_layers.h", "codecs/vp8/libvpx_vp8_decoder.cc", "codecs/vp8/libvpx_vp8_decoder.h", "codecs/vp8/libvpx_vp8_encoder.cc", "codecs/vp8/libvpx_vp8_encoder.h", "codecs/vp8/screenshare_layers.cc", "codecs/vp8/screenshare_layers.h", - "codecs/vp8/temporal_layers.cc", "codecs/vp8/temporal_layers.h", + "codecs/vp8/temporal_layers_checker.cc", + "codecs/vp8/vp8_temporal_layers.cc", ] if (!build_with_chromium && is_clang) { @@ -410,6 +413,7 @@ rtc_static_library("webrtc_vp8") { } deps = [ + ":codec_globals_headers", ":video_codec_interface", ":video_coding_utility", "..:module_api", diff --git a/modules/video_coding/codecs/vp8/default_temporal_layers.h b/modules/video_coding/codecs/vp8/default_temporal_layers.h index 691447964c..ab54621e95 100644 --- a/modules/video_coding/codecs/vp8/default_temporal_layers.h +++ b/modules/video_coding/codecs/vp8/default_temporal_layers.h @@ -17,7 +17,8 @@ #include #include -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "absl/types/optional.h" diff --git a/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h b/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h new file mode 100644 index 0000000000..9878ac9f3a --- /dev/null +++ b/modules/video_coding/codecs/vp8/include/temporal_layers_checker.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +#ifndef MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_TEMPORAL_LAYERS_CHECKER_H_ +#define MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_TEMPORAL_LAYERS_CHECKER_H_ + +#include + +#include + +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" + +namespace webrtc { + +// Interface for a class that verifies correctness of temporal layer +// configurations (dependencies, sync flag, etc). +// Intended to be used in tests as well as with real apps in debug mode. +class TemporalLayersChecker { + public: + explicit TemporalLayersChecker(int num_temporal_layers); + virtual ~TemporalLayersChecker() {} + + virtual bool CheckTemporalConfig( + bool frame_is_keyframe, + const TemporalLayers::FrameConfig& frame_config); + + static std::unique_ptr CreateTemporalLayersChecker( + TemporalLayersType type, + int num_temporal_layers); + + 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 + +#endif // MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_TEMPORAL_LAYERS_CHECKER_H_ diff --git a/modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h b/modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h new file mode 100644 index 0000000000..1b668ebf34 --- /dev/null +++ b/modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h @@ -0,0 +1,188 @@ +/* + * 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. + */ + +#ifndef MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_ +#define MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_ + +#include +#include + +namespace webrtc { + +// Some notes on the prerequisites of the TemporalLayers interface. +// * Implementations of TemporalLayers may not contain internal synchronization +// so caller must make sure doing so thread safe. +// * The encoder is assumed to encode all frames in order, and callbacks to +// PopulateCodecSpecific() / FrameEncoded() must happen in the same order. +// +// This means that in the case of pipelining encoders, it is OK to have a chain +// of calls such as this: +// - UpdateLayerConfig(timestampA) +// - UpdateLayerConfig(timestampB) +// - PopulateCodecSpecific(timestampA, ...) +// - UpdateLayerConfig(timestampC) +// - FrameEncoded(timestampA, 1234, ...) +// - FrameEncoded(timestampB, 0, ...) +// - PopulateCodecSpecific(timestampC, ...) +// - FrameEncoded(timestampC, 1234, ...) +// Note that UpdateLayerConfig() for a new frame can happen before +// FrameEncoded() for a previous one, but calls themselves must be both +// synchronized (e.g. run on a task queue) and in order (per type). + +enum class TemporalLayersType { kFixedPattern, kBitrateDynamic }; + +struct CodecSpecificInfoVP8; +enum class Vp8BufferReference : uint8_t { + kNone = 0, + kLast = 1, + kGolden = 2, + kAltref = 4 +}; + +struct Vp8EncoderConfig { + static constexpr size_t kMaxPeriodicity = 16; + static constexpr size_t kMaxLayers = 5; + + // Number of active temporal layers. Set to 0 if not used. + uint32_t ts_number_layers; + // Arrays of length |ts_number_layers|, indicating (cumulative) target bitrate + // and rate decimator (e.g. 4 if every 4th frame is in the given layer) for + // each active temporal layer, starting with temporal id 0. + uint32_t ts_target_bitrate[kMaxLayers]; + uint32_t ts_rate_decimator[kMaxLayers]; + + // The periodicity of the temporal pattern. Set to 0 if not used. + uint32_t ts_periodicity; + // Array of length |ts_periodicity| indicating the sequence of temporal id's + // to assign to incoming frames. + uint32_t ts_layer_id[kMaxPeriodicity]; + + // Target bitrate, in bps. + uint32_t rc_target_bitrate; + + // Clamp QP to min/max. Use 0 to disable clamping. + uint32_t rc_min_quantizer; + uint32_t rc_max_quantizer; +}; + +// This interface defines a way of getting the encoder settings needed to +// realize a temporal layer structure of predefined size. +class TemporalLayers { + public: + enum BufferFlags : int { + kNone = 0, + kReference = 1, + kUpdate = 2, + kReferenceAndUpdate = kReference | kUpdate, + }; + enum FreezeEntropy { kFreezeEntropy }; + + struct FrameConfig { + FrameConfig(); + + FrameConfig(BufferFlags last, BufferFlags golden, BufferFlags arf); + FrameConfig(BufferFlags last, + BufferFlags golden, + BufferFlags arf, + FreezeEntropy); + + bool drop_frame; + BufferFlags last_buffer_flags; + BufferFlags golden_buffer_flags; + BufferFlags arf_buffer_flags; + + // The encoder layer ID is used to utilize the correct bitrate allocator + // inside the encoder. It does not control references nor determine which + // "actual" temporal layer this is. The packetizer temporal index determines + // which layer the encoded frame should be packetized into. + // Normally these are the same, but current temporal-layer strategies for + // screenshare use one bitrate allocator for all layers, but attempt to + // packetize / utilize references to split a stream into multiple layers, + // with different quantizer settings, to hit target bitrate. + // TODO(pbos): Screenshare layers are being reconsidered at the time of + // writing, we might be able to remove this distinction, and have a temporal + // layer imply both (the normal case). + int encoder_layer_id; + int packetizer_temporal_idx; + + bool layer_sync; + + bool freeze_entropy; + + // Indicates in which order the encoder should search the reference buffers + // when doing motion prediction. Set to kNone to use unspecified order. Any + // buffer indicated here must not have the corresponding no_ref bit set. + // If all three buffers can be reference, the one not listed here should be + // searched last. + Vp8BufferReference first_reference; + Vp8BufferReference second_reference; + + bool operator==(const FrameConfig& o) const; + bool operator!=(const FrameConfig& o) const { return !(*this == o); } + + private: + FrameConfig(BufferFlags last, + BufferFlags golden, + BufferFlags arf, + bool freeze_entropy); + }; + + // Factory for TemporalLayer strategy. Default behavior is a fixed pattern + // of temporal layers. See default_temporal_layers.cc + static std::unique_ptr CreateTemporalLayers( + TemporalLayersType type, + int num_temporal_layers); + + virtual ~TemporalLayers() = default; + + virtual bool SupportsEncoderFrameDropping() const = 0; + + // New target bitrate, per temporal layer. + virtual void OnRatesUpdated(const std::vector& bitrates_bps, + int framerate_fps) = 0; + + // Update the encoder configuration with target bitrates or other parameters. + // Returns true iff the configuration was actually modified. + virtual bool UpdateConfiguration(Vp8EncoderConfig* cfg) = 0; + + // Returns the recommended VP8 encode flags needed, and moves the temporal + // pattern to the next frame. + // The timestamp may be used as both a time and a unique identifier, and so + // the caller must make sure no two frames use the same timestamp. + // The timestamp uses a 90kHz RTP clock. + // After calling this method, the actual encoder should be called with the + // provided frame configuration, after which: + // * On success, call PopulateCodecSpecific() and then FrameEncoded(); + // * On failure/ frame drop: Call FrameEncoded() with size = 0. + virtual FrameConfig UpdateLayerConfig(uint32_t rtp_timestamp) = 0; + + // Called after successful encoding of a frame. The rtp timestamp must match + // the one using in UpdateLayerConfig(). Some fields in |vp8_info| may have + // already been populated by the encoder, check before overwriting. + // |tl_config| is the frame config returned by UpdateLayerConfig() for this + // rtp_timestamp; + // If |is_keyframe| is true, the flags in |tl_config| will be ignored. + virtual void PopulateCodecSpecific( + bool is_keyframe, + const TemporalLayers::FrameConfig& tl_config, + CodecSpecificInfoVP8* vp8_info, + uint32_t rtp_timestamp) = 0; + + // Called after an encode event. If the frame was dropped, |size_bytes| must + // be set to 0. The rtp timestamp must match the one using in + // UpdateLayerConfig() + virtual void FrameEncoded(uint32_t rtp_timestamp, + size_t size_bytes, + int qp) = 0; +}; + +} // namespace webrtc + +#endif // MODULES_VIDEO_CODING_CODECS_VP8_INCLUDE_VP8_TEMPORAL_LAYERS_H_ diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index 72e5f872d8..2b7250823c 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -72,24 +72,24 @@ bool GetGfBoostPercentageFromFieldTrialGroup(int* boost_percentage) { return true; } -static_assert( - VP8_TS_MAX_PERIODICITY == VPX_TS_MAX_PERIODICITY, - "VP8_TS_MAX_PERIODICITY must be kept in sync with the constant in libvpx."); -static_assert( - VP8_TS_MAX_LAYERS == VPX_TS_MAX_LAYERS, - "VP8_TS_MAX_LAYERS must be kept in sync with the constant in libvpx."); +static_assert(Vp8EncoderConfig::kMaxPeriodicity == VPX_TS_MAX_PERIODICITY, + "Vp8EncoderConfig::kMaxPeriodicity must be kept in sync with the " + "constant in libvpx."); +static_assert(Vp8EncoderConfig::kMaxLayers == VPX_TS_MAX_LAYERS, + "Vp8EncoderConfig::kMaxLayers must be kept in sync with the " + "constant in libvpx."); static Vp8EncoderConfig GetEncoderConfig(vpx_codec_enc_cfg* vpx_config) { Vp8EncoderConfig config; config.ts_number_layers = vpx_config->ts_number_layers; memcpy(config.ts_target_bitrate, vpx_config->ts_target_bitrate, - sizeof(unsigned int) * VP8_TS_MAX_LAYERS); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxLayers); memcpy(config.ts_rate_decimator, vpx_config->ts_rate_decimator, - sizeof(unsigned int) * VP8_TS_MAX_LAYERS); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxLayers); config.ts_periodicity = vpx_config->ts_periodicity; memcpy(config.ts_layer_id, vpx_config->ts_layer_id, - sizeof(unsigned int) * VP8_TS_MAX_PERIODICITY); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxPeriodicity); config.rc_target_bitrate = vpx_config->rc_target_bitrate; config.rc_min_quantizer = vpx_config->rc_min_quantizer; config.rc_max_quantizer = vpx_config->rc_max_quantizer; @@ -101,12 +101,12 @@ static void FillInEncoderConfig(vpx_codec_enc_cfg* vpx_config, const Vp8EncoderConfig& config) { vpx_config->ts_number_layers = config.ts_number_layers; memcpy(vpx_config->ts_target_bitrate, config.ts_target_bitrate, - sizeof(unsigned int) * VP8_TS_MAX_LAYERS); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxLayers); memcpy(vpx_config->ts_rate_decimator, config.ts_rate_decimator, - sizeof(unsigned int) * VP8_TS_MAX_LAYERS); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxLayers); vpx_config->ts_periodicity = config.ts_periodicity; memcpy(vpx_config->ts_layer_id, config.ts_layer_id, - sizeof(unsigned int) * VP8_TS_MAX_PERIODICITY); + sizeof(unsigned int) * Vp8EncoderConfig::kMaxPeriodicity); vpx_config->rc_target_bitrate = config.rc_target_bitrate; vpx_config->rc_min_quantizer = config.rc_min_quantizer; vpx_config->rc_max_quantizer = config.rc_max_quantizer; @@ -120,6 +120,7 @@ bool UpdateVpxConfiguration(TemporalLayers* temporal_layers, FillInEncoderConfig(cfg, config); return res; } + } // namespace std::unique_ptr VP8Encoder::Create() { @@ -284,15 +285,25 @@ void LibvpxVp8Encoder::SetStreamState(bool send_stream, int stream_idx) { send_stream_[stream_idx] = send_stream; } -void LibvpxVp8Encoder::SetupTemporalLayers(int num_streams, - int num_temporal_layers, - const VideoCodec& codec) { +void LibvpxVp8Encoder::SetupTemporalLayers(const VideoCodec& codec) { RTC_DCHECK(temporal_layers_.empty()); + int num_streams = SimulcastUtility::NumberOfSimulcastStreams(codec); for (int i = 0; i < num_streams; ++i) { + TemporalLayersType type; + int num_temporal_layers = + SimulcastUtility::NumberOfTemporalLayers(codec, i); + if (SimulcastUtility::IsConferenceModeScreenshare(codec) && i == 0) { + type = TemporalLayersType::kBitrateDynamic; + // Legacy screenshare layers supports max 2 layers. + num_temporal_layers = std::max(2, num_temporal_layers); + } else { + type = TemporalLayersType::kFixedPattern; + } temporal_layers_.emplace_back( - TemporalLayers::CreateTemporalLayers(codec, i)); + TemporalLayers::CreateTemporalLayers(type, num_temporal_layers)); temporal_layers_checkers_.emplace_back( - TemporalLayers::CreateTemporalLayersChecker(codec, i)); + TemporalLayersChecker::CreateTemporalLayersChecker( + type, num_temporal_layers)); } } @@ -324,21 +335,14 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, } int number_of_streams = SimulcastUtility::NumberOfSimulcastStreams(*inst); - bool doing_simulcast = (number_of_streams > 1); - - if (doing_simulcast && (!SimulcastUtility::ValidSimulcastResolutions( - *inst, number_of_streams) || - !SimulcastUtility::ValidSimulcastTemporalLayers( - *inst, number_of_streams))) { + if (number_of_streams > 1 && + (!SimulcastUtility::ValidSimulcastResolutions(*inst, number_of_streams) || + !SimulcastUtility::ValidSimulcastTemporalLayers(*inst, + number_of_streams))) { return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED; } - int num_temporal_layers = - doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers - : inst->VP8().numberOfTemporalLayers; - RTC_DCHECK_GT(num_temporal_layers, 0); - - SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst); + SetupTemporalLayers(*inst); number_of_cores_ = number_of_cores; timestamp_ = 0; @@ -396,7 +400,9 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst, // Set the error resilience mode for temporal layers (but not simulcast). configurations_[0].g_error_resilient = - (num_temporal_layers > 1) ? VPX_ERROR_RESILIENT_DEFAULT : 0; + (SimulcastUtility::NumberOfTemporalLayers(*inst, 0) > 1) + ? VPX_ERROR_RESILIENT_DEFAULT + : 0; // rate control settings configurations_[0].rc_dropframe_thresh = FrameDropThreshold(0); diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h index b1889fcd75..8ee359e5b4 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h @@ -18,8 +18,9 @@ #include "api/video_codecs/video_encoder.h" #include "common_types.h" // NOLINT(build/include) #include "common_video/include/video_frame.h" +#include "modules/video_coding/codecs/vp8/include/temporal_layers_checker.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/video_codec_interface.h" #include "vpx/vp8cx.h" @@ -57,9 +58,7 @@ class LibvpxVp8Encoder : public VP8Encoder { const TemporalLayers::FrameConfig& references); private: - void SetupTemporalLayers(int num_streams, - int num_temporal_layers, - const VideoCodec& codec); + void SetupTemporalLayers(const VideoCodec& codec); // Set the cpu_speed setting for encoder based on resolution and/or platform. int SetCpuSpeed(int width, int height); diff --git a/modules/video_coding/codecs/vp8/screenshare_layers.h b/modules/video_coding/codecs/vp8/screenshare_layers.h index fcc3aca650..cd12ac464e 100644 --- a/modules/video_coding/codecs/vp8/screenshare_layers.h +++ b/modules/video_coding/codecs/vp8/screenshare_layers.h @@ -11,7 +11,7 @@ #include -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/utility/frame_dropper.h" #include "rtc_base/rate_statistics.h" #include "rtc_base/timeutils.h" diff --git a/modules/video_coding/codecs/vp8/temporal_layers.h b/modules/video_coding/codecs/vp8/temporal_layers.h index 91b5531128..788d69a27b 100644 --- a/modules/video_coding/codecs/vp8/temporal_layers.h +++ b/modules/video_coding/codecs/vp8/temporal_layers.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +/* + * 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 @@ -6,222 +7,11 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ -/* - * This file defines the interface for doing temporal layers with VP8. - */ + #ifndef MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_ #define MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_ -#include -#include +// TODO(webrtc:9012) Remove this file when downstream projects have updated. +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" -#include "api/video_codecs/video_codec.h" - -#define VP8_TS_MAX_PERIODICITY 16 -#define VP8_TS_MAX_LAYERS 5 - -namespace webrtc { - -// Some notes on the prerequisites of the TemporalLayers interface. -// * Implementations of TemporalLayers may not contain internal synchronization -// so caller must make sure doing so thread safe. -// * The encoder is assumed to encode all frames in order, and callbacks to -// PopulateCodecSpecific() / FrameEncoded() must happen in the same order. -// -// This means that in the case of pipelining encoders, it is OK to have a chain -// of calls such as this: -// - UpdateLayerConfig(timestampA) -// - UpdateLayerConfig(timestampB) -// - PopulateCodecSpecific(timestampA, ...) -// - UpdateLayerConfig(timestampC) -// - FrameEncoded(timestampA, 1234, ...) -// - FrameEncoded(timestampB, 0, ...) -// - PopulateCodecSpecific(timestampC, ...) -// - FrameEncoded(timestampC, 1234, ...) -// Note that UpdateLayerConfig() for a new frame can happen before -// FrameEncoded() for a previous one, but calls themselves must be both -// synchronized (e.g. run on a task queue) and in order (per type). - -struct CodecSpecificInfoVP8; -enum class Vp8BufferReference : uint8_t { - kNone = 0, - kLast = 1, - kGolden = 2, - kAltref = 4 -}; - -struct Vp8EncoderConfig { - // Number of active temporal layers. Set to 0 if not used. - unsigned int ts_number_layers; - // Arrays of length |ts_number_layers|, indicating (cumulative) target bitrate - // and rate decimator (e.g. 4 if every 4th frame is in the given layer) for - // each active temporal layer, starting with temporal id 0. - unsigned int ts_target_bitrate[VP8_TS_MAX_LAYERS]; - unsigned int ts_rate_decimator[VP8_TS_MAX_LAYERS]; - - // The periodicity of the temporal pattern. Set to 0 if not used. - unsigned int ts_periodicity; - // Array of length |ts_periodicity| indicating the sequence of temporal id's - // to assign to incoming frames. - unsigned int ts_layer_id[VP8_TS_MAX_PERIODICITY]; - - // Target bitrate, in bps. - unsigned int rc_target_bitrate; - - // Clamp QP to min/max. Use 0 to disable clamping. - unsigned int rc_min_quantizer; - unsigned int rc_max_quantizer; -}; - -// This interface defines a way of getting the encoder settings needed to -// realize a temporal layer structure of predefined size. -class TemporalLayersChecker; -class TemporalLayers { - public: - enum BufferFlags : int { - kNone = 0, - kReference = 1, - kUpdate = 2, - kReferenceAndUpdate = kReference | kUpdate, - }; - enum FreezeEntropy { kFreezeEntropy }; - - struct FrameConfig { - FrameConfig(); - - FrameConfig(BufferFlags last, BufferFlags golden, BufferFlags arf); - FrameConfig(BufferFlags last, - BufferFlags golden, - BufferFlags arf, - FreezeEntropy); - - bool drop_frame; - BufferFlags last_buffer_flags; - BufferFlags golden_buffer_flags; - BufferFlags arf_buffer_flags; - - // The encoder layer ID is used to utilize the correct bitrate allocator - // inside the encoder. It does not control references nor determine which - // "actual" temporal layer this is. The packetizer temporal index determines - // which layer the encoded frame should be packetized into. - // Normally these are the same, but current temporal-layer strategies for - // screenshare use one bitrate allocator for all layers, but attempt to - // packetize / utilize references to split a stream into multiple layers, - // with different quantizer settings, to hit target bitrate. - // TODO(pbos): Screenshare layers are being reconsidered at the time of - // writing, we might be able to remove this distinction, and have a temporal - // layer imply both (the normal case). - int encoder_layer_id; - int packetizer_temporal_idx; - - bool layer_sync; - - bool freeze_entropy; - - // Indicates in which order the encoder should search the reference buffers - // when doing motion prediction. Set to kNone to use unspecified order. Any - // buffer indicated here must not have the corresponding no_ref bit set. - // If all three buffers can be reference, the one not listed here should be - // searched last. - Vp8BufferReference first_reference; - Vp8BufferReference second_reference; - - bool operator==(const FrameConfig& o) const; - bool operator!=(const FrameConfig& o) const { return !(*this == o); } - - private: - FrameConfig(BufferFlags last, - BufferFlags golden, - BufferFlags arf, - bool freeze_entropy); - }; - - // Factory for TemporalLayer strategy. Default behavior is a fixed pattern - // of temporal layers. See default_temporal_layers.cc - static std::unique_ptr CreateTemporalLayers( - const VideoCodec& codec, - size_t spatial_id); - static std::unique_ptr CreateTemporalLayersChecker( - const VideoCodec& codec, - size_t spatial_id); - - virtual ~TemporalLayers() = default; - - virtual bool SupportsEncoderFrameDropping() const = 0; - - // New target bitrate, per temporal layer. - virtual void OnRatesUpdated(const std::vector& bitrates_bps, - int framerate_fps) = 0; - - // Update the encoder configuration with target bitrates or other parameters. - // Returns true iff the configuration was actually modified. - virtual bool UpdateConfiguration(Vp8EncoderConfig* cfg) = 0; - - // Returns the recommended VP8 encode flags needed, and moves the temporal - // pattern to the next frame. - // The timestamp may be used as both a time and a unique identifier, and so - // the caller must make sure no two frames use the same timestamp. - // The timestamp uses a 90kHz RTP clock. - // After calling this method, the actual encoder should be called with the - // provided frame configuration, after which: - // * On success, call PopulateCodecSpecific() and then FrameEncoded(); - // * On failure/ frame drop: Call FrameEncoded() with size = 0. - virtual FrameConfig UpdateLayerConfig(uint32_t rtp_timestamp) = 0; - - // Called after successful encoding of a frame. The rtp timestamp must match - // the one using in UpdateLayerConfig(). Some fields in |vp8_info| may have - // already been populated by the encoder, check before overwriting. - // |tl_config| is the frame config returned by UpdateLayerConfig() for this - // rtp_timestamp; - // If |is_keyframe| is true, the flags in |tl_config| will be ignored. - virtual void PopulateCodecSpecific( - bool is_keyframe, - const TemporalLayers::FrameConfig& tl_config, - CodecSpecificInfoVP8* vp8_info, - uint32_t rtp_timestamp) = 0; - - // Called after an encode event. If the frame was dropped, |size_bytes| must - // be set to 0. The rtp timestamp must match the one using in - // UpdateLayerConfig() - virtual void FrameEncoded(uint32_t rtp_timestamp, - size_t size_bytes, - int qp) = 0; -}; - -// Used only inside RTC_DCHECK(). It checks correctness of temporal layers -// dependencies and sync bits. The only method of this class is called after -// each UpdateLayersConfig() of a corresponding TemporalLayers class. -class TemporalLayersChecker { - public: - explicit TemporalLayersChecker(int num_temporal_layers); - virtual ~TemporalLayersChecker() {} - - virtual bool CheckTemporalConfig( - bool frame_is_keyframe, - 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 #endif // MODULES_VIDEO_CODING_CODECS_VP8_TEMPORAL_LAYERS_H_ diff --git a/modules/video_coding/codecs/vp8/temporal_layers.cc b/modules/video_coding/codecs/vp8/temporal_layers_checker.cc similarity index 61% rename from modules/video_coding/codecs/vp8/temporal_layers.cc rename to modules/video_coding/codecs/vp8/temporal_layers_checker.cc index 236950ad3d..b77e8bc219 100644 --- a/modules/video_coding/codecs/vp8/temporal_layers.cc +++ b/modules/video_coding/codecs/vp8/temporal_layers_checker.cc @@ -1,4 +1,5 @@ -/* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. +/* + * 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 @@ -7,83 +8,25 @@ * 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/video_coding/codecs/vp8/include/temporal_layers_checker.h" #include "absl/memory/memory.h" -#include "modules/include/module_common_types.h" +#include "modules/video_coding/codecs/interface/common_constants.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(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 || - NumTemporalLayers(codec, 0) != 2) { - return false; - } - // Fixed default bitrates for legacy screenshare layers mode. - return (codec.numberOfSimulcastStreams == 0 && codec.maxBitrate == 1000) || - (codec.numberOfSimulcastStreams >= 1 && - codec.simulcastStream[0].maxBitrate == 1000 && - codec.simulcastStream[0].targetBitrate == 200); -} -} // namespace - -bool TemporalLayers::FrameConfig::operator==(const FrameConfig& o) const { - return drop_frame == o.drop_frame && - last_buffer_flags == o.last_buffer_flags && - golden_buffer_flags == o.golden_buffer_flags && - arf_buffer_flags == o.arf_buffer_flags && layer_sync == o.layer_sync && - freeze_entropy == o.freeze_entropy && - encoder_layer_id == o.encoder_layer_id && - packetizer_temporal_idx == o.packetizer_temporal_idx; -} - -std::unique_ptr 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(2, Clock::GetRealTimeClock()); - } - - return absl::make_unique( - NumTemporalLayers(codec, spatial_id)); -} std::unique_ptr -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(2); +TemporalLayersChecker::CreateTemporalLayersChecker(TemporalLayersType type, + int num_temporal_layers) { + switch (type) { + case TemporalLayersType::kFixedPattern: + return absl::make_unique( + num_temporal_layers); + case TemporalLayersType::kBitrateDynamic: + // Conference mode temporal layering for screen content in base stream. + return absl::make_unique(num_temporal_layers); } - - return absl::make_unique( - NumTemporalLayers(codec, spatial_id)); } TemporalLayersChecker::TemporalLayersChecker(int num_temporal_layers) @@ -195,4 +138,5 @@ bool TemporalLayersChecker::CheckTemporalConfig( } return true; } + } // namespace webrtc diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index dc55d178e0..45a090df37 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -15,7 +15,7 @@ #include "common_video/libyuv/include/webrtc_libyuv.h" #include "modules/video_coding/codecs/test/video_codec_unittest.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/utility/vp8_header_parser.h" #include "rtc_base/timeutils.h" #include "test/video_codec_settings.h" diff --git a/modules/video_coding/codecs/vp8/vp8_temporal_layers.cc b/modules/video_coding/codecs/vp8/vp8_temporal_layers.cc new file mode 100644 index 0000000000..49584414a9 --- /dev/null +++ b/modules/video_coding/codecs/vp8/vp8_temporal_layers.cc @@ -0,0 +1,42 @@ +/* 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/include/vp8_temporal_layers.h" + +#include "absl/memory/memory.h" +#include "modules/video_coding/codecs/vp8/default_temporal_layers.h" +#include "modules/video_coding/codecs/vp8/screenshare_layers.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +bool TemporalLayers::FrameConfig::operator==(const FrameConfig& o) const { + return drop_frame == o.drop_frame && + last_buffer_flags == o.last_buffer_flags && + golden_buffer_flags == o.golden_buffer_flags && + arf_buffer_flags == o.arf_buffer_flags && layer_sync == o.layer_sync && + freeze_entropy == o.freeze_entropy && + encoder_layer_id == o.encoder_layer_id && + packetizer_temporal_idx == o.packetizer_temporal_idx; +} + +std::unique_ptr TemporalLayers::CreateTemporalLayers( + TemporalLayersType type, + int num_temporal_layers) { + switch (type) { + case TemporalLayersType::kFixedPattern: + return absl::make_unique(num_temporal_layers); + case TemporalLayersType::kBitrateDynamic: + // Conference mode temporal layering for screen content in base stream. + return absl::make_unique(num_temporal_layers, + Clock::GetRealTimeClock()); + } +} + +} // namespace webrtc diff --git a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc index 8166420d62..332c4b83b8 100644 --- a/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc +++ b/modules/video_coding/utility/simulcast_rate_allocator_unittest.cc @@ -15,7 +15,7 @@ #include #include -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "test/gmock.h" #include "test/gtest.h" diff --git a/modules/video_coding/utility/simulcast_utility.cc b/modules/video_coding/utility/simulcast_utility.cc index 60cf0627da..bc8616f9d4 100644 --- a/modules/video_coding/utility/simulcast_utility.cc +++ b/modules/video_coding/utility/simulcast_utility.cc @@ -8,6 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include "modules/video_coding/utility/simulcast_utility.h" namespace webrtc { @@ -62,4 +64,29 @@ bool SimulcastUtility::ValidSimulcastTemporalLayers(const VideoCodec& codec, return true; } +bool SimulcastUtility::IsConferenceModeScreenshare(const VideoCodec& codec) { + if (codec.mode != VideoCodecMode::kScreensharing || + NumberOfTemporalLayers(codec, 0) != 2) { + return false; + } + // Fixed default bitrates for legacy screenshare layers mode. + return (codec.numberOfSimulcastStreams == 0 && codec.maxBitrate == 1000) || + (codec.numberOfSimulcastStreams >= 1 && + codec.simulcastStream[0].maxBitrate == 1000 && + codec.simulcastStream[0].targetBitrate == 200); +} + +int SimulcastUtility::NumberOfTemporalLayers(const VideoCodec& codec, + int spatial_id) { + uint8_t num_temporal_layers = + std::max(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; +} + } // namespace webrtc diff --git a/modules/video_coding/utility/simulcast_utility.h b/modules/video_coding/utility/simulcast_utility.h index cf690f29a8..02ccab6cd7 100644 --- a/modules/video_coding/utility/simulcast_utility.h +++ b/modules/video_coding/utility/simulcast_utility.h @@ -23,6 +23,9 @@ class SimulcastUtility { int num_streams); static bool ValidSimulcastTemporalLayers(const VideoCodec& codec, int num_streams); + static int NumberOfTemporalLayers(const VideoCodec& codec, int spatial_id); + // TODO(sprang): Remove this hack when ScreenshareLayers is gone. + static bool IsConferenceModeScreenshare(const VideoCodec& codec); }; } // namespace webrtc diff --git a/modules/video_coding/video_codec_initializer_unittest.cc b/modules/video_coding/video_codec_initializer_unittest.cc index 80a30160f4..fb601f0d42 100644 --- a/modules/video_coding/video_codec_initializer_unittest.cc +++ b/modules/video_coding/video_codec_initializer_unittest.cc @@ -12,7 +12,7 @@ #include "api/video/video_bitrate_allocator.h" #include "api/video_codecs/video_encoder.h" #include "common_types.h" // NOLINT(build/include) -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "rtc_base/refcountedobject.h" #include "test/gtest.h" @@ -86,8 +86,9 @@ class VideoCodecInitializerTest : public ::testing::Test { // Make sure temporal layers instances have been created. if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) { for (int i = 0; i < codec_out_.numberOfSimulcastStreams; ++i) { - temporal_layers_.emplace_back( - TemporalLayers::CreateTemporalLayers(codec_out_, i)); + temporal_layers_.emplace_back(TemporalLayers::CreateTemporalLayers( + TemporalLayersType::kFixedPattern, + codec_out_.VP8()->numberOfTemporalLayers)); } } return true; diff --git a/modules/video_coding/video_sender_unittest.cc b/modules/video_coding/video_sender_unittest.cc index 5c7f32d677..3cd9caf65c 100644 --- a/modules/video_coding/video_sender_unittest.cc +++ b/modules/video_coding/video_sender_unittest.cc @@ -13,7 +13,7 @@ #include "api/video/i420_buffer.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/mock/mock_vcm_callbacks.h" #include "modules/video_coding/include/mock/mock_video_codec_interface.h" #include "modules/video_coding/include/video_coding.h" diff --git a/test/fake_encoder.cc b/test/fake_encoder.cc index b02d6c160f..bc3c7b1087 100644 --- a/test/fake_encoder.cc +++ b/test/fake_encoder.cc @@ -16,7 +16,7 @@ #include #include "common_types.h" // NOLINT(build/include) -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/video_codec_interface.h" #include "rtc_base/checks.h" #include "system_wrappers/include/sleep.h" diff --git a/test/fake_vp8_encoder.cc b/test/fake_vp8_encoder.cc index afd16d4e1e..07f9d8f666 100644 --- a/test/fake_vp8_encoder.cc +++ b/test/fake_vp8_encoder.cc @@ -11,7 +11,7 @@ #include "test/fake_vp8_encoder.h" #include "common_types.h" // NOLINT(build/include) -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/include/video_codec_interface.h" #include "modules/video_coding/include/video_error_codes.h" #include "modules/video_coding/utility/simulcast_utility.h" @@ -47,15 +47,7 @@ int32_t FakeVP8Encoder::InitEncode(const VideoCodec* config, return result; } - int number_of_streams = SimulcastUtility::NumberOfSimulcastStreams(*config); - bool doing_simulcast = number_of_streams > 1; - - int num_temporal_layers = - doing_simulcast ? config->simulcastStream[0].numberOfTemporalLayers - : config->VP8().numberOfTemporalLayers; - RTC_DCHECK_GT(num_temporal_layers, 0); - - SetupTemporalLayers(number_of_streams, num_temporal_layers, *config); + SetupTemporalLayers(*config); return WEBRTC_VIDEO_CODEC_OK; } @@ -66,15 +58,23 @@ int32_t FakeVP8Encoder::Release() { return result; } -void FakeVP8Encoder::SetupTemporalLayers(int num_streams, - int num_temporal_layers, - const VideoCodec& codec) { +void FakeVP8Encoder::SetupTemporalLayers(const VideoCodec& codec) { RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); - temporal_layers_.clear(); + int num_streams = SimulcastUtility::NumberOfSimulcastStreams(codec); for (int i = 0; i < num_streams; ++i) { + TemporalLayersType type; + int num_temporal_layers = + SimulcastUtility::NumberOfTemporalLayers(codec, i); + if (SimulcastUtility::IsConferenceModeScreenshare(codec) && i == 0) { + type = TemporalLayersType::kBitrateDynamic; + // Legacy screenshare layers supports max 2 layers. + num_temporal_layers = std::max(2, num_temporal_layers); + } else { + type = TemporalLayersType::kFixedPattern; + } temporal_layers_.emplace_back( - TemporalLayers::CreateTemporalLayers(codec, i)); + TemporalLayers::CreateTemporalLayers(type, num_temporal_layers)); } } diff --git a/test/fake_vp8_encoder.h b/test/fake_vp8_encoder.h index 407361bc7d..f21f9f50aa 100644 --- a/test/fake_vp8_encoder.h +++ b/test/fake_vp8_encoder.h @@ -14,7 +14,7 @@ #include #include -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "test/fake_encoder.h" #include "rtc_base/criticalsection.h" @@ -44,9 +44,7 @@ class FakeVP8Encoder : public FakeEncoder, public EncodedImageCallback { const RTPFragmentationHeader* fragments) override; private: - void SetupTemporalLayers(int num_streams, - int num_temporal_layers, - const VideoCodec& codec); + void SetupTemporalLayers(const VideoCodec& codec); void PopulateCodecSpecific(CodecSpecificInfo* codec_specific, const TemporalLayers::FrameConfig& tl_config, FrameType frame_type, diff --git a/video/video_stream_encoder_unittest.cc b/video/video_stream_encoder_unittest.cc index e09df8298a..80f8d5a592 100644 --- a/video/video_stream_encoder_unittest.cc +++ b/video/video_stream_encoder_unittest.cc @@ -14,7 +14,7 @@ #include "api/video/i420_buffer.h" #include "media/base/videoadapter.h" -#include "modules/video_coding/codecs/vp8/temporal_layers.h" +#include "modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h" #include "modules/video_coding/codecs/vp9/include/vp9_globals.h" #include "modules/video_coding/utility/default_video_bitrate_allocator.h" #include "rtc_base/fakeclock.h" @@ -569,7 +569,9 @@ class VideoStreamEncoderTest : public ::testing::Test { int num_streams = std::max(1, config->numberOfSimulcastStreams); for (int i = 0; i < num_streams; ++i) { allocated_temporal_layers_.emplace_back( - TemporalLayers::CreateTemporalLayers(*config, i)); + TemporalLayers::CreateTemporalLayers( + TemporalLayersType::kFixedPattern, + config->VP8().numberOfTemporalLayers)); } } if (force_init_encode_failed_)