1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/modules/video_coding/main/source/codec_database.h" 12 13 #include <assert.h> 14 15 #include "webrtc/engine_configurations.h" 16 #ifdef VIDEOCODEC_I420 17 #include "webrtc/modules/video_coding/codecs/i420/main/interface/i420.h" 18 #endif 19 #ifdef VIDEOCODEC_VP8 20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" 21 #endif 22 #include "webrtc/modules/video_coding/main/source/internal_defines.h" 23 #include "webrtc/system_wrappers/interface/logging.h" 24 25 namespace webrtc { 26 27 VideoCodecVP8 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 42 VideoCodecH264 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 57 VCMDecoderMapItem::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 66 VCMExtDecoderMapItem::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 75 VCMCodecDataBase::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 92 VCMCodecDataBase::~VCMCodecDataBase() { 93 ResetSender(); 94 ResetReceiver(); 95 } 96 97 int VCMCodecDataBase::NumberOfCodecs() { 98 return VCM_NUM_VIDEO_CODECS_AVAILABLE; 99 } 100 101 bool 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 172 bool 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 186 void 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. 192 bool 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 289 bool 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 297 VideoCodecType VCMCodecDataBase::SendCodec() const { 298 if (!ptr_encoder_) { 299 return kVideoCodecUnknown; 300 } 301 return send_codec_.codecType; 302 } 303 304 bool 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 324 void 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 336 bool 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 398 VCMGenericEncoder* VCMCodecDataBase::GetEncoder() { 399 return ptr_encoder_; 400 } 401 402 bool 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 410 void 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 427 bool 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. 450 bool 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 465 bool VCMCodecDataBase::DecoderRegistered() const { 466 return !dec_map_.empty(); 467 } 468 469 bool 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 488 bool 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 505 bool 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 514 VideoCodecType VCMCodecDataBase::ReceiveCodec() const { 515 if (!ptr_decoder_) { 516 return kVideoCodecUnknown; 517 } 518 return receive_codec_.codecType; 519 } 520 521 VCMGenericDecoder* 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 ¤t_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 549 VCMGenericDecoder* 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 560 void 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 571 void 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 583 bool 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 593 VCMGenericDecoder* 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 631 VCMGenericEncoder* 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 648 void 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 659 VCMGenericDecoder* 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 675 const 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 684 const 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