• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VCMDecoderMapItem(VideoCodec * settings,int number_of_cores,bool require_key_frame)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 
VCMExtDecoderMapItem(VideoDecoder * external_decoder_instance,uint8_t payload_type,bool internal_render_timing)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 
VCMCodecDataBase()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 
~VCMCodecDataBase()62 VCMCodecDataBase::~VCMCodecDataBase() {
63   ResetSender();
64   ResetReceiver();
65 }
66 
NumberOfCodecs()67 int VCMCodecDataBase::NumberOfCodecs() {
68   return VCM_NUM_VIDEO_CODECS_AVAILABLE;
69 }
70 
Codec(int list_id,VideoCodec * settings)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 
Codec(VideoCodecType codec_type,VideoCodec * settings)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 
ResetSender()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.
SetSendCodec(const VideoCodec * send_codec,int number_of_cores,int max_payload_size,VCMEncodedFrameCallback * encoded_frame_callback)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 
SendCodec(VideoCodec * current_send_codec) const247 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 
SendCodec() const255 VideoCodecType VCMCodecDataBase::SendCodec() const {
256   if (!ptr_encoder_) {
257     return kVideoCodecUnknown;
258   }
259   return send_codec_.codecType;
260 }
261 
DeregisterExternalEncoder(uint8_t payload_type,bool * was_send_codec)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 
RegisterExternalEncoder(VideoEncoder * external_encoder,uint8_t payload_type,bool internal_source)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 
RequiresEncoderReset(const VideoCodec & new_send_codec)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 
GetEncoder()350 VCMGenericEncoder* VCMCodecDataBase::GetEncoder() {
351   return ptr_encoder_;
352 }
353 
SetPeriodicKeyFrames(bool enable)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 
ResetReceiver()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 
DeregisterExternalDecoder(uint8_t payload_type)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.
RegisterExternalDecoder(VideoDecoder * external_decoder,uint8_t payload_type,bool internal_render_timing)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 
DecoderRegistered() const417 bool VCMCodecDataBase::DecoderRegistered() const {
418   return !dec_map_.empty();
419 }
420 
RegisterReceiveCodec(const VideoCodec * receive_codec,int number_of_cores,bool require_key_frame)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 
DeregisterReceiveCodec(uint8_t payload_type)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 
ReceiveCodec(VideoCodec * current_receive_codec) const457 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 
ReceiveCodec() const466 VideoCodecType VCMCodecDataBase::ReceiveCodec() const {
467   if (!ptr_decoder_) {
468     return kVideoCodecUnknown;
469   }
470   return receive_codec_.codecType;
471 }
472 
GetDecoder(uint8_t payload_type,VCMDecodedFrameCallback * decoded_frame_callback)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 
CreateDecoderCopy() const501 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 
ReleaseDecoder(VCMGenericDecoder * decoder) const512 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 
CopyDecoder(const VCMGenericDecoder & decoder)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 
SupportsRenderScheduling() const535 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 
CreateAndInitDecoder(uint8_t payload_type,VideoCodec * new_codec,bool * external) const545 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 
CreateEncoder(const VideoCodecType type) const583 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 
DeleteEncoder()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 
CreateDecoder(VideoCodecType type) const611 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 
FindDecoderItem(uint8_t payload_type) const626 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 
FindExternalDecoderItem(uint8_t payload_type) const635 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