blob: 9ea3c9c09a210e45454bca2699ee7c6d07ec0a4f [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org439be292012-02-16 14:45:37 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000011#include "webrtc/video_engine/vie_codec_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +000013#include <list>
14
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000015#include "webrtc/engine_configurations.h"
16#include "webrtc/modules/video_coding/main/interface/video_coding.h"
17#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.orgf5d4cb12013-05-17 13:44:48 +000018#include "webrtc/video_engine/include/vie_errors.h"
19#include "webrtc/video_engine/vie_capturer.h"
20#include "webrtc/video_engine/vie_channel.h"
21#include "webrtc/video_engine/vie_channel_manager.h"
22#include "webrtc/video_engine/vie_defines.h"
23#include "webrtc/video_engine/vie_encoder.h"
24#include "webrtc/video_engine/vie_impl.h"
25#include "webrtc/video_engine/vie_input_manager.h"
26#include "webrtc/video_engine/vie_shared_data.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000028namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000029
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000030static void LogCodec(const VideoCodec& codec) {
31 LOG(LS_INFO) << "CodecType " << codec.codecType
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000032 << ", pl_type " << static_cast<int>(codec.plType)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000033 << ", resolution " << codec.width
34 << " x " << codec.height
35 << ", start br " << codec.startBitrate
36 << ", min br " << codec.minBitrate
37 << ", max br " << codec.maxBitrate
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000038 << ", max fps " << static_cast<int>(codec.maxFramerate)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000039 << ", max qp " << codec.qpMax
40 << ", number of streams "
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000041 << static_cast<int>(codec.numberOfSimulcastStreams);
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000042 if (codec.codecType == kVideoCodecVP8) {
43 LOG(LS_INFO) << "VP8 specific settings";
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000044 LOG(LS_INFO) << "pictureLossIndicationOn "
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000045 << codec.codecSpecific.VP8.pictureLossIndicationOn
46 << ", feedbackModeOn "
47 << codec.codecSpecific.VP8.feedbackModeOn
48 << ", complexity "
49 << codec.codecSpecific.VP8.complexity
50 << ", resilience "
51 << codec.codecSpecific.VP8.resilience
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000052 << ", numberOfTemporalLayers "
53 << static_cast<int>(
54 codec.codecSpecific.VP8.numberOfTemporalLayers)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000055 << ", keyFrameinterval "
56 << codec.codecSpecific.VP8.keyFrameInterval;
57 for (int idx = 0; idx < codec.numberOfSimulcastStreams; ++idx) {
58 LOG(LS_INFO) << "Stream " << codec.simulcastStream[idx].width
59 << " x " << codec.simulcastStream[idx].height;
60 LOG(LS_INFO) << "Temporal layers "
asapersson@webrtc.org46106f22014-04-25 07:02:52 +000061 << static_cast<int>(
62 codec.simulcastStream[idx].numberOfTemporalLayers)
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000063 << ", min br "
64 << codec.simulcastStream[idx].minBitrate
65 << ", target br "
66 << codec.simulcastStream[idx].targetBitrate
67 << ", max br "
68 << codec.simulcastStream[idx].maxBitrate
69 << ", qp max "
70 << codec.simulcastStream[idx].qpMax;
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000071 }
72 }
73}
74
75
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000076ViECodec* ViECodec::GetInterface(VideoEngine* video_engine) {
niklase@google.com470e71d2011-07-07 08:21:25 +000077#ifdef WEBRTC_VIDEO_ENGINE_CODEC_API
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000078 if (!video_engine) {
niklase@google.com470e71d2011-07-07 08:21:25 +000079 return NULL;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000080 }
andrew@webrtc.orgd72262d2013-05-09 02:12:07 +000081 VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000082 ViECodecImpl* vie_codec_impl = vie_impl;
83 // Increase ref count.
84 (*vie_codec_impl)++;
85 return vie_codec_impl;
86#else
87 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000088#endif
89}
90
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000091int ViECodecImpl::Release() {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000092 LOG(LS_INFO) << "ViECodec::Release.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000093 // Decrease ref count.
94 (*this)--;
niklase@google.com470e71d2011-07-07 08:21:25 +000095
pbos@webrtc.orgb238d122013-04-09 13:41:51 +000096 int32_t ref_count = GetCount();
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +000097 if (ref_count < 0) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000098 LOG(LS_WARNING) << "ViECodec released too many times.";
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +000099 shared_data_->SetLastError(kViEAPIDoesNotExist);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000100 return -1;
101 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000102 return ref_count;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103}
104
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000105ViECodecImpl::ViECodecImpl(ViESharedData* shared_data)
106 : shared_data_(shared_data) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000107}
108
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000109ViECodecImpl::~ViECodecImpl() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000110}
111
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000112int ViECodecImpl::NumberOfCodecs() const {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000113 // +2 because of FEC(RED and ULPFEC)
114 return static_cast<int>((VideoCodingModule::NumberOfCodecs() + 2));
niklase@google.com470e71d2011-07-07 08:21:25 +0000115}
116
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000117int ViECodecImpl::GetCodec(const unsigned char list_number,
118 VideoCodec& video_codec) const {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000119 if (list_number == VideoCodingModule::NumberOfCodecs()) {
120 memset(&video_codec, 0, sizeof(VideoCodec));
mflodman@webrtc.orgaeff4f32013-04-22 12:41:57 +0000121 strcpy(video_codec.plName, "red");
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000122 video_codec.codecType = kVideoCodecRED;
123 video_codec.plType = VCM_RED_PAYLOAD_TYPE;
124 } else if (list_number == VideoCodingModule::NumberOfCodecs() + 1) {
125 memset(&video_codec, 0, sizeof(VideoCodec));
mflodman@webrtc.orgaeff4f32013-04-22 12:41:57 +0000126 strcpy(video_codec.plName, "ulpfec");
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000127 video_codec.codecType = kVideoCodecULPFEC;
128 video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
129 } else if (VideoCodingModule::Codec(list_number, &video_codec) != VCM_OK) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000130 shared_data_->SetLastError(kViECodecInvalidArgument);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000131 return -1;
132 }
133 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000134}
135
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000136int ViECodecImpl::SetSendCodec(const int video_channel,
137 const VideoCodec& video_codec) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000138 LOG(LS_INFO) << "SetSendCodec for channel " << video_channel;
139 LogCodec(video_codec);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000140 if (!CodecValid(video_codec)) {
141 // Error logged.
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000142 shared_data_->SetLastError(kViECodecInvalidCodec);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000143 return -1;
144 }
stefan@webrtc.org791eec72011-10-11 07:53:43 +0000145
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000146 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000147 ViEChannel* vie_channel = cs.Channel(video_channel);
148 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000149 shared_data_->SetLastError(kViECodecInvalidChannelId);
stefan@webrtc.org791eec72011-10-11 07:53:43 +0000150 return -1;
151 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000152
mflodman@webrtc.org9ec883e2012-03-05 17:12:41 +0000153 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
154 assert(vie_encoder);
155 if (vie_encoder->Owner() != video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000156 LOG_F(LS_ERROR) << "Receive only channel.";
mflodman@webrtc.org9ec883e2012-03-05 17:12:41 +0000157 shared_data_->SetLastError(kViECodecReceiveOnlyChannel);
158 return -1;
159 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000160 // Set a max_bitrate if the user hasn't set one.
161 VideoCodec video_codec_internal;
162 memcpy(&video_codec_internal, &video_codec, sizeof(VideoCodec));
163 if (video_codec_internal.maxBitrate == 0) {
164 // Max is one bit per pixel.
165 video_codec_internal.maxBitrate = (video_codec_internal.width *
166 video_codec_internal.height *
167 video_codec_internal.maxFramerate)
168 / 1000;
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000169 LOG(LS_INFO) << "New max bitrate set " << video_codec_internal.maxBitrate;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000170 }
171
mflodman@webrtc.org60310012013-12-20 15:07:12 +0000172 if (video_codec_internal.startBitrate > video_codec_internal.maxBitrate) {
173 video_codec_internal.startBitrate = video_codec_internal.maxBitrate;
174 }
175
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000176 VideoCodec encoder;
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000177 vie_encoder->GetEncoder(&encoder);
mflodman@webrtc.org9ec883e2012-03-05 17:12:41 +0000178
mflodman@webrtc.org9c0aedc2012-01-03 13:46:49 +0000179 // Make sure to generate a new SSRC if the codec type and/or resolution has
180 // changed. This won't have any effect if the user has set an SSRC.
181 bool new_rtp_stream = false;
stefan@webrtc.org4e8eaba2012-08-20 14:29:52 +0000182 if (encoder.codecType != video_codec_internal.codecType) {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000183 new_rtp_stream = true;
184 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000185
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000186 ViEInputManagerScoped is(*(shared_data_->input_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000187
188 // Stop the media flow while reconfiguring.
189 vie_encoder->Pause();
190
mflodman@webrtc.org3ba883f2013-06-07 13:57:57 +0000191 if (vie_encoder->SetEncoder(video_codec_internal) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000192 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000193 return -1;
194 }
195
mflodman@webrtc.org9c0aedc2012-01-03 13:46:49 +0000196 // Give the channel(s) the new information.
197 ChannelList channels;
198 cs.ChannelsUsingViEEncoder(video_channel, &channels);
199 for (ChannelList::iterator it = channels.begin(); it != channels.end();
200 ++it) {
201 bool ret = true;
202 if ((*it)->SetSendCodec(video_codec_internal, new_rtp_stream) != 0) {
mflodman@webrtc.org9c0aedc2012-01-03 13:46:49 +0000203 ret = false;
204 }
205 if (!ret) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000206 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.org9c0aedc2012-01-03 13:46:49 +0000207 return -1;
208 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000209 }
210
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000211 // TODO(mflodman) Break out this part in GetLocalSsrcList().
212 // Update all SSRCs to ViEEncoder.
213 std::list<unsigned int> ssrcs;
214 if (video_codec_internal.numberOfSimulcastStreams == 0) {
215 unsigned int ssrc = 0;
216 if (vie_channel->GetLocalSSRC(0, &ssrc) != 0) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000217 LOG_F(LS_ERROR) << "Could not get ssrc.";
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000218 }
219 ssrcs.push_back(ssrc);
220 } else {
221 for (int idx = 0; idx < video_codec_internal.numberOfSimulcastStreams;
222 ++idx) {
223 unsigned int ssrc = 0;
224 if (vie_channel->GetLocalSSRC(idx, &ssrc) != 0) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000225 LOG_F(LS_ERROR) << "Could not get ssrc for stream " << idx;
mflodman@webrtc.orgd6ec3862012-10-25 11:30:29 +0000226 }
227 ssrcs.push_back(ssrc);
228 }
229 }
230 vie_encoder->SetSsrcs(ssrcs);
231 shared_data_->channel_manager()->UpdateSsrcs(video_channel, ssrcs);
232
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000233 // Update the protection mode, we might be switching NACK/FEC.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000234 vie_encoder->UpdateProtectionMethod(vie_encoder->nack_enabled());
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000235
236 // Get new best format for frame provider.
pbos@webrtc.org735a7c82013-08-05 09:03:03 +0000237 ViEFrameProviderBase* frame_provider = is.FrameProvider(vie_encoder);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000238 if (frame_provider) {
239 frame_provider->FrameCallbackChanged();
240 }
241 // Restart the media flow
242 if (new_rtp_stream) {
243 // Stream settings changed, make sure we get a key frame.
244 vie_encoder->SendKeyFrame();
245 }
246 vie_encoder->Restart();
247 return 0;
stefan@webrtc.org791eec72011-10-11 07:53:43 +0000248}
249
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000250int ViECodecImpl::GetSendCodec(const int video_channel,
251 VideoCodec& video_codec) const {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000252 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000253 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
254 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000255 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000256 return -1;
257 }
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000258 return vie_encoder->GetEncoder(&video_codec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000259}
260
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000261int ViECodecImpl::SetReceiveCodec(const int video_channel,
262 const VideoCodec& video_codec) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000263 LOG(LS_INFO) << "SetReceiveCodec for channel " << video_channel;
264 LOG(LS_INFO) << "Codec type " << video_codec.codecType
265 << ", payload type " << video_codec.plType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000267 if (CodecValid(video_codec) == false) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000268 shared_data_->SetLastError(kViECodecInvalidCodec);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000269 return -1;
270 }
271
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000272 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000273 ViEChannel* vie_channel = cs.Channel(video_channel);
274 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000275 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000276 return -1;
277 }
278
279 if (vie_channel->SetReceiveCodec(video_codec) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000280 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000281 return -1;
282 }
283 return 0;
284}
285
286int ViECodecImpl::GetReceiveCodec(const int video_channel,
287 VideoCodec& video_codec) const {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000288 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000289 ViEChannel* vie_channel = cs.Channel(video_channel);
290 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000291 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000292 return -1;
293 }
294
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000295 if (vie_channel->GetReceiveCodec(&video_codec) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000296 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000297 return -1;
298 }
299 return 0;
300}
301
302int ViECodecImpl::GetCodecConfigParameters(
303 const int video_channel,
304 unsigned char config_parameters[kConfigParameterSize],
305 unsigned char& config_parameters_size) const {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000306 LOG(LS_INFO) << "GetCodecConfigParameters " << video_channel;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000307
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000308 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000309 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
310 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000311 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000312 return -1;
313 }
314
315 if (vie_encoder->GetCodecConfigParameters(config_parameters,
316 config_parameters_size) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000317 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000318 return -1;
319 }
320 return 0;
321}
322
323int ViECodecImpl::SetImageScaleStatus(const int video_channel,
324 const bool enable) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000325 LOG(LS_INFO) << "SetImageScaleStates for channel " << video_channel
326 << ", enable: " << enable;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000327
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000328 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000329 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
330 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000331 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000332 return -1;
333 }
334
335 if (vie_encoder->ScaleInputImage(enable) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000336 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000337 return -1;
338 }
339 return 0;
340}
341
342int ViECodecImpl::GetSendCodecStastistics(const int video_channel,
343 unsigned int& key_frames,
344 unsigned int& delta_frames) const {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000345 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000346 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
347 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000348 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000349 return -1;
350 }
351
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000352 if (vie_encoder->SendCodecStatistics(&key_frames, &delta_frames) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000353 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000354 return -1;
355 }
356 return 0;
357}
358
359int ViECodecImpl::GetReceiveCodecStastistics(const int video_channel,
360 unsigned int& key_frames,
361 unsigned int& delta_frames) const {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000362 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000363 ViEChannel* vie_channel = cs.Channel(video_channel);
364 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000365 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000366 return -1;
367 }
mflodman@webrtc.orgf5e99db2012-06-27 09:49:37 +0000368 if (vie_channel->ReceiveCodecStatistics(&key_frames, &delta_frames) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000369 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000370 return -1;
371 }
372 return 0;
373}
374
mflodman@webrtc.org4aee6b62012-12-14 14:02:10 +0000375int ViECodecImpl::GetReceiveSideDelay(const int video_channel,
376 int* delay_ms) const {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000377 assert(delay_ms != NULL);
mflodman@webrtc.org4aee6b62012-12-14 14:02:10 +0000378
379 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
380 ViEChannel* vie_channel = cs.Channel(video_channel);
381 if (!vie_channel) {
mflodman@webrtc.org4aee6b62012-12-14 14:02:10 +0000382 shared_data_->SetLastError(kViECodecInvalidChannelId);
383 return -1;
384 }
385 *delay_ms = vie_channel->ReceiveDelay();
386 if (*delay_ms < 0) {
387 return -1;
388 }
389 return 0;
390}
391
392
stefan@webrtc.org439be292012-02-16 14:45:37 +0000393int ViECodecImpl::GetCodecTargetBitrate(const int video_channel,
394 unsigned int* bitrate) const {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000395 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
396 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
397 if (!vie_encoder) {
stefan@webrtc.org439be292012-02-16 14:45:37 +0000398 shared_data_->SetLastError(kViECodecInvalidChannelId);
399 return -1;
400 }
pbos@webrtc.orgb238d122013-04-09 13:41:51 +0000401 return vie_encoder->CodecTargetBitrate(static_cast<uint32_t*>(bitrate));
stefan@webrtc.org439be292012-02-16 14:45:37 +0000402}
403
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000404unsigned int ViECodecImpl::GetDiscardedPackets(const int video_channel) const {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000405 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000406 ViEChannel* vie_channel = cs.Channel(video_channel);
407 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000408 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000409 return -1;
410 }
411 return vie_channel->DiscardedPackets();
412}
413
414int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int video_channel,
415 const bool enable) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000416 LOG(LS_INFO) << "SetKeyFrameRequestCallbackStatus for " << video_channel
417 << ", enacle " << enable;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000418
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000419 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000420 ViEChannel* vie_channel = cs.Channel(video_channel);
421 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000422 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000423 return -1;
424 }
425 if (vie_channel->EnableKeyFrameRequestCallback(enable) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000426 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000427 return -1;
428 }
429 return 0;
430}
431
432int ViECodecImpl::SetSignalKeyPacketLossStatus(const int video_channel,
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 const bool enable,
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000434 const bool only_key_frames) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000435 LOG(LS_INFO) << "SetSignalKeyPacketLossStatus for " << video_channel
436 << "enable, " << enable
437 << ", only key frames " << only_key_frames;
niklase@google.com470e71d2011-07-07 08:21:25 +0000438
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000439 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000440 ViEChannel* vie_channel = cs.Channel(video_channel);
441 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000442 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000443 return -1;
444 }
445 if (vie_channel->SetSignalPacketLossStatus(enable, only_key_frames) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000446 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000447 return -1;
448 }
449 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000450}
451
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000452int ViECodecImpl::RegisterEncoderObserver(const int video_channel,
453 ViEEncoderObserver& observer) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000454 LOG(LS_INFO) << "RegisterEncoderObserver for channel " << video_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000456 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000457 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
458 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000459 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000460 return -1;
461 }
462 if (vie_encoder->RegisterCodecObserver(&observer) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000463 shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000464 return -1;
465 }
466 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467}
468
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000469int ViECodecImpl::DeregisterEncoderObserver(const int video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000470 LOG(LS_INFO) << "DeregisterEncoderObserver for channel " << video_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000471
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000472 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000473 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
474 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000475 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000476 return -1;
477 }
478 if (vie_encoder->RegisterCodecObserver(NULL) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000479 shared_data_->SetLastError(kViECodecObserverNotRegistered);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000480 return -1;
481 }
482 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000483}
484
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000485int ViECodecImpl::RegisterDecoderObserver(const int video_channel,
486 ViEDecoderObserver& observer) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000487 LOG(LS_INFO) << "RegisterDecoderObserver for channel " << video_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000488
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000489 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000490 ViEChannel* vie_channel = cs.Channel(video_channel);
491 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000492 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000493 return -1;
494 }
495 if (vie_channel->RegisterCodecObserver(&observer) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000496 shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000497 return -1;
498 }
499 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000500}
501
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000502int ViECodecImpl::DeregisterDecoderObserver(const int video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000503 LOG(LS_INFO) << "DeregisterDecodeObserver for channel " << video_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000505 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000506 ViEChannel* vie_channel = cs.Channel(video_channel);
507 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000508 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000509 return -1;
510 }
511 if (vie_channel->RegisterCodecObserver(NULL) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000512 shared_data_->SetLastError(kViECodecObserverNotRegistered);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000513 return -1;
514 }
515 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000516}
517
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000518int ViECodecImpl::SendKeyFrame(const int video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000519 LOG(LS_INFO) << "SendKeyFrame on channel " << video_channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000520
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000521 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000522 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
523 if (!vie_encoder) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000524 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000525 return -1;
526 }
527 if (vie_encoder->SendKeyFrame() != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000528 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000529 return -1;
530 }
531 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000532}
533
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000534int ViECodecImpl::WaitForFirstKeyFrame(const int video_channel,
535 const bool wait) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000536 LOG(LS_INFO) << "WaitForFirstKeyFrame for channel " << video_channel
537 << ", wait " << wait;
niklase@google.com470e71d2011-07-07 08:21:25 +0000538
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000539 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000540 ViEChannel* vie_channel = cs.Channel(video_channel);
541 if (!vie_channel) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000542 shared_data_->SetLastError(kViECodecInvalidChannelId);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000543 return -1;
544 }
545 if (vie_channel->WaitForKeyFrame(wait) != 0) {
mflodman@webrtc.orgb11424b2012-01-25 13:42:03 +0000546 shared_data_->SetLastError(kViECodecUnknownError);
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000547 return -1;
548 }
549 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000550}
551
mflodman@webrtc.org1c986e72013-06-26 09:12:49 +0000552int ViECodecImpl::StartDebugRecording(int video_channel,
553 const char* file_name_utf8) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000554 LOG(LS_INFO) << "StartDebugRecording for channel " << video_channel;
mflodman@webrtc.org1c986e72013-06-26 09:12:49 +0000555 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
556 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
557 if (!vie_encoder) {
mflodman@webrtc.org1c986e72013-06-26 09:12:49 +0000558 return -1;
559 }
560 return vie_encoder->StartDebugRecording(file_name_utf8);
561}
562
563int ViECodecImpl::StopDebugRecording(int video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000564 LOG(LS_INFO) << "StopDebugRecording for channel " << video_channel;
mflodman@webrtc.org1c986e72013-06-26 09:12:49 +0000565 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
566 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
567 if (!vie_encoder) {
mflodman@webrtc.org1c986e72013-06-26 09:12:49 +0000568 return -1;
569 }
570 return vie_encoder->StopDebugRecording();
571}
572
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000573void ViECodecImpl::SuspendBelowMinBitrate(int video_channel) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000574 LOG(LS_INFO) << "SuspendBelowMinBitrate for channel " << video_channel;
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +0000575 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
576 ViEEncoder* vie_encoder = cs.Encoder(video_channel);
577 if (!vie_encoder) {
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +0000578 return;
579 }
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000580 vie_encoder->SuspendBelowMinBitrate();
581 ViEChannel* vie_channel = cs.Channel(video_channel);
582 if (!vie_channel) {
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000583 return;
584 }
585 // Must enable pacing when enabling SuspendBelowMinBitrate. Otherwise, no
586 // padding will be sent when the video is suspended so the video will be
587 // unable to recover.
588 vie_channel->SetTransmissionSmoothingStatus(true);
henrik.lundin@webrtc.org7ea4f242013-10-02 13:34:26 +0000589}
590
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000591bool ViECodecImpl::GetSendSideDelay(int video_channel, int* avg_delay_ms,
592 int* max_delay_ms) const {
593 ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
594 ViEChannel* vie_channel = cs.Channel(video_channel);
595 if (!vie_channel) {
stefan@webrtc.org0a3c1472013-12-05 14:05:07 +0000596 shared_data_->SetLastError(kViECodecInvalidChannelId);
597 return false;
598 }
599 return vie_channel->GetSendSideDelay(avg_delay_ms, max_delay_ms);
600}
601
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000602bool ViECodecImpl::CodecValid(const VideoCodec& video_codec) {
603 // Check pl_name matches codec_type.
604 if (video_codec.codecType == kVideoCodecRED) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000605#if defined(WIN32)
mflodman@webrtc.org1fe2ada2011-12-21 12:23:15 +0000606 if (_strnicmp(video_codec.plName, "red", 3) == 0) {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000607#else
608 if (strncasecmp(video_codec.plName, "red", 3) == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000609#endif
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000610 // We only care about the type and name for red.
611 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000613 LOG_F(LS_ERROR) << "Invalid RED configuration.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000614 return false;
615 } else if (video_codec.codecType == kVideoCodecULPFEC) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000616#if defined(WIN32)
mflodman@webrtc.org1fe2ada2011-12-21 12:23:15 +0000617 if (_strnicmp(video_codec.plName, "ULPFEC", 6) == 0) {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000618#else
619 if (strncasecmp(video_codec.plName, "ULPFEC", 6) == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000620#endif
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000621 // We only care about the type and name for ULPFEC.
622 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 }
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000624 LOG_F(LS_ERROR) << "Invalid ULPFEC configuration.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000625 return false;
pwestin@webrtc.org56210572012-01-17 12:45:47 +0000626 } else if ((video_codec.codecType == kVideoCodecVP8 &&
pbos@webrtc.org8911ce42013-03-18 16:39:03 +0000627 strncmp(video_codec.plName, "VP8", 4) == 0) ||
628 (video_codec.codecType == kVideoCodecI420 &&
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +0000629 strncmp(video_codec.plName, "I420", 4) == 0)) {
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000630 // OK.
pbos@webrtc.orgb5bf54c2013-04-05 13:27:38 +0000631 } else if (video_codec.codecType != kVideoCodecGeneric) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000632 LOG(LS_ERROR) << "Codec type and name mismatch.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000633 return false;
634 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000635
braveyao@webrtc.org49273ff2013-01-14 01:52:26 +0000636 if (video_codec.plType == 0 || video_codec.plType > 127) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000637 LOG(LS_ERROR) << "Invalif payload type: " << video_codec.plType;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000638 return false;
639 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000640
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000641 if (video_codec.width > kViEMaxCodecWidth ||
642 video_codec.height > kViEMaxCodecHeight) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000643 LOG(LS_ERROR) << "Invalid codec resolution " << video_codec.width
644 << " x " << video_codec.height;
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000645 return false;
646 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000647
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000648 if (video_codec.startBitrate < kViEMinCodecBitrate) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000649 LOG(LS_ERROR) << "Invalid start bitrate.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000650 return false;
651 }
652 if (video_codec.minBitrate < kViEMinCodecBitrate) {
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000653 LOG(LS_ERROR) << "Invalid min bitrate.";
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000654 return false;
655 }
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000656 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000657}
mflodman@webrtc.orgc12686c2011-12-21 09:29:28 +0000658
659} // namespace webrtc