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