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}
This commit is contained in:
Erik Språng
2018-10-01 18:47:03 +02:00
committed by Commit Bot
parent ee216640dd
commit 8abd56cfdf
22 changed files with 420 additions and 352 deletions

View File

@ -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",

View File

@ -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"

View File

@ -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_

View File

@ -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_

View File

@ -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> 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<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 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);

View File

@ -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);

View File

@ -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"

View File

@ -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_

View File

@ -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 @@ bool TemporalLayersChecker::CheckTemporalConfig(
}
return true;
}
} // namespace webrtc

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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 @@ 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<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

View File

@ -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

View File

@ -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;

View File

@ -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"