Split TemporalLayers and TemporalLayers checker, clean up header.
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 <sprang@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Reviewed-by: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24920}
diff --git a/modules/video_coding/BUILD.gn b/modules/video_coding/BUILD.gn
index f000f41..c992da5 100644
--- a/modules/video_coding/BUILD.gn
+++ b/modules/video_coding/BUILD.gn
@@ -393,15 +393,18 @@
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 @@
}
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 6914479..ab54621 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 <set>
#include <vector>
-#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 0000000..9878ac9
--- /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 <stdint.h>
+
+#include <memory>
+
+#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<TemporalLayersChecker> 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 0000000..1b668eb
--- /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 <memory>
+#include <vector>
+
+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<TemporalLayers> 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<uint32_t>& 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 72e5f87..2b72508 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 @@
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 @@
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 @@
FillInEncoderConfig(cfg, config);
return res;
}
+
} // namespace
std::unique_ptr<VP8Encoder> VP8Encoder::Create() {
@@ -284,15 +285,25 @@
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<int>(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 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 @@
// 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 b1889fc..8ee359e 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 @@
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 fcc3aca..cd12ac4 100644
--- a/modules/video_coding/codecs/vp8/screenshare_layers.h
+++ b/modules/video_coding/codecs/vp8/screenshare_layers.h
@@ -11,7 +11,7 @@
#include <vector>
-#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 91b5531..788d69a 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 <vector>
-#include <memory>
+// 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<TemporalLayers> CreateTemporalLayers(
- const VideoCodec& codec,
- size_t spatial_id);
- static std::unique_ptr<TemporalLayersChecker> 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<uint32_t>& 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 236950a..b77e8bc 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 <algorithm>
-#include <memory>
-#include <set>
-#include <vector>
-
+#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<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 ||
- 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> 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);
+TemporalLayersChecker::CreateTemporalLayersChecker(TemporalLayersType type,
+ int num_temporal_layers) {
+ switch (type) {
+ case TemporalLayersType::kFixedPattern:
+ return absl::make_unique<DefaultTemporalLayersChecker>(
+ num_temporal_layers);
+ case TemporalLayersType::kBitrateDynamic:
+ // Conference mode temporal layering for screen content in base stream.
+ return absl::make_unique<TemporalLayersChecker>(num_temporal_layers);
}
-
- return absl::make_unique<DefaultTemporalLayersChecker>(
- NumTemporalLayers(codec, spatial_id));
}
TemporalLayersChecker::TemporalLayersChecker(int num_temporal_layers)
@@ -195,4 +138,5 @@
}
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 dc55d17..45a090d 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 0000000..4958441
--- /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> TemporalLayers::CreateTemporalLayers(
+ TemporalLayersType type,
+ int num_temporal_layers) {
+ switch (type) {
+ case TemporalLayersType::kFixedPattern:
+ return absl::make_unique<DefaultTemporalLayers>(num_temporal_layers);
+ case TemporalLayersType::kBitrateDynamic:
+ // Conference mode temporal layering for screen content in base stream.
+ return absl::make_unique<ScreenshareLayers>(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 8166420..332c4b8 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 <utility>
#include <vector>
-#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 60cf062..bc8616f 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 <algorithm>
+
#include "modules/video_coding/utility/simulcast_utility.h"
namespace webrtc {
@@ -62,4 +64,29 @@
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<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;
+}
+
} // namespace webrtc
diff --git a/modules/video_coding/utility/simulcast_utility.h b/modules/video_coding/utility/simulcast_utility.h
index cf690f2..02ccab6 100644
--- a/modules/video_coding/utility/simulcast_utility.h
+++ b/modules/video_coding/utility/simulcast_utility.h
@@ -23,6 +23,9 @@
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 80a3016..fb601f0 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 @@
// 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 5c7f32d..3cd9caf 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"