Home | History | Annotate | Download | only in source
      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/modules/video_coding/main/source/codec_database.h"
     12 
     13 #include <assert.h>
     14 
     15 #include "webrtc/engine_configurations.h"
     16 #ifdef VIDEOCODEC_I420
     17 #include "webrtc/modules/video_coding/codecs/i420/main/interface/i420.h"
     18 #endif
     19 #ifdef VIDEOCODEC_VP8
     20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
     21 #endif
     22 #include "webrtc/modules/video_coding/main/source/internal_defines.h"
     23 #include "webrtc/system_wrappers/interface/logging.h"
     24 
     25 namespace webrtc {
     26 
     27 VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
     28                                      int number_of_cores,
     29                                      bool require_key_frame)
     30     : settings(settings),
     31       number_of_cores(number_of_cores),
     32       require_key_frame(require_key_frame) {
     33   assert(number_of_cores >= 0);
     34 }
     35 
     36 VCMExtDecoderMapItem::VCMExtDecoderMapItem(
     37     VideoDecoder* external_decoder_instance,
     38     uint8_t payload_type,
     39     bool internal_render_timing)
     40     : payload_type(payload_type),
     41       external_decoder_instance(external_decoder_instance),
     42       internal_render_timing(internal_render_timing) {
     43 }
     44 
     45 VCMCodecDataBase::VCMCodecDataBase()
     46     : number_of_cores_(0),
     47       max_payload_size_(kDefaultPayloadSize),
     48       periodic_key_frames_(false),
     49       pending_encoder_reset_(true),
     50       current_enc_is_external_(false),
     51       send_codec_(),
     52       receive_codec_(),
     53       external_payload_type_(0),
     54       external_encoder_(NULL),
     55       internal_source_(false),
     56       ptr_encoder_(NULL),
     57       ptr_decoder_(NULL),
     58       current_dec_is_external_(false),
     59       dec_map_(),
     60       dec_external_map_() {}
     61 
     62 VCMCodecDataBase::~VCMCodecDataBase() {
     63   ResetSender();
     64   ResetReceiver();
     65 }
     66 
     67 int VCMCodecDataBase::NumberOfCodecs() {
     68   return VCM_NUM_VIDEO_CODECS_AVAILABLE;
     69 }
     70 
     71 bool VCMCodecDataBase::Codec(int list_id,
     72                              VideoCodec* settings) {
     73   if (!settings) {
     74     return false;
     75   }
     76   if (list_id >= VCM_NUM_VIDEO_CODECS_AVAILABLE) {
     77     return false;
     78   }
     79   memset(settings, 0, sizeof(VideoCodec));
     80   switch (list_id) {
     81 #ifdef VIDEOCODEC_VP8
     82     case VCM_VP8_IDX: {
     83       strncpy(settings->plName, "VP8", 4);
     84       settings->codecType = kVideoCodecVP8;
     85       // 96 to 127 dynamic payload types for video codecs.
     86       settings->plType = VCM_VP8_PAYLOAD_TYPE;
     87       settings->startBitrate = 100;
     88       settings->minBitrate = VCM_MIN_BITRATE;
     89       settings->maxBitrate = 0;
     90       settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
     91       settings->width = VCM_DEFAULT_CODEC_WIDTH;
     92       settings->height = VCM_DEFAULT_CODEC_HEIGHT;
     93       settings->numberOfSimulcastStreams = 0;
     94       settings->qpMax = 56;
     95       settings->codecSpecific.VP8.resilience = kResilientStream;
     96       settings->codecSpecific.VP8.numberOfTemporalLayers = 1;
     97       settings->codecSpecific.VP8.denoisingOn = true;
     98       settings->codecSpecific.VP8.errorConcealmentOn = false;
     99       settings->codecSpecific.VP8.automaticResizeOn = false;
    100       settings->codecSpecific.VP8.frameDroppingOn = true;
    101       settings->codecSpecific.VP8.keyFrameInterval = 3000;
    102       return true;
    103     }
    104 #endif
    105 #ifdef VIDEOCODEC_I420
    106     case VCM_I420_IDX: {
    107       strncpy(settings->plName, "I420", 5);
    108       settings->codecType = kVideoCodecI420;
    109       // 96 to 127 dynamic payload types for video codecs.
    110       settings->plType = VCM_I420_PAYLOAD_TYPE;
    111       // Bitrate needed for this size and framerate.
    112       settings->startBitrate = 3 * VCM_DEFAULT_CODEC_WIDTH *
    113                                VCM_DEFAULT_CODEC_HEIGHT * 8 *
    114                                VCM_DEFAULT_FRAME_RATE / 1000 / 2;
    115       settings->maxBitrate = settings->startBitrate;
    116       settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
    117       settings->width = VCM_DEFAULT_CODEC_WIDTH;
    118       settings->height = VCM_DEFAULT_CODEC_HEIGHT;
    119       settings->minBitrate = VCM_MIN_BITRATE;
    120       settings->numberOfSimulcastStreams = 0;
    121       return true;
    122     }
    123 #endif
    124     default: {
    125       return false;
    126     }
    127   }
    128 }
    129 
    130 bool VCMCodecDataBase::Codec(VideoCodecType codec_type,
    131                              VideoCodec* settings) {
    132   for (int i = 0; i < VCMCodecDataBase::NumberOfCodecs(); i++) {
    133     const bool ret = VCMCodecDataBase::Codec(i, settings);
    134     if (!ret) {
    135       return false;
    136     }
    137     if (codec_type == settings->codecType) {
    138       return true;
    139     }
    140   }
    141   return false;
    142 }
    143 
    144 void VCMCodecDataBase::ResetSender() {
    145   DeleteEncoder();
    146   periodic_key_frames_ = false;
    147 }
    148 
    149 // Assuming only one registered encoder - since only one used, no need for more.
    150 bool VCMCodecDataBase::SetSendCodec(
    151     const VideoCodec* send_codec,
    152     int number_of_cores,
    153     int max_payload_size,
    154     VCMEncodedFrameCallback* encoded_frame_callback) {
    155   if (!send_codec) {
    156     return false;
    157   }
    158   if (max_payload_size <= 0) {
    159     max_payload_size = kDefaultPayloadSize;
    160   }
    161   if (number_of_cores <= 0) {
    162     return false;
    163   }
    164   if (send_codec->plType <= 0) {
    165     return false;
    166   }
    167   // Make sure the start bit rate is sane...
    168   if (send_codec->startBitrate > 1000000) {
    169     return false;
    170   }
    171   if (send_codec->codecType == kVideoCodecUnknown) {
    172     return false;
    173   }
    174   bool reset_required = pending_encoder_reset_;
    175   if (number_of_cores_ != number_of_cores) {
    176     number_of_cores_ = number_of_cores;
    177     reset_required = true;
    178   }
    179   if (max_payload_size_ != max_payload_size) {
    180     max_payload_size_ = max_payload_size;
    181     reset_required = true;
    182   }
    183 
    184   VideoCodec new_send_codec;
    185   memcpy(&new_send_codec, send_codec, sizeof(new_send_codec));
    186 
    187   if (new_send_codec.maxBitrate == 0) {
    188     // max is one bit per pixel
    189     new_send_codec.maxBitrate = (static_cast<int>(send_codec->height) *
    190         static_cast<int>(send_codec->width) *
    191         static_cast<int>(send_codec->maxFramerate)) / 1000;
    192     if (send_codec->startBitrate > new_send_codec.maxBitrate) {
    193       // But if the user tries to set a higher start bit rate we will
    194       // increase the max accordingly.
    195       new_send_codec.maxBitrate = send_codec->startBitrate;
    196     }
    197   }
    198 
    199   if (!reset_required) {
    200     reset_required = RequiresEncoderReset(new_send_codec);
    201   }
    202 
    203   memcpy(&send_codec_, &new_send_codec, sizeof(send_codec_));
    204 
    205   if (!reset_required) {
    206     encoded_frame_callback->SetPayloadType(send_codec->plType);
    207     if (ptr_encoder_->RegisterEncodeCallback(encoded_frame_callback) < 0) {
    208       return false;
    209     }
    210     return true;
    211   }
    212 
    213   // If encoder exists, will destroy it and create new one.
    214   DeleteEncoder();
    215   if (send_codec->plType == external_payload_type_) {
    216     // External encoder.
    217     ptr_encoder_ = new VCMGenericEncoder(*external_encoder_, internal_source_);
    218     current_enc_is_external_ = true;
    219   } else {
    220     ptr_encoder_ = CreateEncoder(send_codec->codecType);
    221     current_enc_is_external_ = false;
    222     if (!ptr_encoder_) {
    223       return false;
    224     }
    225   }
    226   encoded_frame_callback->SetPayloadType(send_codec->plType);
    227   if (ptr_encoder_->InitEncode(send_codec,
    228                                number_of_cores_,
    229                                max_payload_size_) < 0) {
    230     DeleteEncoder();
    231     return false;
    232   } else if (ptr_encoder_->RegisterEncodeCallback(encoded_frame_callback) < 0) {
    233     DeleteEncoder();
    234     return false;
    235   }
    236 
    237   // Intentionally don't check return value since the encoder registration
    238   // shouldn't fail because the codec doesn't support changing the periodic key
    239   // frame setting.
    240   ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_);
    241 
    242   pending_encoder_reset_ = false;
    243 
    244   return true;
    245 }
    246 
    247 bool VCMCodecDataBase::SendCodec(VideoCodec* current_send_codec) const {
    248   if (!ptr_encoder_) {
    249     return false;
    250   }
    251   memcpy(current_send_codec, &send_codec_, sizeof(VideoCodec));
    252   return true;
    253 }
    254 
    255 VideoCodecType VCMCodecDataBase::SendCodec() const {
    256   if (!ptr_encoder_) {
    257     return kVideoCodecUnknown;
    258   }
    259   return send_codec_.codecType;
    260 }
    261 
    262 bool VCMCodecDataBase::DeregisterExternalEncoder(
    263     uint8_t payload_type, bool* was_send_codec) {
    264   assert(was_send_codec);
    265   *was_send_codec = false;
    266   if (external_payload_type_ != payload_type) {
    267     return false;
    268   }
    269   if (send_codec_.plType == payload_type) {
    270     // De-register as send codec if needed.
    271     DeleteEncoder();
    272     memset(&send_codec_, 0, sizeof(VideoCodec));
    273     current_enc_is_external_ = false;
    274     *was_send_codec = true;
    275   }
    276   external_payload_type_ = 0;
    277   external_encoder_ = NULL;
    278   internal_source_ = false;
    279   return true;
    280 }
    281 
    282 void VCMCodecDataBase::RegisterExternalEncoder(
    283     VideoEncoder* external_encoder,
    284     uint8_t payload_type,
    285     bool internal_source) {
    286   // Since only one encoder can be used at a given time, only one external
    287   // encoder can be registered/used.
    288   external_encoder_ = external_encoder;
    289   external_payload_type_ = payload_type;
    290   internal_source_ = internal_source;
    291   pending_encoder_reset_ = true;
    292 }
    293 
    294 bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) {
    295   if (ptr_encoder_ == NULL) {
    296     return true;
    297   }
    298 
    299   // Does not check startBitrate or maxFramerate
    300   if (new_send_codec.codecType != send_codec_.codecType ||
    301       strcmp(new_send_codec.plName, send_codec_.plName) != 0 ||
    302       new_send_codec.plType != send_codec_.plType ||
    303       new_send_codec.width != send_codec_.width ||
    304       new_send_codec.height != send_codec_.height ||
    305       new_send_codec.maxBitrate != send_codec_.maxBitrate ||
    306       new_send_codec.minBitrate != send_codec_.minBitrate ||
    307       new_send_codec.qpMax != send_codec_.qpMax ||
    308       new_send_codec.numberOfSimulcastStreams !=
    309           send_codec_.numberOfSimulcastStreams ||
    310       new_send_codec.mode != send_codec_.mode ||
    311       new_send_codec.extra_options != send_codec_.extra_options) {
    312     return true;
    313   }
    314 
    315   switch (new_send_codec.codecType) {
    316     case kVideoCodecVP8:
    317       if (memcmp(&new_send_codec.codecSpecific.VP8,
    318                  &send_codec_.codecSpecific.VP8,
    319                  sizeof(new_send_codec.codecSpecific.VP8)) !=
    320           0) {
    321         return true;
    322       }
    323       break;
    324     case kVideoCodecGeneric:
    325       break;
    326     // Known codecs without payload-specifics
    327     case kVideoCodecI420:
    328     case kVideoCodecRED:
    329     case kVideoCodecULPFEC:
    330       break;
    331     // Unknown codec type, reset just to be sure.
    332     case kVideoCodecUnknown:
    333       return true;
    334   }
    335 
    336   if (new_send_codec.numberOfSimulcastStreams > 0) {
    337     for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams;
    338          ++i) {
    339       if (memcmp(&new_send_codec.simulcastStream[i],
    340                  &send_codec_.simulcastStream[i],
    341                  sizeof(new_send_codec.simulcastStream[i])) !=
    342           0) {
    343         return true;
    344       }
    345     }
    346   }
    347   return false;
    348 }
    349 
    350 VCMGenericEncoder* VCMCodecDataBase::GetEncoder() {
    351   return ptr_encoder_;
    352 }
    353 
    354 bool VCMCodecDataBase::SetPeriodicKeyFrames(bool enable) {
    355   periodic_key_frames_ = enable;
    356   if (ptr_encoder_) {
    357     return (ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_) == 0);
    358   }
    359   return true;
    360 }
    361 
    362 void VCMCodecDataBase::ResetReceiver() {
    363   ReleaseDecoder(ptr_decoder_);
    364   ptr_decoder_ = NULL;
    365   memset(&receive_codec_, 0, sizeof(VideoCodec));
    366   while (!dec_map_.empty()) {
    367     DecoderMap::iterator it = dec_map_.begin();
    368     delete (*it).second;
    369     dec_map_.erase(it);
    370   }
    371   while (!dec_external_map_.empty()) {
    372     ExternalDecoderMap::iterator external_it = dec_external_map_.begin();
    373     delete (*external_it).second;
    374     dec_external_map_.erase(external_it);
    375   }
    376   current_dec_is_external_ = false;
    377 }
    378 
    379 bool VCMCodecDataBase::DeregisterExternalDecoder(uint8_t payload_type) {
    380   ExternalDecoderMap::iterator it = dec_external_map_.find(payload_type);
    381   if (it == dec_external_map_.end()) {
    382     // Not found
    383     return false;
    384   }
    385   // We can't use payload_type to check if the decoder is currently in use,
    386   // because payload type may be out of date (e.g. before we decode the first
    387   // frame after RegisterReceiveCodec)
    388   if (ptr_decoder_ != NULL &&
    389       &ptr_decoder_->_decoder == (*it).second->external_decoder_instance) {
    390     // Release it if it was registered and in use.
    391     ReleaseDecoder(ptr_decoder_);
    392     ptr_decoder_ = NULL;
    393   }
    394   DeregisterReceiveCodec(payload_type);
    395   delete (*it).second;
    396   dec_external_map_.erase(it);
    397   return true;
    398 }
    399 
    400 // Add the external encoder object to the list of external decoders.
    401 // Won't be registered as a receive codec until RegisterReceiveCodec is called.
    402 bool VCMCodecDataBase::RegisterExternalDecoder(
    403     VideoDecoder* external_decoder,
    404     uint8_t payload_type,
    405     bool internal_render_timing) {
    406   // Check if payload value already exists, if so  - erase old and insert new.
    407   VCMExtDecoderMapItem* ext_decoder = new VCMExtDecoderMapItem(
    408       external_decoder, payload_type, internal_render_timing);
    409   if (!ext_decoder) {
    410     return false;
    411   }
    412   DeregisterExternalDecoder(payload_type);
    413   dec_external_map_[payload_type] = ext_decoder;
    414   return true;
    415 }
    416 
    417 bool VCMCodecDataBase::DecoderRegistered() const {
    418   return !dec_map_.empty();
    419 }
    420 
    421 bool VCMCodecDataBase::RegisterReceiveCodec(
    422     const VideoCodec* receive_codec,
    423     int number_of_cores,
    424     bool require_key_frame) {
    425   if (number_of_cores < 0) {
    426     return false;
    427   }
    428   // Check if payload value already exists, if so  - erase old and insert new.
    429   DeregisterReceiveCodec(receive_codec->plType);
    430   if (receive_codec->codecType == kVideoCodecUnknown) {
    431     return false;
    432   }
    433   VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
    434   dec_map_[receive_codec->plType] = new VCMDecoderMapItem(new_receive_codec,
    435                                                           number_of_cores,
    436                                                           require_key_frame);
    437   return true;
    438 }
    439 
    440 bool VCMCodecDataBase::DeregisterReceiveCodec(
    441     uint8_t payload_type) {
    442   DecoderMap::iterator it = dec_map_.find(payload_type);
    443   if (it == dec_map_.end()) {
    444     return false;
    445   }
    446   VCMDecoderMapItem* dec_item = (*it).second;
    447   delete dec_item;
    448   dec_map_.erase(it);
    449   if (receive_codec_.plType == payload_type) {
    450     // This codec is currently in use.
    451     memset(&receive_codec_, 0, sizeof(VideoCodec));
    452     current_dec_is_external_ = false;
    453   }
    454   return true;
    455 }
    456 
    457 bool VCMCodecDataBase::ReceiveCodec(VideoCodec* current_receive_codec) const {
    458   assert(current_receive_codec);
    459   if (!ptr_decoder_) {
    460     return false;
    461   }
    462   memcpy(current_receive_codec, &receive_codec_, sizeof(VideoCodec));
    463   return true;
    464 }
    465 
    466 VideoCodecType VCMCodecDataBase::ReceiveCodec() const {
    467   if (!ptr_decoder_) {
    468     return kVideoCodecUnknown;
    469   }
    470   return receive_codec_.codecType;
    471 }
    472 
    473 VCMGenericDecoder* VCMCodecDataBase::GetDecoder(
    474     uint8_t payload_type, VCMDecodedFrameCallback* decoded_frame_callback) {
    475   if (payload_type == receive_codec_.plType || payload_type == 0) {
    476     return ptr_decoder_;
    477   }
    478   // Check for exisitng decoder, if exists - delete.
    479   if (ptr_decoder_) {
    480     ReleaseDecoder(ptr_decoder_);
    481     ptr_decoder_ = NULL;
    482     memset(&receive_codec_, 0, sizeof(VideoCodec));
    483   }
    484   ptr_decoder_ = CreateAndInitDecoder(payload_type, &receive_codec_,
    485                                       &current_dec_is_external_);
    486   if (!ptr_decoder_) {
    487     return NULL;
    488   }
    489   VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
    490   if (callback) callback->IncomingCodecChanged(receive_codec_);
    491   if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback)
    492       < 0) {
    493     ReleaseDecoder(ptr_decoder_);
    494     ptr_decoder_ = NULL;
    495     memset(&receive_codec_, 0, sizeof(VideoCodec));
    496     return NULL;
    497   }
    498   return ptr_decoder_;
    499 }
    500 
    501 VCMGenericDecoder* VCMCodecDataBase::CreateDecoderCopy() const {
    502   if (!ptr_decoder_) {
    503     return NULL;
    504   }
    505   VideoDecoder* decoder_copy = ptr_decoder_->_decoder.Copy();
    506   if (!decoder_copy) {
    507     return NULL;
    508   }
    509   return new VCMGenericDecoder(*decoder_copy, ptr_decoder_->External());
    510 }
    511 
    512 void VCMCodecDataBase::ReleaseDecoder(VCMGenericDecoder* decoder) const {
    513   if (decoder) {
    514     assert(&decoder->_decoder);
    515     decoder->Release();
    516     if (!decoder->External()) {
    517       delete &decoder->_decoder;
    518     }
    519     delete decoder;
    520   }
    521 }
    522 
    523 void VCMCodecDataBase::CopyDecoder(const VCMGenericDecoder& decoder) {
    524   VideoDecoder* decoder_copy = decoder._decoder.Copy();
    525   if (decoder_copy) {
    526     VCMDecodedFrameCallback* cb = ptr_decoder_->_callback;
    527     ReleaseDecoder(ptr_decoder_);
    528     ptr_decoder_ = new VCMGenericDecoder(*decoder_copy, decoder.External());
    529     if (cb && ptr_decoder_->RegisterDecodeCompleteCallback(cb)) {
    530       assert(false);
    531     }
    532   }
    533 }
    534 
    535 bool VCMCodecDataBase::SupportsRenderScheduling() const {
    536   bool render_timing = true;
    537   if (current_dec_is_external_) {
    538     const VCMExtDecoderMapItem* ext_item = FindExternalDecoderItem(
    539         receive_codec_.plType);
    540     render_timing = ext_item->internal_render_timing;
    541   }
    542   return render_timing;
    543 }
    544 
    545 VCMGenericDecoder* VCMCodecDataBase::CreateAndInitDecoder(
    546     uint8_t payload_type,
    547     VideoCodec* new_codec,
    548     bool* external) const {
    549   assert(external);
    550   assert(new_codec);
    551   const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
    552   if (!decoder_item) {
    553     LOG(LS_ERROR) << "Can't find a decoder associated with payload type: "
    554                   << payload_type;
    555     return NULL;
    556   }
    557   VCMGenericDecoder* ptr_decoder = NULL;
    558   const VCMExtDecoderMapItem* external_dec_item = FindExternalDecoderItem(
    559                                               payload_type);
    560   if (external_dec_item) {
    561     // External codec.
    562     ptr_decoder = new VCMGenericDecoder(
    563         *external_dec_item->external_decoder_instance, true);
    564     *external = true;
    565   } else {
    566     // Create decoder.
    567     ptr_decoder = CreateDecoder(decoder_item->settings->codecType);
    568     *external = false;
    569   }
    570   if (!ptr_decoder) {
    571     return NULL;
    572   }
    573 
    574   if (ptr_decoder->InitDecode(decoder_item->settings.get(),
    575                               decoder_item->number_of_cores) < 0) {
    576     ReleaseDecoder(ptr_decoder);
    577     return NULL;
    578   }
    579   memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
    580   return ptr_decoder;
    581 }
    582 
    583 VCMGenericEncoder* VCMCodecDataBase::CreateEncoder(
    584   const VideoCodecType type) const {
    585   switch (type) {
    586 #ifdef VIDEOCODEC_VP8
    587     case kVideoCodecVP8:
    588       return new VCMGenericEncoder(*(VP8Encoder::Create()));
    589 #endif
    590 #ifdef VIDEOCODEC_I420
    591     case kVideoCodecI420:
    592       return new VCMGenericEncoder(*(new I420Encoder));
    593 #endif
    594     default:
    595       LOG(LS_WARNING) << "No internal encoder of this type exists.";
    596       return NULL;
    597   }
    598 }
    599 
    600 void VCMCodecDataBase::DeleteEncoder() {
    601   if (ptr_encoder_) {
    602     ptr_encoder_->Release();
    603     if (!current_enc_is_external_) {
    604       delete &ptr_encoder_->_encoder;
    605     }
    606     delete ptr_encoder_;
    607     ptr_encoder_ = NULL;
    608   }
    609 }
    610 
    611 VCMGenericDecoder* VCMCodecDataBase::CreateDecoder(VideoCodecType type) const {
    612   switch (type) {
    613 #ifdef VIDEOCODEC_VP8
    614     case kVideoCodecVP8:
    615       return new VCMGenericDecoder(*(VP8Decoder::Create()));
    616 #endif
    617 #ifdef VIDEOCODEC_I420
    618     case kVideoCodecI420:
    619       return new VCMGenericDecoder(*(new I420Decoder));
    620 #endif
    621     default:
    622       return NULL;
    623   }
    624 }
    625 
    626 const VCMDecoderMapItem* VCMCodecDataBase::FindDecoderItem(
    627     uint8_t payload_type) const {
    628   DecoderMap::const_iterator it = dec_map_.find(payload_type);
    629   if (it != dec_map_.end()) {
    630     return (*it).second;
    631   }
    632   return NULL;
    633 }
    634 
    635 const VCMExtDecoderMapItem* VCMCodecDataBase::FindExternalDecoderItem(
    636     uint8_t payload_type) const {
    637   ExternalDecoderMap::const_iterator it = dec_external_map_.find(payload_type);
    638   if (it != dec_external_map_.end()) {
    639     return (*it).second;
    640   }
    641   return NULL;
    642 }
    643 }  // namespace webrtc
    644