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:
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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_
|
||||
188
modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h
Normal file
188
modules/video_coding/codecs/vp8/include/vp8_temporal_layers.h
Normal 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_
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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
|
||||
@ -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"
|
||||
|
||||
42
modules/video_coding/codecs/vp8/vp8_temporal_layers.cc
Normal file
42
modules/video_coding/codecs/vp8/vp8_temporal_layers.cc
Normal 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
|
||||
@ -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"
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
|
||||
Reference in New Issue
Block a user