Home | History | Annotate | Download | only in video_engine
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      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 
     11 #include "webrtc/video_engine/vie_codec_impl.h"
     12 
     13 #include <list>
     14 
     15 #include "webrtc/engine_configurations.h"
     16 #include "webrtc/modules/video_coding/main/interface/video_coding.h"
     17 #include "webrtc/system_wrappers/interface/logging.h"
     18 #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"
     27 
     28 namespace webrtc {
     29 
     30 static void LogCodec(const VideoCodec& codec) {
     31   LOG(LS_INFO) << "CodecType " << codec.codecType
     32                << ", pl_type " << static_cast<int>(codec.plType)
     33                << ", resolution " << codec.width
     34                << " x " << codec.height
     35                << ", start br " << codec.startBitrate
     36                << ", min br " << codec.minBitrate
     37                << ", max br " << codec.maxBitrate
     38                << ", max fps " << static_cast<int>(codec.maxFramerate)
     39                << ", max qp " << codec.qpMax
     40                << ", number of streams "
     41                << static_cast<int>(codec.numberOfSimulcastStreams);
     42   if (codec.codecType == kVideoCodecVP8) {
     43     LOG(LS_INFO) << "VP8 specific settings";
     44     LOG(LS_INFO) << "pictureLossIndicationOn "
     45                  << 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
     52                  << ", numberOfTemporalLayers "
     53                  << static_cast<int>(
     54                      codec.codecSpecific.VP8.numberOfTemporalLayers)
     55                  << ", 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 "
     61                    << static_cast<int>(
     62                        codec.simulcastStream[idx].numberOfTemporalLayers)
     63                    << ", 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;
     71     }
     72   }
     73 }
     74 
     75 
     76 ViECodec* ViECodec::GetInterface(VideoEngine* video_engine) {
     77 #ifdef WEBRTC_VIDEO_ENGINE_CODEC_API
     78   if (!video_engine) {
     79     return NULL;
     80   }
     81   VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine);
     82   ViECodecImpl* vie_codec_impl = vie_impl;
     83   // Increase ref count.
     84   (*vie_codec_impl)++;
     85   return vie_codec_impl;
     86 #else
     87   return NULL;
     88 #endif
     89 }
     90 
     91 int ViECodecImpl::Release() {
     92   LOG(LS_INFO) << "ViECodec::Release.";
     93   // Decrease ref count.
     94   (*this)--;
     95 
     96   int32_t ref_count = GetCount();
     97   if (ref_count < 0) {
     98     LOG(LS_WARNING) << "ViECodec released too many times.";
     99     shared_data_->SetLastError(kViEAPIDoesNotExist);
    100     return -1;
    101   }
    102   return ref_count;
    103 }
    104 
    105 ViECodecImpl::ViECodecImpl(ViESharedData* shared_data)
    106     : shared_data_(shared_data) {
    107 }
    108 
    109 ViECodecImpl::~ViECodecImpl() {
    110 }
    111 
    112 int ViECodecImpl::NumberOfCodecs() const {
    113   // +2 because of FEC(RED and ULPFEC)
    114   return static_cast<int>((VideoCodingModule::NumberOfCodecs() + 2));
    115 }
    116 
    117 int ViECodecImpl::GetCodec(const unsigned char list_number,
    118                            VideoCodec& video_codec) const {
    119   if (list_number == VideoCodingModule::NumberOfCodecs()) {
    120     memset(&video_codec, 0, sizeof(VideoCodec));
    121     strcpy(video_codec.plName, "red");
    122     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));
    126     strcpy(video_codec.plName, "ulpfec");
    127     video_codec.codecType = kVideoCodecULPFEC;
    128     video_codec.plType = VCM_ULPFEC_PAYLOAD_TYPE;
    129   } else if (VideoCodingModule::Codec(list_number, &video_codec) != VCM_OK) {
    130     shared_data_->SetLastError(kViECodecInvalidArgument);
    131     return -1;
    132   }
    133   return 0;
    134 }
    135 
    136 int ViECodecImpl::SetSendCodec(const int video_channel,
    137                                const VideoCodec& video_codec) {
    138   LOG(LS_INFO) << "SetSendCodec for channel " << video_channel;
    139   LogCodec(video_codec);
    140   if (!CodecValid(video_codec)) {
    141     // Error logged.
    142     shared_data_->SetLastError(kViECodecInvalidCodec);
    143     return -1;
    144   }
    145 
    146   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    147   ViEChannel* vie_channel = cs.Channel(video_channel);
    148   if (!vie_channel) {
    149     shared_data_->SetLastError(kViECodecInvalidChannelId);
    150     return -1;
    151   }
    152 
    153   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    154   assert(vie_encoder);
    155   if (vie_encoder->Owner() != video_channel) {
    156     LOG_F(LS_ERROR) << "Receive only channel.";
    157     shared_data_->SetLastError(kViECodecReceiveOnlyChannel);
    158     return -1;
    159   }
    160   // 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;
    169     LOG(LS_INFO) << "New max bitrate set " << video_codec_internal.maxBitrate;
    170   }
    171 
    172   if (video_codec_internal.startBitrate < video_codec_internal.minBitrate) {
    173     video_codec_internal.startBitrate = video_codec_internal.minBitrate;
    174   }
    175   if (video_codec_internal.startBitrate > video_codec_internal.maxBitrate) {
    176     video_codec_internal.startBitrate = video_codec_internal.maxBitrate;
    177   }
    178 
    179   VideoCodec encoder;
    180   vie_encoder->GetEncoder(&encoder);
    181 
    182   // Make sure to generate a new SSRC if the codec type and/or resolution has
    183   // changed. This won't have any effect if the user has set an SSRC.
    184   bool new_rtp_stream = false;
    185   if (encoder.codecType != video_codec_internal.codecType) {
    186     new_rtp_stream = true;
    187   }
    188 
    189   ViEInputManagerScoped is(*(shared_data_->input_manager()));
    190 
    191   // Stop the media flow while reconfiguring.
    192   vie_encoder->Pause();
    193 
    194   if (vie_encoder->SetEncoder(video_codec_internal) != 0) {
    195     shared_data_->SetLastError(kViECodecUnknownError);
    196     return -1;
    197   }
    198 
    199   // Give the channel(s) the new information.
    200   ChannelList channels;
    201   cs.ChannelsUsingViEEncoder(video_channel, &channels);
    202   for (ChannelList::iterator it = channels.begin(); it != channels.end();
    203        ++it) {
    204     bool ret = true;
    205     if ((*it)->SetSendCodec(video_codec_internal, new_rtp_stream) != 0) {
    206       ret = false;
    207     }
    208     if (!ret) {
    209       shared_data_->SetLastError(kViECodecUnknownError);
    210       return -1;
    211     }
    212   }
    213 
    214   // TODO(mflodman) Break out this part in GetLocalSsrcList().
    215   // Update all SSRCs to ViEEncoder.
    216   std::list<unsigned int> ssrcs;
    217   if (video_codec_internal.numberOfSimulcastStreams == 0) {
    218     unsigned int ssrc = 0;
    219     if (vie_channel->GetLocalSSRC(0, &ssrc) != 0) {
    220       LOG_F(LS_ERROR) << "Could not get ssrc.";
    221     }
    222     ssrcs.push_back(ssrc);
    223   } else {
    224     for (int idx = 0; idx < video_codec_internal.numberOfSimulcastStreams;
    225          ++idx) {
    226       unsigned int ssrc = 0;
    227       if (vie_channel->GetLocalSSRC(idx, &ssrc) != 0) {
    228         LOG_F(LS_ERROR) << "Could not get ssrc for stream " << idx;
    229       }
    230       ssrcs.push_back(ssrc);
    231     }
    232   }
    233   vie_encoder->SetSsrcs(ssrcs);
    234   shared_data_->channel_manager()->UpdateSsrcs(video_channel, ssrcs);
    235 
    236   // Update the protection mode, we might be switching NACK/FEC.
    237   vie_encoder->UpdateProtectionMethod(vie_encoder->nack_enabled());
    238 
    239   // Get new best format for frame provider.
    240   ViEFrameProviderBase* frame_provider = is.FrameProvider(vie_encoder);
    241   if (frame_provider) {
    242     frame_provider->FrameCallbackChanged();
    243   }
    244   // Restart the media flow
    245   if (new_rtp_stream) {
    246     // Stream settings changed, make sure we get a key frame.
    247     vie_encoder->SendKeyFrame();
    248   }
    249   vie_encoder->Restart();
    250   return 0;
    251 }
    252 
    253 int ViECodecImpl::GetSendCodec(const int video_channel,
    254                                VideoCodec& video_codec) const {
    255   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    256   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    257   if (!vie_encoder) {
    258     shared_data_->SetLastError(kViECodecInvalidChannelId);
    259     return -1;
    260   }
    261   return vie_encoder->GetEncoder(&video_codec);
    262 }
    263 
    264 int ViECodecImpl::SetReceiveCodec(const int video_channel,
    265                                   const VideoCodec& video_codec) {
    266   LOG(LS_INFO) << "SetReceiveCodec for channel " << video_channel;
    267   LOG(LS_INFO) << "Codec type " << video_codec.codecType
    268                << ", payload type " << video_codec.plType;
    269 
    270   if (CodecValid(video_codec) == false) {
    271     shared_data_->SetLastError(kViECodecInvalidCodec);
    272     return -1;
    273   }
    274 
    275   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    276   ViEChannel* vie_channel = cs.Channel(video_channel);
    277   if (!vie_channel) {
    278     shared_data_->SetLastError(kViECodecInvalidChannelId);
    279     return -1;
    280   }
    281 
    282   if (vie_channel->SetReceiveCodec(video_codec) != 0) {
    283     shared_data_->SetLastError(kViECodecUnknownError);
    284     return -1;
    285   }
    286   return 0;
    287 }
    288 
    289 int ViECodecImpl::GetReceiveCodec(const int video_channel,
    290                                   VideoCodec& video_codec) const {
    291   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    292   ViEChannel* vie_channel = cs.Channel(video_channel);
    293   if (!vie_channel) {
    294     shared_data_->SetLastError(kViECodecInvalidChannelId);
    295     return -1;
    296   }
    297 
    298   if (vie_channel->GetReceiveCodec(&video_codec) != 0) {
    299     shared_data_->SetLastError(kViECodecUnknownError);
    300     return -1;
    301   }
    302   return 0;
    303 }
    304 
    305 int ViECodecImpl::GetCodecConfigParameters(
    306   const int video_channel,
    307   unsigned char config_parameters[kConfigParameterSize],
    308   unsigned char& config_parameters_size) const {
    309   LOG(LS_INFO) << "GetCodecConfigParameters " << video_channel;
    310 
    311   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    312   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    313   if (!vie_encoder) {
    314     shared_data_->SetLastError(kViECodecInvalidChannelId);
    315     return -1;
    316   }
    317 
    318   if (vie_encoder->GetCodecConfigParameters(config_parameters,
    319                                             config_parameters_size) != 0) {
    320     shared_data_->SetLastError(kViECodecUnknownError);
    321     return -1;
    322   }
    323   return 0;
    324 }
    325 
    326 int ViECodecImpl::SetImageScaleStatus(const int video_channel,
    327                                       const bool enable) {
    328   LOG(LS_INFO) << "SetImageScaleStates for channel " << video_channel
    329                << ", enable: " << enable;
    330 
    331   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    332   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    333   if (!vie_encoder) {
    334     shared_data_->SetLastError(kViECodecInvalidChannelId);
    335     return -1;
    336   }
    337 
    338   if (vie_encoder->ScaleInputImage(enable) != 0) {
    339     shared_data_->SetLastError(kViECodecUnknownError);
    340     return -1;
    341   }
    342   return 0;
    343 }
    344 
    345 int ViECodecImpl::GetSendCodecStastistics(const int video_channel,
    346                                           unsigned int& key_frames,
    347                                           unsigned int& delta_frames) const {
    348   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    349   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    350   if (!vie_encoder) {
    351     shared_data_->SetLastError(kViECodecInvalidChannelId);
    352     return -1;
    353   }
    354 
    355   if (vie_encoder->SendCodecStatistics(&key_frames, &delta_frames) != 0) {
    356     shared_data_->SetLastError(kViECodecUnknownError);
    357     return -1;
    358   }
    359   return 0;
    360 }
    361 
    362 int ViECodecImpl::GetReceiveCodecStastistics(const int video_channel,
    363                                              unsigned int& key_frames,
    364                                              unsigned int& delta_frames) const {
    365   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    366   ViEChannel* vie_channel = cs.Channel(video_channel);
    367   if (!vie_channel) {
    368     shared_data_->SetLastError(kViECodecInvalidChannelId);
    369     return -1;
    370   }
    371   if (vie_channel->ReceiveCodecStatistics(&key_frames, &delta_frames) != 0) {
    372     shared_data_->SetLastError(kViECodecUnknownError);
    373     return -1;
    374   }
    375   return 0;
    376 }
    377 
    378 int ViECodecImpl::GetReceiveSideDelay(const int video_channel,
    379                                       int* delay_ms) const {
    380   assert(delay_ms != NULL);
    381 
    382   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    383   ViEChannel* vie_channel = cs.Channel(video_channel);
    384   if (!vie_channel) {
    385     shared_data_->SetLastError(kViECodecInvalidChannelId);
    386     return -1;
    387   }
    388   *delay_ms = vie_channel->ReceiveDelay();
    389   if (*delay_ms < 0) {
    390     return -1;
    391   }
    392   return 0;
    393 }
    394 
    395 
    396 int ViECodecImpl::GetCodecTargetBitrate(const int video_channel,
    397                                         unsigned int* bitrate) const {
    398   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    399   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    400   if (!vie_encoder) {
    401     shared_data_->SetLastError(kViECodecInvalidChannelId);
    402     return -1;
    403   }
    404   return vie_encoder->CodecTargetBitrate(static_cast<uint32_t*>(bitrate));
    405 }
    406 
    407 unsigned int ViECodecImpl::GetDiscardedPackets(const int video_channel) const {
    408   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    409   ViEChannel* vie_channel = cs.Channel(video_channel);
    410   if (!vie_channel) {
    411     shared_data_->SetLastError(kViECodecInvalidChannelId);
    412     return -1;
    413   }
    414   return vie_channel->DiscardedPackets();
    415 }
    416 
    417 int ViECodecImpl::SetKeyFrameRequestCallbackStatus(const int video_channel,
    418                                                    const bool enable) {
    419   LOG(LS_INFO) << "SetKeyFrameRequestCallbackStatus for " << video_channel
    420                << ", enacle " << enable;
    421 
    422   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    423   ViEChannel* vie_channel = cs.Channel(video_channel);
    424   if (!vie_channel) {
    425     shared_data_->SetLastError(kViECodecInvalidChannelId);
    426     return -1;
    427   }
    428   if (vie_channel->EnableKeyFrameRequestCallback(enable) != 0) {
    429     shared_data_->SetLastError(kViECodecUnknownError);
    430     return -1;
    431   }
    432   return 0;
    433 }
    434 
    435 int ViECodecImpl::SetSignalKeyPacketLossStatus(const int video_channel,
    436                                                const bool enable,
    437                                                const bool only_key_frames) {
    438   LOG(LS_INFO) << "SetSignalKeyPacketLossStatus for " << video_channel
    439                << "enable, " << enable
    440                << ", only key frames " << only_key_frames;
    441 
    442   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    443   ViEChannel* vie_channel = cs.Channel(video_channel);
    444   if (!vie_channel) {
    445     shared_data_->SetLastError(kViECodecInvalidChannelId);
    446     return -1;
    447   }
    448   if (vie_channel->SetSignalPacketLossStatus(enable, only_key_frames) != 0) {
    449     shared_data_->SetLastError(kViECodecUnknownError);
    450     return -1;
    451   }
    452   return 0;
    453 }
    454 
    455 int ViECodecImpl::RegisterEncoderObserver(const int video_channel,
    456                                           ViEEncoderObserver& observer) {
    457   LOG(LS_INFO) << "RegisterEncoderObserver for channel " << video_channel;
    458 
    459   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    460   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    461   if (!vie_encoder) {
    462     shared_data_->SetLastError(kViECodecInvalidChannelId);
    463     return -1;
    464   }
    465   if (vie_encoder->RegisterCodecObserver(&observer) != 0) {
    466     shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
    467     return -1;
    468   }
    469   return 0;
    470 }
    471 
    472 int ViECodecImpl::DeregisterEncoderObserver(const int video_channel) {
    473   LOG(LS_INFO) << "DeregisterEncoderObserver for channel " << video_channel;
    474 
    475   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    476   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    477   if (!vie_encoder) {
    478     shared_data_->SetLastError(kViECodecInvalidChannelId);
    479     return -1;
    480   }
    481   if (vie_encoder->RegisterCodecObserver(NULL) != 0) {
    482     shared_data_->SetLastError(kViECodecObserverNotRegistered);
    483     return -1;
    484   }
    485   return 0;
    486 }
    487 
    488 int ViECodecImpl::RegisterDecoderObserver(const int video_channel,
    489                                           ViEDecoderObserver& observer) {
    490   LOG(LS_INFO) << "RegisterDecoderObserver for channel " << video_channel;
    491 
    492   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    493   ViEChannel* vie_channel = cs.Channel(video_channel);
    494   if (!vie_channel) {
    495     shared_data_->SetLastError(kViECodecInvalidChannelId);
    496     return -1;
    497   }
    498   if (vie_channel->RegisterCodecObserver(&observer) != 0) {
    499     shared_data_->SetLastError(kViECodecObserverAlreadyRegistered);
    500     return -1;
    501   }
    502   return 0;
    503 }
    504 
    505 int ViECodecImpl::DeregisterDecoderObserver(const int video_channel) {
    506   LOG(LS_INFO) << "DeregisterDecodeObserver for channel " << video_channel;
    507 
    508   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    509   ViEChannel* vie_channel = cs.Channel(video_channel);
    510   if (!vie_channel) {
    511     shared_data_->SetLastError(kViECodecInvalidChannelId);
    512     return -1;
    513   }
    514   if (vie_channel->RegisterCodecObserver(NULL) != 0) {
    515     shared_data_->SetLastError(kViECodecObserverNotRegistered);
    516     return -1;
    517   }
    518   return 0;
    519 }
    520 
    521 int ViECodecImpl::SendKeyFrame(const int video_channel) {
    522   LOG(LS_INFO) << "SendKeyFrame on channel " << video_channel;
    523 
    524   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    525   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    526   if (!vie_encoder) {
    527     shared_data_->SetLastError(kViECodecInvalidChannelId);
    528     return -1;
    529   }
    530   if (vie_encoder->SendKeyFrame() != 0) {
    531     shared_data_->SetLastError(kViECodecUnknownError);
    532     return -1;
    533   }
    534   return 0;
    535 }
    536 
    537 int ViECodecImpl::WaitForFirstKeyFrame(const int video_channel,
    538                                        const bool wait) {
    539   LOG(LS_INFO) << "WaitForFirstKeyFrame for channel " << video_channel
    540                << ", wait " << wait;
    541 
    542   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    543   ViEChannel* vie_channel = cs.Channel(video_channel);
    544   if (!vie_channel) {
    545     shared_data_->SetLastError(kViECodecInvalidChannelId);
    546     return -1;
    547   }
    548   if (vie_channel->WaitForKeyFrame(wait) != 0) {
    549     shared_data_->SetLastError(kViECodecUnknownError);
    550     return -1;
    551   }
    552   return 0;
    553 }
    554 
    555 int ViECodecImpl::StartDebugRecording(int video_channel,
    556                                       const char* file_name_utf8) {
    557   LOG(LS_INFO) << "StartDebugRecording for channel " << video_channel;
    558   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    559   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    560   if (!vie_encoder) {
    561     return -1;
    562   }
    563   return vie_encoder->StartDebugRecording(file_name_utf8);
    564 }
    565 
    566 int ViECodecImpl::StopDebugRecording(int video_channel) {
    567   LOG(LS_INFO) << "StopDebugRecording for channel " << video_channel;
    568   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    569   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    570   if (!vie_encoder) {
    571     return -1;
    572   }
    573   return vie_encoder->StopDebugRecording();
    574 }
    575 
    576 void ViECodecImpl::SuspendBelowMinBitrate(int video_channel) {
    577   LOG(LS_INFO) << "SuspendBelowMinBitrate for channel " << video_channel;
    578   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    579   ViEEncoder* vie_encoder = cs.Encoder(video_channel);
    580   if (!vie_encoder) {
    581     return;
    582   }
    583   vie_encoder->SuspendBelowMinBitrate();
    584   ViEChannel* vie_channel = cs.Channel(video_channel);
    585   if (!vie_channel) {
    586     return;
    587   }
    588   // Must enable pacing when enabling SuspendBelowMinBitrate. Otherwise, no
    589   // padding will be sent when the video is suspended so the video will be
    590   // unable to recover.
    591   vie_channel->SetTransmissionSmoothingStatus(true);
    592 }
    593 
    594 bool ViECodecImpl::GetSendSideDelay(int video_channel, int* avg_delay_ms,
    595                                    int* max_delay_ms) const {
    596   ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
    597   ViEChannel* vie_channel = cs.Channel(video_channel);
    598   if (!vie_channel) {
    599     shared_data_->SetLastError(kViECodecInvalidChannelId);
    600     return false;
    601   }
    602   return vie_channel->GetSendSideDelay(avg_delay_ms, max_delay_ms);
    603 }
    604 
    605 bool ViECodecImpl::CodecValid(const VideoCodec& video_codec) {
    606   // Check pl_name matches codec_type.
    607   if (video_codec.codecType == kVideoCodecRED) {
    608 #if defined(WIN32)
    609     if (_strnicmp(video_codec.plName, "red", 3) == 0) {
    610 #else
    611     if (strncasecmp(video_codec.plName, "red", 3) == 0) {
    612 #endif
    613       // We only care about the type and name for red.
    614       return true;
    615     }
    616     LOG_F(LS_ERROR) << "Invalid RED configuration.";
    617     return false;
    618   } else if (video_codec.codecType == kVideoCodecULPFEC) {
    619 #if defined(WIN32)
    620     if (_strnicmp(video_codec.plName, "ULPFEC", 6) == 0) {
    621 #else
    622     if (strncasecmp(video_codec.plName, "ULPFEC", 6) == 0) {
    623 #endif
    624       // We only care about the type and name for ULPFEC.
    625       return true;
    626     }
    627     LOG_F(LS_ERROR) << "Invalid ULPFEC configuration.";
    628     return false;
    629   } else if ((video_codec.codecType == kVideoCodecVP8 &&
    630               strncmp(video_codec.plName, "VP8", 4) == 0) ||
    631              (video_codec.codecType == kVideoCodecI420 &&
    632               strncmp(video_codec.plName, "I420", 4) == 0)) {
    633     // OK.
    634   } else if (video_codec.codecType != kVideoCodecGeneric) {
    635     LOG(LS_ERROR) << "Codec type and name mismatch.";
    636     return false;
    637   }
    638 
    639   if (video_codec.plType == 0 || video_codec.plType > 127) {
    640     LOG(LS_ERROR) << "Invalif payload type: " << video_codec.plType;
    641     return false;
    642   }
    643 
    644   if (video_codec.width > kViEMaxCodecWidth ||
    645       video_codec.height > kViEMaxCodecHeight) {
    646     LOG(LS_ERROR) << "Invalid codec resolution " << video_codec.width
    647                   << " x " << video_codec.height;
    648     return false;
    649   }
    650 
    651   if (video_codec.startBitrate < kViEMinCodecBitrate) {
    652     LOG(LS_ERROR) << "Invalid start bitrate.";
    653     return false;
    654   }
    655   if (video_codec.minBitrate < kViEMinCodecBitrate) {
    656     LOG(LS_ERROR) << "Invalid min bitrate.";
    657     return false;
    658   }
    659   return true;
    660 }
    661 
    662 }  // namespace webrtc
    663