Refactor VP8 encoder creation logic

Now decision between using SimulcastEncoderAdapter and using VP8 encoder
is postponed before codec is initialized for VP8 internal codecs. This is done
be new VP8EncoderProxy class. New error code for codec initialization is used
to signal that simulcast parameters are not supported.

Bug: webrtc:7925
Change-Id: I3a82c21bf5dfaaa7fa25350986830523f02c39d8
Reviewed-on: https://webrtc-review.googlesource.com/13980
Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20419}
This commit is contained in:
Ilya Nikolaevskiy
2017-10-25 10:04:54 +02:00
committed by Commit Bot
parent 7ddd46386a
commit c22a3a6a7d
9 changed files with 386 additions and 27 deletions

View File

@ -162,6 +162,8 @@ rtc_static_library("rtc_audio_video") {
"engine/videodecodersoftwarefallbackwrapper.h",
"engine/videoencodersoftwarefallbackwrapper.cc",
"engine/videoencodersoftwarefallbackwrapper.h",
"engine/vp8_encoder_simulcast_proxy.cc",
"engine/vp8_encoder_simulcast_proxy.h",
"engine/webrtcmediaengine.cc",
"engine/webrtcmediaengine.h",
"engine/webrtcvideocapturer.cc",
@ -460,6 +462,7 @@ if (rtc_include_tests) {
"engine/simulcast_unittest.cc",
"engine/videodecodersoftwarefallbackwrapper_unittest.cc",
"engine/videoencodersoftwarefallbackwrapper_unittest.cc",
"engine/vp8_encoder_simulcast_proxy_unittest.cc",
"engine/webrtcmediaengine_unittest.cc",
"engine/webrtcvideocapturer_unittest.cc",
"engine/webrtcvideoencoderfactory_unittest.cc",
@ -541,6 +544,7 @@ if (rtc_include_tests) {
"../system_wrappers:metrics_default",
"../test:audio_codec_mocks",
"../test:test_support",
"../test:video_test_common",
"../voice_engine:voice_engine",
]
}

View File

@ -0,0 +1,85 @@
/*
* 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 "media/engine/vp8_encoder_simulcast_proxy.h"
#include "media/engine/scopedvideoencoder.h"
#include "media/engine/simulcast_encoder_adapter.h"
#include "rtc_base/checks.h"
namespace webrtc {
VP8EncoderSimulcastProxy::VP8EncoderSimulcastProxy(
cricket::WebRtcVideoEncoderFactory* factory)
: factory_(factory), callback_(nullptr) {
encoder_ = CreateScopedVideoEncoder(factory_, cricket::VideoCodec("VP8"));
}
VP8EncoderSimulcastProxy::~VP8EncoderSimulcastProxy() {}
int VP8EncoderSimulcastProxy::Release() {
return encoder_->Release();
}
int VP8EncoderSimulcastProxy::InitEncode(const VideoCodec* inst,
int number_of_cores,
size_t max_payload_size) {
int ret = encoder_->InitEncode(inst, number_of_cores, max_payload_size);
if (ret == WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED) {
encoder_.reset(new SimulcastEncoderAdapter(factory_));
if (callback_) {
encoder_->RegisterEncodeCompleteCallback(callback_);
}
ret = encoder_->InitEncode(inst, number_of_cores, max_payload_size);
}
return ret;
}
int VP8EncoderSimulcastProxy::Encode(
const VideoFrame& input_image,
const CodecSpecificInfo* codec_specific_info,
const std::vector<FrameType>* frame_types) {
return encoder_->Encode(input_image, codec_specific_info, frame_types);
}
int VP8EncoderSimulcastProxy::RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) {
callback_ = callback;
return encoder_->RegisterEncodeCompleteCallback(callback);
}
int VP8EncoderSimulcastProxy::SetChannelParameters(uint32_t packet_loss,
int64_t rtt) {
return encoder_->SetChannelParameters(packet_loss, rtt);
}
int VP8EncoderSimulcastProxy::SetRateAllocation(
const BitrateAllocation& bitrate,
uint32_t new_framerate) {
return encoder_->SetRateAllocation(bitrate, new_framerate);
}
VideoEncoder::ScalingSettings VP8EncoderSimulcastProxy::GetScalingSettings()
const {
return encoder_->GetScalingSettings();
}
int32_t VP8EncoderSimulcastProxy::SetPeriodicKeyFrames(bool enable) {
return encoder_->SetPeriodicKeyFrames(enable);
}
bool VP8EncoderSimulcastProxy::SupportsNativeHandle() const {
return encoder_->SupportsNativeHandle();
}
const char* VP8EncoderSimulcastProxy::ImplementationName() const {
return encoder_->ImplementationName();
}
} // namespace webrtc

View File

@ -0,0 +1,58 @@
/*
* 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.
*
*/
#ifndef MEDIA_ENGINE_VP8_ENCODER_SIMULCAST_PROXY_H_
#define MEDIA_ENGINE_VP8_ENCODER_SIMULCAST_PROXY_H_
#include <memory>
#include <vector>
#include "media/engine/webrtcvideoencoderfactory.h"
#include "modules/video_coding/codecs/vp8/include/vp8.h"
namespace webrtc {
// This class provides fallback to SimulcastEncoderAdapter if default VP8Encoder
// doesn't support simulcast for provided settings.
class VP8EncoderSimulcastProxy : public VP8Encoder {
public:
explicit VP8EncoderSimulcastProxy(
cricket::WebRtcVideoEncoderFactory* factory);
virtual ~VP8EncoderSimulcastProxy();
// Implements VideoEncoder.
int Release() override;
int InitEncode(const VideoCodec* inst,
int number_of_cores,
size_t max_payload_size) override;
int Encode(const VideoFrame& input_image,
const CodecSpecificInfo* codec_specific_info,
const std::vector<FrameType>* frame_types) override;
int RegisterEncodeCompleteCallback(EncodedImageCallback* callback) override;
int SetChannelParameters(uint32_t packet_loss, int64_t rtt) override;
int SetRateAllocation(const BitrateAllocation& bitrate,
uint32_t new_framerate) override;
VideoEncoder::ScalingSettings GetScalingSettings() const override;
int32_t SetPeriodicKeyFrames(bool enable) override;
bool SupportsNativeHandle() const override;
const char* ImplementationName() const override;
private:
cricket::WebRtcVideoEncoderFactory* const factory_;
std::unique_ptr<VideoEncoder> encoder_;
EncodedImageCallback* callback_;
};
} // namespace webrtc
#endif // MEDIA_ENGINE_VP8_ENCODER_SIMULCAST_PROXY_H_

View File

@ -0,0 +1,152 @@
/*
* 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 "media/engine/vp8_encoder_simulcast_proxy.h"
#include <string>
#include "media/engine/webrtcvideoencoderfactory.h"
#include "modules/video_coding/codecs/vp8/temporal_layers.h"
#include "modules/video_coding/include/video_codec_interface.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/video_codec_settings.h"
namespace webrtc {
namespace testing {
using ::testing::Return;
using ::testing::_;
using ::testing::NiceMock;
class MockEncoder : public VideoEncoder {
public:
// TODO(nisse): Valid overrides commented out, because the gmock
// methods don't use any override declarations, and we want to avoid
// warnings from -Winconsistent-missing-override. See
// http://crbug.com/428099.
MockEncoder() {}
virtual ~MockEncoder() {}
MOCK_METHOD3(InitEncode,
int32_t(const VideoCodec* codec_settings,
int32_t number_of_cores,
size_t max_payload_size));
MOCK_METHOD1(RegisterEncodeCompleteCallback, int32_t(EncodedImageCallback*));
MOCK_METHOD0(Release, int32_t());
MOCK_METHOD3(
Encode,
int32_t(const VideoFrame& inputImage,
const CodecSpecificInfo* codecSpecificInfo,
const std::vector<FrameType>* frame_types) /* override */);
MOCK_METHOD2(SetChannelParameters, int32_t(uint32_t packetLoss, int64_t rtt));
MOCK_CONST_METHOD0(ImplementationName, const char*());
};
class MockWebRtcVideoEncoderFactory
: public cricket::WebRtcVideoEncoderFactory {
public:
MockWebRtcVideoEncoderFactory() {}
virtual ~MockWebRtcVideoEncoderFactory() {}
MOCK_METHOD1(CreateVideoEncoder,
webrtc::VideoEncoder*(const cricket::VideoCodec& codec));
MOCK_CONST_METHOD0(supported_codecs, std::vector<cricket::VideoCodec>&());
MOCK_METHOD1(DestroyVideoEncoder, void(webrtc::VideoEncoder*));
};
TEST(VP8EncoderSimulcastProxy, ChoosesCorrectImplementation) {
const std::string kImplementationName = "Fake";
const std::string kSimulcastAdaptedImplementationName =
"SimulcastEncoderAdapter (Fake, Fake, Fake)";
VideoCodec codec_settings;
webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings);
TemporalLayersFactory tl_factory;
codec_settings.VP8()->tl_factory = &tl_factory;
codec_settings.simulcastStream[0] = {
test::kTestWidth, test::kTestHeight, 2, 2000, 1000, 1000, 56};
codec_settings.simulcastStream[1] = {
test::kTestWidth, test::kTestHeight, 2, 3000, 1000, 1000, 56};
codec_settings.simulcastStream[2] = {
test::kTestWidth, test::kTestHeight, 2, 5000, 1000, 1000, 56};
codec_settings.numberOfSimulcastStreams = 3;
NiceMock<MockEncoder> mock_encoder;
NiceMock<MockWebRtcVideoEncoderFactory> simulcast_factory;
EXPECT_CALL(mock_encoder, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(mock_encoder, ImplementationName())
.WillRepeatedly(Return(kImplementationName.c_str()));
EXPECT_CALL(simulcast_factory, CreateVideoEncoder(_))
.Times(1)
.WillOnce(Return(&mock_encoder));
VP8EncoderSimulcastProxy simulcast_enabled_proxy(&simulcast_factory);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
simulcast_enabled_proxy.InitEncode(&codec_settings, 4, 1200));
EXPECT_EQ(kImplementationName, simulcast_enabled_proxy.ImplementationName());
NiceMock<MockEncoder> mock_encoder1;
NiceMock<MockEncoder> mock_encoder2;
NiceMock<MockEncoder> mock_encoder3;
NiceMock<MockEncoder> mock_encoder4;
NiceMock<MockWebRtcVideoEncoderFactory> nonsimulcast_factory;
EXPECT_CALL(mock_encoder1, InitEncode(_, _, _))
.WillOnce(
Return(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED));
EXPECT_CALL(mock_encoder1, ImplementationName())
.WillRepeatedly(Return(kImplementationName.c_str()));
EXPECT_CALL(mock_encoder2, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(mock_encoder2, ImplementationName())
.WillRepeatedly(Return(kImplementationName.c_str()));
EXPECT_CALL(mock_encoder3, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(mock_encoder3, ImplementationName())
.WillRepeatedly(Return(kImplementationName.c_str()));
EXPECT_CALL(mock_encoder4, InitEncode(_, _, _))
.WillOnce(Return(WEBRTC_VIDEO_CODEC_OK));
EXPECT_CALL(mock_encoder4, ImplementationName())
.WillRepeatedly(Return(kImplementationName.c_str()));
EXPECT_CALL(nonsimulcast_factory, CreateVideoEncoder(_))
.Times(4)
.WillOnce(Return(&mock_encoder1))
.WillOnce(Return(&mock_encoder2))
.WillOnce(Return(&mock_encoder3))
.WillOnce(Return(&mock_encoder4));
VP8EncoderSimulcastProxy simulcast_disabled_proxy(&nonsimulcast_factory);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
simulcast_disabled_proxy.InitEncode(&codec_settings, 4, 1200));
EXPECT_EQ(kSimulcastAdaptedImplementationName,
simulcast_disabled_proxy.ImplementationName());
// Cleanup.
simulcast_enabled_proxy.Release();
simulcast_disabled_proxy.Release();
}
} // namespace testing
} // namespace webrtc

View File

@ -42,6 +42,7 @@
#include "rtc_base/timeutils.h"
#include "rtc_base/trace_event.h"
#include "system_wrappers/include/field_trial.h"
#include "vp8_encoder_simulcast_proxy.h"
using DegradationPreference = webrtc::VideoSendStream::DegradationPreference;
@ -67,8 +68,7 @@ class EncoderFactoryAdapter {
virtual ~EncoderFactoryAdapter() {}
virtual AllocatedEncoder CreateVideoEncoder(
const VideoCodec& codec,
bool is_conference_mode_screenshare) const = 0;
const VideoCodec& codec) const = 0;
virtual std::vector<VideoCodec> GetSupportedCodecs() const = 0;
};
@ -99,9 +99,7 @@ class CricketEncoderFactoryAdapter : public EncoderFactoryAdapter {
external_encoder_factory_(std::move(external_encoder_factory)) {}
private:
AllocatedEncoder CreateVideoEncoder(
const VideoCodec& codec,
bool is_conference_mode_screenshare) const override;
AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec) const override;
std::vector<VideoCodec> GetSupportedCodecs() const override;
@ -134,9 +132,7 @@ class WebRtcEncoderFactoryAdapter : public EncoderFactoryAdapter {
: encoder_factory_(std::move(encoder_factory)) {}
private:
AllocatedEncoder CreateVideoEncoder(
const VideoCodec& codec,
bool is_conference_mode_screenshare) const override {
AllocatedEncoder CreateVideoEncoder(const VideoCodec& codec) const override {
if (!encoder_factory_)
return AllocatedEncoder();
const webrtc::SdpVideoFormat format(codec.name, codec.params);
@ -1688,8 +1684,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetSsrcs() const {
EncoderFactoryAdapter::AllocatedEncoder
CricketEncoderFactoryAdapter::CreateVideoEncoder(
const VideoCodec& codec,
bool is_conference_mode_screenshare) const {
const VideoCodec& codec) const {
// Try creating external encoder.
if (external_encoder_factory_ != nullptr &&
FindMatchingCodec(external_encoder_factory_->supported_codecs(), codec)) {
@ -1719,12 +1714,10 @@ CricketEncoderFactoryAdapter::CreateVideoEncoder(
// Try creating internal encoder.
std::unique_ptr<webrtc::VideoEncoder> internal_encoder;
if (FindMatchingCodec(internal_encoder_factory_->supported_codecs(), codec)) {
if (CodecNamesEq(codec.name.c_str(), kVp8CodecName) &&
is_conference_mode_screenshare && UseSimulcastScreenshare()) {
// TODO(sprang): Remove this adapter once libvpx supports simulcast with
// same-resolution substreams.
if (CodecNamesEq(codec.name.c_str(), kVp8CodecName)) {
internal_encoder = std::unique_ptr<webrtc::VideoEncoder>(
new webrtc::SimulcastEncoderAdapter(internal_encoder_factory_.get()));
new webrtc::VP8EncoderSimulcastProxy(
internal_encoder_factory_.get()));
} else {
internal_encoder = std::unique_ptr<webrtc::VideoEncoder>(
internal_encoder_factory_->CreateVideoEncoder(codec));
@ -1753,13 +1746,8 @@ void WebRtcVideoChannel::WebRtcVideoSendStream::SetCodec(
std::unique_ptr<webrtc::VideoEncoder> new_encoder;
if (force_encoder_allocation || !allocated_encoder_ ||
allocated_codec_ != codec_settings.codec) {
const bool is_conference_mode_screenshare =
parameters_.encoder_config.content_type ==
webrtc::VideoEncoderConfig::ContentType::kScreen &&
parameters_.conference_mode;
EncoderFactoryAdapter::AllocatedEncoder new_allocated_encoder =
encoder_factory_->CreateVideoEncoder(codec_settings.codec,
is_conference_mode_screenshare);
encoder_factory_->CreateVideoEncoder(codec_settings.codec);
new_encoder = std::unique_ptr<webrtc::VideoEncoder>(
std::move(new_allocated_encoder.encoder));
parameters_.config.encoder_settings.encoder = new_encoder.get();

View File

@ -67,10 +67,6 @@ TEST_F(TestVp8Impl, TestSaptioTemporalLayers333PatternEncoder) {
TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder();
}
TEST_F(TestVp8Impl, TestSpatioTemporalLayers321PatternEncoder) {
TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder();
}
TEST_F(TestVp8Impl, TestStrideEncodeDecode) {
TestVp8Simulcast::TestStrideEncodeDecode();
}

View File

@ -286,6 +286,64 @@ TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) {
EXPECT_EQ(encoded_cb_.encoded_frame_.qp_, *decoded_cb_.qp_);
}
TEST_F(TestVp8Impl, ChecksSimulcastSettings) {
codec_settings_.numberOfSimulcastStreams = 2;
// Reslutions are not scaled by 2, temporal layers do not match.
codec_settings_.simulcastStream[0] = {kWidth, kHeight, 2, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[1] = {kWidth, kHeight, 3, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
codec_settings_.numberOfSimulcastStreams = 3;
// Reslutions are not scaled by 2.
codec_settings_.simulcastStream[0] = {kWidth / 2, kHeight / 2, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[1] = {kWidth / 2, kHeight / 2, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[2] = {kWidth, kHeight, 1, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Reslutions are not scaled by 2.
codec_settings_.simulcastStream[0] = {kWidth, kHeight, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[1] = {kWidth, kHeight, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[2] = {kWidth, kHeight, 1, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Temporal layers do not match.
codec_settings_.simulcastStream[0] = {kWidth / 4, kHeight / 4, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[1] = {kWidth / 2, kHeight / 2, 2, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[2] = {kWidth, kHeight, 3, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Resolutions do not match codec config.
codec_settings_.simulcastStream[0] = {
kWidth / 4 + 1, kHeight / 4 + 1, 1, 4000, 3000, 2000, 80};
codec_settings_.simulcastStream[1] = {
kWidth / 2 + 2, kHeight / 2 + 2, 1, 4000, 3000, 2000, 80};
codec_settings_.simulcastStream[2] = {kWidth + 4, kHeight + 4, 1, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
// Everything fine: scaling by 2, top resolution matches video, temporal
// settings are the same for all layers.
codec_settings_.simulcastStream[0] = {kWidth / 4, kHeight / 4, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[1] = {kWidth / 2, kHeight / 2, 1, 4000,
3000, 2000, 80};
codec_settings_.simulcastStream[2] = {kWidth, kHeight, 1, 4000,
3000, 2000, 80};
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize));
}
#if defined(WEBRTC_ANDROID)
#define MAYBE_AlignedStrideEncodeDecode DISABLED_AlignedStrideEncodeDecode
#else

View File

@ -100,6 +100,21 @@ bool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) {
return false;
}
}
for (int i = 1; i < num_streams; ++i) {
if (codec.simulcastStream[i].width !=
codec.simulcastStream[i - 1].width * 2) {
return false;
}
}
return true;
}
bool ValidSimulcastTemporalLayers(const VideoCodec& codec, int num_streams) {
for (int i = 0; i < num_streams - 1; ++i) {
if (codec.simulcastStream[i].numberOfTemporalLayers !=
codec.simulcastStream[i + 1].numberOfTemporalLayers)
return false;
}
return true;
}
@ -395,8 +410,10 @@ int VP8EncoderImpl::InitEncode(const VideoCodec* inst,
int number_of_streams = NumberOfStreams(*inst);
bool doing_simulcast = (number_of_streams > 1);
if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
if (doing_simulcast &&
(!ValidSimulcastResolutions(*inst, number_of_streams) ||
!ValidSimulcastTemporalLayers(*inst, number_of_streams))) {
return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED;
}
int num_temporal_layers =

View File

@ -28,5 +28,6 @@
#define WEBRTC_VIDEO_CODEC_ERR_REQUEST_SLI -12
#define WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE -13
#define WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT -14
#define WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED -15
#endif // MODULES_VIDEO_CODING_INCLUDE_VIDEO_ERROR_CODES_H_