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