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