2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/video_coding/main/source/codec_database.h"
15 #include "webrtc/engine_configurations.h"
16 #ifdef VIDEOCODEC_I420
17 #include "webrtc/modules/video_coding/codecs/i420/main/interface/i420.h"
20 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
22 #include "webrtc/modules/video_coding/main/source/internal_defines.h"
23 #include "webrtc/system_wrappers/interface/trace.h"
27 VCMDecoderMapItem::VCMDecoderMapItem(VideoCodec* settings,
29 bool require_key_frame)
31 number_of_cores(number_of_cores),
32 require_key_frame(require_key_frame) {
33 assert(number_of_cores >= 0);
36 VCMExtDecoderMapItem::VCMExtDecoderMapItem(
37 VideoDecoder* external_decoder_instance,
39 bool internal_render_timing)
40 : payload_type(payload_type),
41 external_decoder_instance(external_decoder_instance),
42 internal_render_timing(internal_render_timing) {
45 VCMCodecDataBase::VCMCodecDataBase(int id)
48 max_payload_size_(kDefaultPayloadSize),
49 periodic_key_frames_(false),
50 pending_encoder_reset_(true),
51 current_enc_is_external_(false),
54 external_payload_type_(0),
55 external_encoder_(NULL),
56 internal_source_(false),
59 current_dec_is_external_(false),
64 VCMCodecDataBase::~VCMCodecDataBase() {
69 int VCMCodecDataBase::NumberOfCodecs() {
70 return VCM_NUM_VIDEO_CODECS_AVAILABLE;
73 bool VCMCodecDataBase::Codec(int list_id,
74 VideoCodec* settings) {
78 if (list_id >= VCM_NUM_VIDEO_CODECS_AVAILABLE) {
81 memset(settings, 0, sizeof(VideoCodec));
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;
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;
107 #ifdef VIDEOCODEC_I420
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;
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);
139 if (codec_type == settings->codecType) {
146 void VCMCodecDataBase::ResetSender() {
148 periodic_key_frames_ = false;
151 // Assuming only one registered encoder - since only one used, no need for more.
152 bool VCMCodecDataBase::SetSendCodec(
153 const VideoCodec* send_codec,
155 int max_payload_size,
156 VCMEncodedFrameCallback* encoded_frame_callback) {
160 if (max_payload_size <= 0) {
161 max_payload_size = kDefaultPayloadSize;
163 if (number_of_cores <= 0 || number_of_cores > 32) {
166 if (send_codec->plType <= 0) {
169 // Make sure the start bit rate is sane...
170 if (send_codec->startBitrate > 1000000) {
173 if (send_codec->codecType == kVideoCodecUnknown) {
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;
181 if (max_payload_size_ != max_payload_size) {
182 max_payload_size_ = max_payload_size;
183 reset_required = true;
186 VideoCodec new_send_codec;
187 memcpy(&new_send_codec, send_codec, sizeof(new_send_codec));
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;
201 if (!reset_required) {
202 reset_required = RequiresEncoderReset(new_send_codec);
205 memcpy(&send_codec_, &new_send_codec, sizeof(send_codec_));
207 if (!reset_required) {
208 encoded_frame_callback->SetPayloadType(send_codec->plType);
209 if (ptr_encoder_->RegisterEncodeCallback(encoded_frame_callback) < 0) {
215 // If encoder exists, will destroy it and create new one.
217 if (send_codec->plType == external_payload_type_) {
219 ptr_encoder_ = new VCMGenericEncoder(*external_encoder_, internal_source_);
220 current_enc_is_external_ = true;
222 ptr_encoder_ = CreateEncoder(send_codec->codecType);
223 current_enc_is_external_ = false;
225 encoded_frame_callback->SetPayloadType(send_codec->plType);
227 WEBRTC_TRACE(webrtc::kTraceError,
228 webrtc::kTraceVideoCoding,
230 "Failed to create encoder: %s.",
234 if (ptr_encoder_->InitEncode(send_codec,
236 max_payload_size_) < 0) {
237 WEBRTC_TRACE(webrtc::kTraceError,
238 webrtc::kTraceVideoCoding,
240 "Failed to initialize encoder: %s.",
244 } else if (ptr_encoder_->RegisterEncodeCallback(encoded_frame_callback) < 0) {
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
252 ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_);
254 pending_encoder_reset_ = false;
259 bool VCMCodecDataBase::SendCodec(VideoCodec* current_send_codec) const {
260 WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(id_),
265 memcpy(current_send_codec, &send_codec_, sizeof(VideoCodec));
269 VideoCodecType VCMCodecDataBase::SendCodec() const {
270 WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, VCMId(id_),
273 return kVideoCodecUnknown;
275 return send_codec_.codecType;
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) {
285 if (send_codec_.plType == payload_type) {
286 // De-register as send codec if needed.
288 memset(&send_codec_, 0, sizeof(VideoCodec));
289 current_enc_is_external_ = false;
290 *was_send_codec = true;
292 external_payload_type_ = 0;
293 external_encoder_ = NULL;
294 internal_source_ = false;
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;
310 bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) {
311 if (ptr_encoder_ == NULL) {
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) {
331 switch (new_send_codec.codecType) {
333 if (memcmp(&new_send_codec.codecSpecific.VP8,
334 &send_codec_.codecSpecific.VP8,
335 sizeof(new_send_codec.codecSpecific.VP8)) !=
340 case kVideoCodecGeneric:
342 // Known codecs without payload-specifics
343 case kVideoCodecI420:
345 case kVideoCodecULPFEC:
347 // Unknown codec type, reset just to be sure.
348 case kVideoCodecUnknown:
352 if (new_send_codec.numberOfSimulcastStreams > 0) {
353 for (unsigned char i = 0; i < new_send_codec.numberOfSimulcastStreams;
355 if (memcmp(&new_send_codec.simulcastStream[i],
356 &send_codec_.simulcastStream[i],
357 sizeof(new_send_codec.simulcastStream[i])) !=
366 VCMGenericEncoder* VCMCodecDataBase::GetEncoder() {
370 bool VCMCodecDataBase::SetPeriodicKeyFrames(bool enable) {
371 periodic_key_frames_ = enable;
373 return (ptr_encoder_->SetPeriodicKeyFrames(periodic_key_frames_) == 0);
378 void VCMCodecDataBase::ResetReceiver() {
379 ReleaseDecoder(ptr_decoder_);
381 memset(&receive_codec_, 0, sizeof(VideoCodec));
382 while (!dec_map_.empty()) {
383 DecoderMap::iterator it = dec_map_.begin();
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);
392 current_dec_is_external_ = false;
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()) {
401 if (receive_codec_.plType == payload_type) {
402 // Release it if it was registered and in use.
403 ReleaseDecoder(ptr_decoder_);
406 DeregisterReceiveCodec(payload_type);
408 dec_external_map_.erase(it);
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);
424 DeregisterExternalDecoder(payload_type);
425 dec_external_map_[payload_type] = ext_decoder;
429 bool VCMCodecDataBase::DecoderRegistered() const {
430 return !dec_map_.empty();
433 bool VCMCodecDataBase::RegisterReceiveCodec(
434 const VideoCodec* receive_codec,
436 bool require_key_frame) {
437 if (number_of_cores < 0) {
440 WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCoding, VCMId(id_),
441 "Codec: %s, Payload type %d, Height %d, Width %d, Bitrate %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) {
451 VideoCodec* new_receive_codec = new VideoCodec(*receive_codec);
452 dec_map_[receive_codec->plType] = new VCMDecoderMapItem(new_receive_codec,
458 bool VCMCodecDataBase::DeregisterReceiveCodec(
459 uint8_t payload_type) {
460 DecoderMap::iterator it = dec_map_.find(payload_type);
461 if (it == dec_map_.end()) {
464 VCMDecoderMapItem* dec_item = (*it).second;
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;
475 bool VCMCodecDataBase::ReceiveCodec(VideoCodec* current_receive_codec) const {
476 assert(current_receive_codec);
480 memcpy(current_receive_codec, &receive_codec_, sizeof(VideoCodec));
484 VideoCodecType VCMCodecDataBase::ReceiveCodec() const {
486 return kVideoCodecUnknown;
488 return receive_codec_.codecType;
491 VCMGenericDecoder* VCMCodecDataBase::GetDecoder(
492 uint8_t payload_type, VCMDecodedFrameCallback* decoded_frame_callback) {
493 if (payload_type == receive_codec_.plType || payload_type == 0) {
496 // Check for exisitng decoder, if exists - delete.
498 ReleaseDecoder(ptr_decoder_);
500 memset(&receive_codec_, 0, sizeof(VideoCodec));
502 ptr_decoder_ = CreateAndInitDecoder(payload_type, &receive_codec_,
503 ¤t_dec_is_external_);
507 VCMReceiveCallback* callback = decoded_frame_callback->UserReceiveCallback();
508 if (callback) callback->IncomingCodecChanged(receive_codec_);
509 if (ptr_decoder_->RegisterDecodeCompleteCallback(decoded_frame_callback)
511 ReleaseDecoder(ptr_decoder_);
513 memset(&receive_codec_, 0, sizeof(VideoCodec));
519 VCMGenericDecoder* VCMCodecDataBase::CreateDecoderCopy() const {
523 VideoDecoder* decoder_copy = ptr_decoder_->_decoder.Copy();
527 return new VCMGenericDecoder(*decoder_copy, id_, ptr_decoder_->External());
530 void VCMCodecDataBase::ReleaseDecoder(VCMGenericDecoder* decoder) const {
532 assert(&decoder->_decoder);
534 if (!decoder->External()) {
535 delete &decoder->_decoder;
541 void VCMCodecDataBase::CopyDecoder(const VCMGenericDecoder& decoder) {
542 VideoDecoder* decoder_copy = decoder._decoder.Copy();
544 VCMDecodedFrameCallback* cb = ptr_decoder_->_callback;
545 ReleaseDecoder(ptr_decoder_);
546 ptr_decoder_ = new VCMGenericDecoder(*decoder_copy, id_,
548 if (cb && ptr_decoder_->RegisterDecodeCompleteCallback(cb)) {
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;
561 return render_timing;
564 VCMGenericDecoder* VCMCodecDataBase::CreateAndInitDecoder(
565 uint8_t payload_type,
566 VideoCodec* new_codec,
567 bool* external) const {
570 const VCMDecoderMapItem* decoder_item = FindDecoderItem(payload_type);
572 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, VCMId(id_),
573 "Unknown payload type: %u", payload_type);
576 VCMGenericDecoder* ptr_decoder = NULL;
577 const VCMExtDecoderMapItem* external_dec_item = FindExternalDecoderItem(
579 if (external_dec_item) {
581 ptr_decoder = new VCMGenericDecoder(
582 *external_dec_item->external_decoder_instance, id_, true);
586 ptr_decoder = CreateDecoder(decoder_item->settings->codecType);
593 if (ptr_decoder->InitDecode(decoder_item->settings.get(),
594 decoder_item->number_of_cores) < 0) {
595 ReleaseDecoder(ptr_decoder);
598 memcpy(new_codec, decoder_item->settings.get(), sizeof(VideoCodec));
602 VCMGenericEncoder* VCMCodecDataBase::CreateEncoder(
603 const VideoCodecType type) const {
605 #ifdef VIDEOCODEC_VP8
607 return new VCMGenericEncoder(*(VP8Encoder::Create()));
609 #ifdef VIDEOCODEC_I420
610 case kVideoCodecI420:
611 return new VCMGenericEncoder(*(new I420Encoder));
618 void VCMCodecDataBase::DeleteEncoder() {
620 ptr_encoder_->Release();
621 if (!current_enc_is_external_) {
622 delete &ptr_encoder_->_encoder;
629 VCMGenericDecoder* VCMCodecDataBase::CreateDecoder(VideoCodecType type) const {
631 #ifdef VIDEOCODEC_VP8
633 return new VCMGenericDecoder(*(VP8Decoder::Create()), id_);
635 #ifdef VIDEOCODEC_I420
636 case kVideoCodecI420:
637 return new VCMGenericDecoder(*(new I420Decoder), id_);
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()) {
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()) {
661 } // namespace webrtc