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 ¤t_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