diff options
Diffstat (limited to 'tinyDAV/src/codecs/theora/tdav_codec_theora.c')
-rwxr-xr-x | tinyDAV/src/codecs/theora/tdav_codec_theora.c | 1394 |
1 files changed, 694 insertions, 700 deletions
diff --git a/tinyDAV/src/codecs/theora/tdav_codec_theora.c b/tinyDAV/src/codecs/theora/tdav_codec_theora.c index 01072c3..620d6ed 100755 --- a/tinyDAV/src/codecs/theora/tdav_codec_theora.c +++ b/tinyDAV/src/codecs/theora/tdav_codec_theora.c @@ -2,19 +2,19 @@ * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop <diopmamadou(at)doubango.org> -* +* * This file is part of Open Source Doubango Framework. * * DOUBANGO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. -* +* * DOUBANGO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. -* +* * You should have received a copy of the GNU General Public License * along with DOUBANGO. * @@ -55,64 +55,63 @@ #define THEORA_IDENT_HEADER_SIZE 42 /* 6.2 Identification Header Decode */ #define THEORA_CONF_SEND_COUNT 10 /* at 250ms, 500ms, 1000ms, .... */ -typedef struct tdav_codec_theora_s -{ - TMEDIA_DECLARE_CODEC_VIDEO; - - struct{ - uint8_t* ptr; - tsk_size_t size; - } rtp; - - // Encoder - struct{ - AVCodec* codec; - AVCodecContext* context; - AVFrame* picture; - void* buffer; - - uint64_t conf_last; - int conf_count; - tsk_bool_t force_idr; - int quality; - int rotation; - int32_t max_bw_kpbs; - } encoder; - - // decoder - struct{ - AVCodec* codec; - AVCodecContext* context; - AVFrame* picture; - - tsk_bool_t opened; - uint8_t conf_ident[3]; - tsk_buffer_t* conf_pkt; - - void* accumulator; - uint8_t ebit; - tsk_size_t accumulator_pos; - uint16_t last_seq; - } decoder; +typedef struct tdav_codec_theora_s { + TMEDIA_DECLARE_CODEC_VIDEO; + + struct { + uint8_t* ptr; + tsk_size_t size; + } rtp; + + // Encoder + struct { + AVCodec* codec; + AVCodecContext* context; + AVFrame* picture; + void* buffer; + + uint64_t conf_last; + int conf_count; + tsk_bool_t force_idr; + int quality; + int rotation; + int32_t max_bw_kpbs; + } encoder; + + // decoder + struct { + AVCodec* codec; + AVCodecContext* context; + AVFrame* picture; + + tsk_bool_t opened; + uint8_t conf_ident[3]; + tsk_buffer_t* conf_pkt; + + void* accumulator; + uint8_t ebit; + tsk_size_t accumulator_pos; + uint16_t last_seq; + } decoder; } tdav_codec_theora_t; /* 2.2. Payload Header filed 'F'*/ -typedef enum theora_frag_type_e{ - Not_Fragmented = 0, - Start_Fragment = 1, - Continuation_Fragment = 2, - End_Fragment = 3, +typedef enum theora_frag_type_e { + Not_Fragmented = 0, + Start_Fragment = 1, + Continuation_Fragment = 2, + End_Fragment = 3, } theora_frag_type_t; /* 2.2. Payload Header field 'TDT'*/ -typedef enum theora_datatype_e{ - Raw_Theora_payload = 0, - Theora_Packed_Configuration_payload = 1, - Legacy_Theora_Comment_payload = 2, - Reserved = 3, +typedef enum theora_datatype_e { + Raw_Theora_payload = 0, + Theora_Packed_Configuration_payload = 1, + Legacy_Theora_Comment_payload = 2, + Reserved = 3, } theora_datatype_t; @@ -130,399 +129,396 @@ static void tdav_codec_theora_encap(tdav_codec_theora_t* theora, const uint8_t* static int tdav_codec_theora_set(tmedia_codec_t* self, const tmedia_param_t* param) { - tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; - if(!self->opened){ - TSK_DEBUG_ERROR("Codec not opened"); - return -1; - } - if(param->value_type == tmedia_pvt_int32){ - if(tsk_striequals(param->key, "action")){ - tmedia_codec_action_t action = (tmedia_codec_action_t)TSK_TO_INT32((uint8_t*)param->value); - switch(action){ - case tmedia_codec_action_encode_idr: - { - theora->encoder.force_idr = tsk_true; - break; - } - case tmedia_codec_action_bw_down: - { - theora->encoder.quality = TSK_CLAMP(1, (theora->encoder.quality + 1), 31); - theora->encoder.context->global_quality = FF_QP2LAMBDA * theora->encoder.quality; - break; - } - case tmedia_codec_action_bw_up: - { - theora->encoder.quality = TSK_CLAMP(1, (theora->encoder.quality - 1), 31); - theora->encoder.context->global_quality = FF_QP2LAMBDA * theora->encoder.quality; - break; - } - } - } - // FIXME: not working as expected - /*else if(tsk_striequals(param->key, "rotation")){ - int rotation = *((int32_t*)param->value); - if(theora->encoder.rotation != rotation){ - if(self->opened){ - int ret; - theora->encoder.rotation = rotation; - if((ret = tdav_codec_theora_close_encoder(theora))){ - return ret; - } - if((ret = tdav_codec_theora_open_encoder(theora))){ - return ret; - } - } - } - return 0; - }*/ - } - return -1; + tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; + if(!self->opened) { + TSK_DEBUG_ERROR("Codec not opened"); + return -1; + } + if(param->value_type == tmedia_pvt_int32) { + if(tsk_striequals(param->key, "action")) { + tmedia_codec_action_t action = (tmedia_codec_action_t)TSK_TO_INT32((uint8_t*)param->value); + switch(action) { + case tmedia_codec_action_encode_idr: { + theora->encoder.force_idr = tsk_true; + break; + } + case tmedia_codec_action_bw_down: { + theora->encoder.quality = TSK_CLAMP(1, (theora->encoder.quality + 1), 31); + theora->encoder.context->global_quality = FF_QP2LAMBDA * theora->encoder.quality; + break; + } + case tmedia_codec_action_bw_up: { + theora->encoder.quality = TSK_CLAMP(1, (theora->encoder.quality - 1), 31); + theora->encoder.context->global_quality = FF_QP2LAMBDA * theora->encoder.quality; + break; + } + } + } + // FIXME: not working as expected + /*else if(tsk_striequals(param->key, "rotation")){ + int rotation = *((int32_t*)param->value); + if(theora->encoder.rotation != rotation){ + if(self->opened){ + int ret; + theora->encoder.rotation = rotation; + if((ret = tdav_codec_theora_close_encoder(theora))){ + return ret; + } + if((ret = tdav_codec_theora_open_encoder(theora))){ + return ret; + } + } + } + return 0; + }*/ + } + return -1; } int tdav_codec_theora_open(tmedia_codec_t* self) { - int ret; - - tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; - - if(!theora){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* the caller (base class) already checked that the codec is not opened */ - - - // Encoder - if((ret = tdav_codec_theora_open_encoder(theora))){ - return ret; - } - - // Decoder - if((ret = tdav_codec_theora_open_decoder(theora))){ - return ret; - } - - return 0; + int ret; + + tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; + + if(!theora) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + /* the caller (base class) already checked that the codec is not opened */ + + + // Encoder + if((ret = tdav_codec_theora_open_encoder(theora))) { + return ret; + } + + // Decoder + if((ret = tdav_codec_theora_open_decoder(theora))) { + return ret; + } + + return 0; } int tdav_codec_theora_close(tmedia_codec_t* self) { - tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; + tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; - if(!theora){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } + if(!theora) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } - /* the caller (base class) already checked that the codec is opened */ + /* the caller (base class) already checked that the codec is opened */ - - // Encoder - tdav_codec_theora_close_encoder(theora); - - // Decoder - tdav_codec_theora_close_decoder(theora); - return 0; + // Encoder + tdav_codec_theora_close_encoder(theora); + + // Decoder + tdav_codec_theora_close_decoder(theora); + + return 0; } //#include "tsk_time.h" tsk_size_t tdav_codec_theora_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) { - int ret; - int size; - - tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; - - if(!self || !in_data || !in_size || !out_data){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - // wrap yuv420 buffer - size = avpicture_fill((AVPicture *)theora->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, theora->encoder.context->width, theora->encoder.context->height); - if(size != in_size){ - /* guard */ - TSK_DEBUG_ERROR("Invalid size"); - return 0; - } - - // Encode data + int ret; + int size; + + tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; + + if(!self || !in_data || !in_size || !out_data) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + // wrap yuv420 buffer + size = avpicture_fill((AVPicture *)theora->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, theora->encoder.context->width, theora->encoder.context->height); + if(size != in_size) { + /* guard */ + TSK_DEBUG_ERROR("Invalid size"); + return 0; + } + + // Encode data #if LIBAVCODEC_VERSION_MAJOR <= 53 - theora->encoder.picture->pict_type = theora->encoder.force_idr ? FF_I_TYPE : 0; + theora->encoder.picture->pict_type = theora->encoder.force_idr ? FF_I_TYPE : 0; #else theora->encoder.picture->pict_type = theora->encoder.force_idr ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE; #endif - theora->encoder.picture->pts = AV_NOPTS_VALUE; - theora->encoder.picture->quality = theora->encoder.context->global_quality; - ret = avcodec_encode_video(theora->encoder.context, theora->encoder.buffer, size, theora->encoder.picture); - if(ret > 0){ - tdav_codec_theora_encap(theora, theora->encoder.buffer, (tsk_size_t)ret); - } - theora->encoder.force_idr = tsk_false; - - return 0; + theora->encoder.picture->pts = AV_NOPTS_VALUE; + theora->encoder.picture->quality = theora->encoder.context->global_quality; + ret = avcodec_encode_video(theora->encoder.context, theora->encoder.buffer, size, theora->encoder.picture); + if(ret > 0) { + tdav_codec_theora_encap(theora, theora->encoder.buffer, (tsk_size_t)ret); + } + theora->encoder.force_idr = tsk_false; + + return 0; } tsk_size_t tdav_codec_theora_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr) { - const uint8_t* pdata = in_data; - int pkts; - const uint8_t* pay_ptr; - tsk_size_t pay_size; - //tsk_size_t hdr_size; - tsk_size_t xsize, retsize = 0; - int got_picture_ptr; - int ret; - - tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; - const trtp_rtp_header_t* rtp_hdr = proto_hdr; - - if(!self || !in_data || (in_size<(THEORA_PAYLOAD_HEADER_SIZE + THEORA_PAYLOAD_LENGTH_SIZE)) || !out_data || !theora->decoder.context){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - /* Packet lost? */ - if(theora->decoder.last_seq != (rtp_hdr->seq_num - 1) && theora->decoder.last_seq){ - if(theora->decoder.last_seq == rtp_hdr->seq_num){ - // Could happen on some stupid emulators - //TSK_DEBUG_INFO("Packet duplicated, seq_num=%d", rtp_hdr->seq_num); - return 0; - } - TSK_DEBUG_INFO("Packet lost, seq_num=%d", rtp_hdr->seq_num); - } - theora->decoder.last_seq = rtp_hdr->seq_num; - - xsize = avpicture_get_size(theora->decoder.context->pix_fmt, theora->decoder.context->width, theora->decoder.context->height); - - /* 2.2. Payload Header - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Configuration Ident | F |TDT|# pkts.| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - /* 2.3. Payload Data - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Payload Length | Theora Data .. - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - pkts = (pdata[3] & 0x0F); - pay_ptr = (pdata + THEORA_PAYLOAD_HEADER_SIZE); - - do{ /* pkts=0 for fragmented packets */ - - pay_size = pay_ptr[0], pay_size<<=8, pay_size |= pay_ptr[1]; /* Big Endian read */ - pay_ptr += THEORA_PAYLOAD_LENGTH_SIZE; - /* check size validity */ - if((pay_ptr + pay_size)>(pdata + in_size)){ - TSK_DEBUG_ERROR("Too short"); - break; - } - - switch((pdata[3]>>4) & 0x03){ - case Raw_Theora_payload: - { /* ====== Theora data (2.2. Payload Header, 2.3. Payload Data) ====== */ - /* append buffer */ - if((int)(theora->decoder.accumulator_pos + pay_size) <= xsize){ - memcpy(&((uint8_t*)theora->decoder.accumulator)[theora->decoder.accumulator_pos], pay_ptr, pay_size); - theora->decoder.accumulator_pos += pay_size; - } - else{ - TSK_DEBUG_WARN("Buffer overflow"); - theora->decoder.accumulator_pos = 0; - break; - } - /* only take care if last packet (What about the RTP marker?) */ - if(((pdata[3]>>6) == Not_Fragmented || (pdata[3]>>6) == End_Fragment /*|| rtp_hdr->marker*/) && theora->decoder.opened){ - AVPacket packet; - /* Perform decoding */ - av_init_packet(&packet); - packet.size = (int)theora->decoder.accumulator_pos; - packet.data = theora->decoder.accumulator; - ret = avcodec_decode_video2(theora->decoder.context, theora->decoder.picture, &got_picture_ptr, &packet); - - if(ret < 0){ - TSK_DEBUG_WARN("Failed to decode the buffer with error code = %d", ret); - if(TMEDIA_CODEC_VIDEO(self)->in.callback){ - TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_error; - TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; - TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); - } - } - else if(got_picture_ptr){ - retsize = xsize; - TMEDIA_CODEC_VIDEO(theora)->in.width = theora->decoder.context->width; - TMEDIA_CODEC_VIDEO(theora)->in.height = theora->decoder.context->height; - - /* allocate buffer */ - if(*out_max_size <xsize){ - if((*out_data = tsk_realloc(*out_data, xsize))){ - *out_max_size = xsize; - } - else{ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - *out_max_size = 0; - return 0; - } - } - /* copy picture into a linear buffer */ - avpicture_layout((AVPicture *)theora->decoder.picture, theora->decoder.context->pix_fmt, (int)theora->decoder.context->width, (int)theora->decoder.context->height, - *out_data, (int)retsize); - } - /* in all cases: reset accumulator */ - theora->decoder.accumulator_pos = 0; - } - break; - } - case Theora_Packed_Configuration_payload: - {/* ====== Configuration packet (3.1.1. Packed Configuration) ====== */ - static uint8_t __theora_comment_hdr[] = {0x81, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61, - 0x00, 0x00, 0x00, 0x08, /* 4-byte length */ - 'd', 'o', 'u', 'b', 'a', 'n', 'g', 'o', /* UTF-8 encoded string */ - }; - - /* http://www.theora.org/doc/Theora.pdf - Chapter 6 - A Theora bitstream begins with three header packets. The header packets - are, in order, the identifcation header, the comment header, and the setup - header. All are required for decode compliance. An end-of-packet condition - encountered while decoding the identification or setup header packets renders - the stream undecodable. An end-of-packet condition encountered while decode - the comment header is a non-fatal error condition, and MAY be ignored by a - decoder. - - Decode continues according to HEADERTYPE. The identification header - is type 0x80, the comment header is type 0x81, and the setup header is type - 0x82. - */ - /*TSK_DEBUG_INFO("Theora_Packed_Configuration_payload");*/ - - if(!theora->decoder.opened /*|| (conf_ident changed)*/){ - if(!theora->decoder.conf_pkt){ - theora->decoder.conf_pkt = tsk_buffer_create(pay_ptr, pay_size); - } - else{ - tsk_buffer_append(theora->decoder.conf_pkt, pay_ptr, pay_size); - } - - if((pdata[3]>>6) == Not_Fragmented || (pdata[3]>>6) == End_Fragment || rtp_hdr->marker){ - if(theora->decoder.conf_pkt->size > THEORA_IDENT_HEADER_SIZE){ - const uint8_t* conf_ptr = theora->decoder.conf_pkt->data; - int setup_size = (int)theora->decoder.conf_pkt->size - THEORA_IDENT_HEADER_SIZE; - int extradata_size = (2 + THEORA_IDENT_HEADER_SIZE) + (2 + setup_size) + (2 + sizeof(__theora_comment_hdr)); - if(conf_ptr[0] == 0x80 && conf_ptr[THEORA_IDENT_HEADER_SIZE] == 0x82){ /* Do not check for 't'h'e'o'r'a' */ - /* save configration identification */ - memcpy(theora->decoder.conf_ident, &pdata[0], sizeof(theora->decoder.conf_ident)); - if(theora->decoder.context->extradata){ - TSK_FREE(theora->decoder.context->extradata); - } - if((theora->decoder.context->extradata = tsk_calloc(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE, 1))){ - int index = 0; - /* Because of endianess pb. do not use uint16_t or uint32_t */ - theora->decoder.context->extradata[index++] = 0x00; - theora->decoder.context->extradata[index++] = THEORA_IDENT_HEADER_SIZE; - memcpy(&theora->decoder.context->extradata[index], &conf_ptr[0], THEORA_IDENT_HEADER_SIZE); - index += THEORA_IDENT_HEADER_SIZE; - - theora->decoder.context->extradata[index++] = (setup_size >>8) & 0xFF; - theora->decoder.context->extradata[index++] = (setup_size & 0xFF); - memcpy(&theora->decoder.context->extradata[index], &conf_ptr[THEORA_IDENT_HEADER_SIZE], setup_size); - index+=setup_size; - - theora->decoder.context->extradata[index++] = 0x00; - theora->decoder.context->extradata[index++] = sizeof(__theora_comment_hdr);/* <0xFF */ - memcpy(&theora->decoder.context->extradata[index], __theora_comment_hdr, sizeof(__theora_comment_hdr)); - - theora->decoder.context->extradata_size = extradata_size; - - if((ret = avcodec_open(theora->decoder.context, theora->decoder.codec)) == 0){ - theora->decoder.opened = tsk_true; - } - else{ - TSK_DEBUG_ERROR("Failed to open theora decoder %d", ret); - TSK_FREE(theora->decoder.context->extradata); - theora->decoder.context->extradata_size = 0; - } - } - } - else{ - TSK_DEBUG_ERROR("Invalid configuration packet"); - } - } - else{ - TSK_DEBUG_ERROR("Too short"); - } - tsk_buffer_cleanup(theora->decoder.conf_pkt); - } - } - break; - } - case Legacy_Theora_Comment_payload: - /*TSK_DEBUG_INFO("Legacy_Theora_Comment_payload");*/ - break; - case Reserved: - /*TSK_DEBUG_INFO("Reserved");*/ - break; - } - } - while(--pkts>0); - - - - return retsize; + const uint8_t* pdata = in_data; + int pkts; + const uint8_t* pay_ptr; + tsk_size_t pay_size; + //tsk_size_t hdr_size; + tsk_size_t xsize, retsize = 0; + int got_picture_ptr; + int ret; + + tdav_codec_theora_t* theora = (tdav_codec_theora_t*)self; + const trtp_rtp_header_t* rtp_hdr = proto_hdr; + + if(!self || !in_data || (in_size<(THEORA_PAYLOAD_HEADER_SIZE + THEORA_PAYLOAD_LENGTH_SIZE)) || !out_data || !theora->decoder.context) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + /* Packet lost? */ + if(theora->decoder.last_seq != (rtp_hdr->seq_num - 1) && theora->decoder.last_seq) { + if(theora->decoder.last_seq == rtp_hdr->seq_num) { + // Could happen on some stupid emulators + //TSK_DEBUG_INFO("Packet duplicated, seq_num=%d", rtp_hdr->seq_num); + return 0; + } + TSK_DEBUG_INFO("Packet lost, seq_num=%d", rtp_hdr->seq_num); + } + theora->decoder.last_seq = rtp_hdr->seq_num; + + xsize = avpicture_get_size(theora->decoder.context->pix_fmt, theora->decoder.context->width, theora->decoder.context->height); + + /* 2.2. Payload Header + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Ident | F |TDT|# pkts.| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + /* 2.3. Payload Data + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Payload Length | Theora Data .. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + pkts = (pdata[3] & 0x0F); + pay_ptr = (pdata + THEORA_PAYLOAD_HEADER_SIZE); + + do { /* pkts=0 for fragmented packets */ + + pay_size = pay_ptr[0], pay_size<<=8, pay_size |= pay_ptr[1]; /* Big Endian read */ + pay_ptr += THEORA_PAYLOAD_LENGTH_SIZE; + /* check size validity */ + if((pay_ptr + pay_size)>(pdata + in_size)) { + TSK_DEBUG_ERROR("Too short"); + break; + } + + switch((pdata[3]>>4) & 0x03) { + case Raw_Theora_payload: { + /* ====== Theora data (2.2. Payload Header, 2.3. Payload Data) ====== */ + /* append buffer */ + if((int)(theora->decoder.accumulator_pos + pay_size) <= xsize) { + memcpy(&((uint8_t*)theora->decoder.accumulator)[theora->decoder.accumulator_pos], pay_ptr, pay_size); + theora->decoder.accumulator_pos += pay_size; + } + else { + TSK_DEBUG_WARN("Buffer overflow"); + theora->decoder.accumulator_pos = 0; + break; + } + /* only take care if last packet (What about the RTP marker?) */ + if(((pdata[3]>>6) == Not_Fragmented || (pdata[3]>>6) == End_Fragment /*|| rtp_hdr->marker*/) && theora->decoder.opened) { + AVPacket packet; + /* Perform decoding */ + av_init_packet(&packet); + packet.size = (int)theora->decoder.accumulator_pos; + packet.data = theora->decoder.accumulator; + ret = avcodec_decode_video2(theora->decoder.context, theora->decoder.picture, &got_picture_ptr, &packet); + + if(ret < 0) { + TSK_DEBUG_WARN("Failed to decode the buffer with error code = %d", ret); + if(TMEDIA_CODEC_VIDEO(self)->in.callback) { + TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_error; + TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; + TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); + } + } + else if(got_picture_ptr) { + retsize = xsize; + TMEDIA_CODEC_VIDEO(theora)->in.width = theora->decoder.context->width; + TMEDIA_CODEC_VIDEO(theora)->in.height = theora->decoder.context->height; + + /* allocate buffer */ + if(*out_max_size <xsize) { + if((*out_data = tsk_realloc(*out_data, xsize))) { + *out_max_size = xsize; + } + else { + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + *out_max_size = 0; + return 0; + } + } + /* copy picture into a linear buffer */ + avpicture_layout((AVPicture *)theora->decoder.picture, theora->decoder.context->pix_fmt, (int)theora->decoder.context->width, (int)theora->decoder.context->height, + *out_data, (int)retsize); + } + /* in all cases: reset accumulator */ + theora->decoder.accumulator_pos = 0; + } + break; + } + case Theora_Packed_Configuration_payload: { + /* ====== Configuration packet (3.1.1. Packed Configuration) ====== */ + static uint8_t __theora_comment_hdr[] = {0x81, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61, + 0x00, 0x00, 0x00, 0x08, /* 4-byte length */ + 'd', 'o', 'u', 'b', 'a', 'n', 'g', 'o', /* UTF-8 encoded string */ + }; + + /* http://www.theora.org/doc/Theora.pdf - Chapter 6 + A Theora bitstream begins with three header packets. The header packets + are, in order, the identifcation header, the comment header, and the setup + header. All are required for decode compliance. An end-of-packet condition + encountered while decoding the identification or setup header packets renders + the stream undecodable. An end-of-packet condition encountered while decode + the comment header is a non-fatal error condition, and MAY be ignored by a + decoder. + + Decode continues according to HEADERTYPE. The identification header + is type 0x80, the comment header is type 0x81, and the setup header is type + 0x82. + */ + /*TSK_DEBUG_INFO("Theora_Packed_Configuration_payload");*/ + + if(!theora->decoder.opened /*|| (conf_ident changed)*/) { + if(!theora->decoder.conf_pkt) { + theora->decoder.conf_pkt = tsk_buffer_create(pay_ptr, pay_size); + } + else { + tsk_buffer_append(theora->decoder.conf_pkt, pay_ptr, pay_size); + } + + if((pdata[3]>>6) == Not_Fragmented || (pdata[3]>>6) == End_Fragment || rtp_hdr->marker) { + if(theora->decoder.conf_pkt->size > THEORA_IDENT_HEADER_SIZE) { + const uint8_t* conf_ptr = theora->decoder.conf_pkt->data; + int setup_size = (int)theora->decoder.conf_pkt->size - THEORA_IDENT_HEADER_SIZE; + int extradata_size = (2 + THEORA_IDENT_HEADER_SIZE) + (2 + setup_size) + (2 + sizeof(__theora_comment_hdr)); + if(conf_ptr[0] == 0x80 && conf_ptr[THEORA_IDENT_HEADER_SIZE] == 0x82) { /* Do not check for 't'h'e'o'r'a' */ + /* save configration identification */ + memcpy(theora->decoder.conf_ident, &pdata[0], sizeof(theora->decoder.conf_ident)); + if(theora->decoder.context->extradata) { + TSK_FREE(theora->decoder.context->extradata); + } + if((theora->decoder.context->extradata = tsk_calloc(extradata_size + FF_INPUT_BUFFER_PADDING_SIZE, 1))) { + int index = 0; + /* Because of endianess pb. do not use uint16_t or uint32_t */ + theora->decoder.context->extradata[index++] = 0x00; + theora->decoder.context->extradata[index++] = THEORA_IDENT_HEADER_SIZE; + memcpy(&theora->decoder.context->extradata[index], &conf_ptr[0], THEORA_IDENT_HEADER_SIZE); + index += THEORA_IDENT_HEADER_SIZE; + + theora->decoder.context->extradata[index++] = (setup_size >>8) & 0xFF; + theora->decoder.context->extradata[index++] = (setup_size & 0xFF); + memcpy(&theora->decoder.context->extradata[index], &conf_ptr[THEORA_IDENT_HEADER_SIZE], setup_size); + index+=setup_size; + + theora->decoder.context->extradata[index++] = 0x00; + theora->decoder.context->extradata[index++] = sizeof(__theora_comment_hdr);/* <0xFF */ + memcpy(&theora->decoder.context->extradata[index], __theora_comment_hdr, sizeof(__theora_comment_hdr)); + + theora->decoder.context->extradata_size = extradata_size; + + if((ret = avcodec_open(theora->decoder.context, theora->decoder.codec)) == 0) { + theora->decoder.opened = tsk_true; + } + else { + TSK_DEBUG_ERROR("Failed to open theora decoder %d", ret); + TSK_FREE(theora->decoder.context->extradata); + theora->decoder.context->extradata_size = 0; + } + } + } + else { + TSK_DEBUG_ERROR("Invalid configuration packet"); + } + } + else { + TSK_DEBUG_ERROR("Too short"); + } + tsk_buffer_cleanup(theora->decoder.conf_pkt); + } + } + break; + } + case Legacy_Theora_Comment_payload: + /*TSK_DEBUG_INFO("Legacy_Theora_Comment_payload");*/ + break; + case Reserved: + /*TSK_DEBUG_INFO("Reserved");*/ + break; + } + } + while(--pkts>0); + + + + return retsize; } tsk_bool_t tdav_codec_theora_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value) { - tsk_bool_t ret = tsk_true; // accept decoding any size - - if(tsk_striequals(att_name, "fmtp")){ - tsk_params_L_t* params; - if((params = tsk_params_fromstring(att_value, ";", tsk_true))){ - int pref_width, pref_height; - int prop_width = tsk_params_get_param_value_as_int(params, "width"); - int prop_height = tsk_params_get_param_value_as_int(params, "height"); - - if(prop_width > 0 && prop_height > 0){ - if(tmedia_video_get_size(TMEDIA_CODEC_VIDEO(codec)->pref_size, (unsigned *)&pref_width, (unsigned *)&pref_height) != 0){ - TSK_OBJECT_SAFE_FREE(params); - return tsk_false; - } - TMEDIA_CODEC_VIDEO(codec)->in.width = TMEDIA_CODEC_VIDEO(codec)->out.width = TSK_MIN(pref_width, prop_width); - TMEDIA_CODEC_VIDEO(codec)->in.height = TMEDIA_CODEC_VIDEO(codec)->out.height = TSK_MIN(pref_height, prop_height); - } - TSK_OBJECT_SAFE_FREE(params); - } - } - else if(tsk_striequals(att_name, "imageattr")){ - unsigned in_width, in_height, out_width, out_height; - if(tmedia_parse_video_imageattr(att_value, TMEDIA_CODEC_VIDEO(codec)->pref_size, &in_width, &in_height, &out_width, &out_height) != 0){ - return tsk_false; - } - TMEDIA_CODEC_VIDEO(codec)->in.width = in_width; - TMEDIA_CODEC_VIDEO(codec)->in.height = in_height; - TMEDIA_CODEC_VIDEO(codec)->out.width = out_width; - TMEDIA_CODEC_VIDEO(codec)->out.height = out_height; - } - - return ret; + tsk_bool_t ret = tsk_true; // accept decoding any size + + if(tsk_striequals(att_name, "fmtp")) { + tsk_params_L_t* params; + if((params = tsk_params_fromstring(att_value, ";", tsk_true))) { + int pref_width, pref_height; + int prop_width = tsk_params_get_param_value_as_int(params, "width"); + int prop_height = tsk_params_get_param_value_as_int(params, "height"); + + if(prop_width > 0 && prop_height > 0) { + if(tmedia_video_get_size(TMEDIA_CODEC_VIDEO(codec)->pref_size, (unsigned *)&pref_width, (unsigned *)&pref_height) != 0) { + TSK_OBJECT_SAFE_FREE(params); + return tsk_false; + } + TMEDIA_CODEC_VIDEO(codec)->in.width = TMEDIA_CODEC_VIDEO(codec)->out.width = TSK_MIN(pref_width, prop_width); + TMEDIA_CODEC_VIDEO(codec)->in.height = TMEDIA_CODEC_VIDEO(codec)->out.height = TSK_MIN(pref_height, prop_height); + } + TSK_OBJECT_SAFE_FREE(params); + } + } + else if(tsk_striequals(att_name, "imageattr")) { + unsigned in_width, in_height, out_width, out_height; + if(tmedia_parse_video_imageattr(att_value, TMEDIA_CODEC_VIDEO(codec)->pref_size, &in_width, &in_height, &out_width, &out_height) != 0) { + return tsk_false; + } + TMEDIA_CODEC_VIDEO(codec)->in.width = in_width; + TMEDIA_CODEC_VIDEO(codec)->in.height = in_height; + TMEDIA_CODEC_VIDEO(codec)->out.width = out_width; + TMEDIA_CODEC_VIDEO(codec)->out.height = out_height; + } + + return ret; } char* tdav_codec_theora_sdp_att_get(const tmedia_codec_t* codec, const char* att_name) { - if(tsk_striequals(att_name, "fmtp")){ - char* fmtp = tsk_null; - tsk_sprintf(&fmtp, "sampling=YCbCr-4:2:0; width=%u; height=%u", TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height); - return fmtp; - } - else if(tsk_striequals(att_name, "imageattr")){ - return tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(codec)->pref_size, - TMEDIA_CODEC_VIDEO(codec)->in.width, TMEDIA_CODEC_VIDEO(codec)->in.height, TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height); - } - return tsk_null; + if(tsk_striequals(att_name, "fmtp")) { + char* fmtp = tsk_null; + tsk_sprintf(&fmtp, "sampling=YCbCr-4:2:0; width=%u; height=%u", TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height); + return fmtp; + } + else if(tsk_striequals(att_name, "imageattr")) { + return tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(codec)->pref_size, + TMEDIA_CODEC_VIDEO(codec)->in.width, TMEDIA_CODEC_VIDEO(codec)->in.height, TMEDIA_CODEC_VIDEO(codec)->out.width, TMEDIA_CODEC_VIDEO(codec)->out.height); + } + return tsk_null; } @@ -530,64 +526,62 @@ char* tdav_codec_theora_sdp_att_get(const tmedia_codec_t* codec, const char* att /* constructor */ static tsk_object_t* tdav_codec_theora_ctor(tsk_object_t * self, va_list * app) { - tdav_codec_theora_t *theora = self; - if(theora){ - /* init base: called by tmedia_codec_create() */ - /* init self */ - theora->encoder.quality = 1; - theora->encoder.max_bw_kpbs = tmedia_defaults_get_bandwidth_video_upload_max(); - } - return self; + tdav_codec_theora_t *theora = self; + if(theora) { + /* init base: called by tmedia_codec_create() */ + /* init self */ + theora->encoder.quality = 1; + theora->encoder.max_bw_kpbs = tmedia_defaults_get_bandwidth_video_upload_max(); + } + return self; } /* destructor */ static tsk_object_t* tdav_codec_theora_dtor(tsk_object_t * self) -{ - tdav_codec_theora_t *theora = self; - if(theora){ - /* deinit base */ - tmedia_codec_video_deinit(self); - /* deinit self */ - TSK_OBJECT_SAFE_FREE(theora->decoder.conf_pkt); - TSK_FREE(theora->rtp.ptr); - theora->rtp.size = 0; - } - - return self; +{ + tdav_codec_theora_t *theora = self; + if(theora) { + /* deinit base */ + tmedia_codec_video_deinit(self); + /* deinit self */ + TSK_OBJECT_SAFE_FREE(theora->decoder.conf_pkt); + TSK_FREE(theora->rtp.ptr); + theora->rtp.size = 0; + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_codec_theora_def_s = -{ - sizeof(tdav_codec_theora_t), - tdav_codec_theora_ctor, - tdav_codec_theora_dtor, - tmedia_codec_cmp, +static const tsk_object_def_t tdav_codec_theora_def_s = { + sizeof(tdav_codec_theora_t), + tdav_codec_theora_ctor, + tdav_codec_theora_dtor, + tmedia_codec_cmp, }; /* plugin definition*/ -static const tmedia_codec_plugin_def_t tdav_codec_theora_plugin_def_s = -{ - &tdav_codec_theora_def_s, - - tmedia_video, - tmedia_codec_id_theora, - "theora", - "Theora Codec", - TMEDIA_CODEC_FORMAT_THEORA, - tsk_true, - 90000, // rate - - /* audio */ - { 0 }, - - /* video (width, height, fps)*/ - {176, 144, 0},// fps is @deprecated - - tdav_codec_theora_set, - tdav_codec_theora_open, - tdav_codec_theora_close, - tdav_codec_theora_encode, - tdav_codec_theora_decode, - tdav_codec_theora_sdp_att_match, - tdav_codec_theora_sdp_att_get +static const tmedia_codec_plugin_def_t tdav_codec_theora_plugin_def_s = { + &tdav_codec_theora_def_s, + + tmedia_video, + tmedia_codec_id_theora, + "theora", + "Theora Codec", + TMEDIA_CODEC_FORMAT_THEORA, + tsk_true, + 90000, // rate + + /* audio */ + { 0 }, + + /* video (width, height, fps)*/ + {176, 144, 0},// fps is @deprecated + + tdav_codec_theora_set, + tdav_codec_theora_open, + tdav_codec_theora_close, + tdav_codec_theora_encode, + tdav_codec_theora_decode, + tdav_codec_theora_sdp_att_match, + tdav_codec_theora_sdp_att_get }; const tmedia_codec_plugin_def_t *tdav_codec_theora_plugin_def_t = &tdav_codec_theora_plugin_def_s; @@ -595,268 +589,268 @@ const tmedia_codec_plugin_def_t *tdav_codec_theora_plugin_def_t = &tdav_codec_th int tdav_codec_theora_open_encoder(tdav_codec_theora_t* self) { - int ret, size; - int32_t max_bw_kpbs; - if(!self->encoder.codec && !(self->encoder.codec = avcodec_find_encoder(CODEC_ID_THEORA))){ - TSK_DEBUG_ERROR("Failed to find Theora encoder"); - return -1; - } - if(self->encoder.context){ - TSK_DEBUG_ERROR("Encoder already initialized"); - return -1; - } - self->encoder.context = avcodec_alloc_context(); - avcodec_get_context_defaults(self->encoder.context); - - self->encoder.context->pix_fmt = PIX_FMT_YUV420P; - self->encoder.context->time_base.num = 1; - self->encoder.context->time_base.den = TMEDIA_CODEC_VIDEO(self)->out.fps; - self->encoder.context->width = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.height : TMEDIA_CODEC_VIDEO(self)->out.width; - self->encoder.context->height = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.width : TMEDIA_CODEC_VIDEO(self)->out.height; - self->encoder.context->mb_decision = FF_MB_DECISION_RD; - - // Theoraenc doesn't honor 'CODEC_FLAG_QSCALE' - max_bw_kpbs = TSK_CLAMP( - 0, - tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height, TMEDIA_CODEC_VIDEO(self)->out.fps), - self->encoder.max_bw_kpbs - ); - self->encoder.context->bit_rate = (max_bw_kpbs * 1024);// bps + int ret, size; + int32_t max_bw_kpbs; + if(!self->encoder.codec && !(self->encoder.codec = avcodec_find_encoder(CODEC_ID_THEORA))) { + TSK_DEBUG_ERROR("Failed to find Theora encoder"); + return -1; + } + if(self->encoder.context) { + TSK_DEBUG_ERROR("Encoder already initialized"); + return -1; + } + self->encoder.context = avcodec_alloc_context(); + avcodec_get_context_defaults(self->encoder.context); + + self->encoder.context->pix_fmt = PIX_FMT_YUV420P; + self->encoder.context->time_base.num = 1; + self->encoder.context->time_base.den = TMEDIA_CODEC_VIDEO(self)->out.fps; + self->encoder.context->width = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.height : TMEDIA_CODEC_VIDEO(self)->out.width; + self->encoder.context->height = (self->encoder.rotation == 90 || self->encoder.rotation == 270) ? TMEDIA_CODEC_VIDEO(self)->out.width : TMEDIA_CODEC_VIDEO(self)->out.height; + self->encoder.context->mb_decision = FF_MB_DECISION_RD; + + // Theoraenc doesn't honor 'CODEC_FLAG_QSCALE' + max_bw_kpbs = TSK_CLAMP( + 0, + tmedia_get_video_bandwidth_kbps_2(TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height, TMEDIA_CODEC_VIDEO(self)->out.fps), + self->encoder.max_bw_kpbs + ); + self->encoder.context->bit_rate = (max_bw_kpbs * 1024);// bps #if LIBAVCODEC_VERSION_MAJOR <= 53 - self->encoder.context->rc_lookahead = 0; + self->encoder.context->rc_lookahead = 0; #endif - self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality; - - self->encoder.context->thread_count = 0; - self->encoder.context->rtp_payload_size = THEORA_RTP_PAYLOAD_SIZE; - self->encoder.context->opaque = tsk_null; - self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->out.fps * THEORA_GOP_SIZE_IN_SECONDS); - - // Picture (YUV 420) - if(!(self->encoder.picture = avcodec_alloc_frame())){ - TSK_DEBUG_ERROR("Failed to create encoder picture"); - return -2; - } - avcodec_get_frame_defaults(self->encoder.picture); - - size = avpicture_get_size(PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height); - if(!(self->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))){ - TSK_DEBUG_ERROR("Failed to allocate encoder buffer"); - return -2; - } - - // Open encoder - if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0){ - TSK_DEBUG_ERROR("Failed to open Theora encoder"); - return ret; - } - - self->encoder.conf_last = 0; - self->encoder.conf_count = 0; - - TSK_DEBUG_INFO("[THEORA] bitrate=%d bps", self->encoder.context->bit_rate); - - return ret; + self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality; + + self->encoder.context->thread_count = 0; + self->encoder.context->rtp_payload_size = THEORA_RTP_PAYLOAD_SIZE; + self->encoder.context->opaque = tsk_null; + self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->out.fps * THEORA_GOP_SIZE_IN_SECONDS); + + // Picture (YUV 420) + if(!(self->encoder.picture = avcodec_alloc_frame())) { + TSK_DEBUG_ERROR("Failed to create encoder picture"); + return -2; + } + avcodec_get_frame_defaults(self->encoder.picture); + + size = avpicture_get_size(PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height); + if(!(self->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))) { + TSK_DEBUG_ERROR("Failed to allocate encoder buffer"); + return -2; + } + + // Open encoder + if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0) { + TSK_DEBUG_ERROR("Failed to open Theora encoder"); + return ret; + } + + self->encoder.conf_last = 0; + self->encoder.conf_count = 0; + + TSK_DEBUG_INFO("[THEORA] bitrate=%d bps", self->encoder.context->bit_rate); + + return ret; } int tdav_codec_theora_open_decoder(tdav_codec_theora_t* self) { - int size; - if(!self->decoder.codec && !(self->decoder.codec = avcodec_find_decoder(CODEC_ID_THEORA))){ - TSK_DEBUG_ERROR("Failed to find Theora decoder"); - return -1; - } - if(self->decoder.context){ - TSK_DEBUG_ERROR("Decoder already opened"); - return -1; - } - self->decoder.context = avcodec_alloc_context(); - avcodec_get_context_defaults(self->decoder.context); - - self->decoder.context->pix_fmt = PIX_FMT_YUV420P; - self->decoder.context->width = TMEDIA_CODEC_VIDEO(self)->in.width; - self->decoder.context->height = TMEDIA_CODEC_VIDEO(self)->in.height; - - // Picture (YUV 420) - if(!(self->decoder.picture = avcodec_alloc_frame())){ - TSK_DEBUG_ERROR("Failed to create decoder picture"); - return -2; - } - avcodec_get_frame_defaults(self->decoder.picture); - - size = avpicture_get_size(PIX_FMT_YUV420P, self->decoder.context->width, self->decoder.context->height); - if(!(self->decoder.accumulator = tsk_calloc((size + FF_INPUT_BUFFER_PADDING_SIZE), sizeof(uint8_t)))){ - TSK_DEBUG_ERROR("Failed to allocate decoder buffer"); - return -2; - } - - if(!(self->decoder.accumulator = tsk_calloc((size + FF_INPUT_BUFFER_PADDING_SIZE), sizeof(uint8_t)))){ - TSK_DEBUG_ERROR("Failed to allocate decoder buffer"); - return -2; - } - - // Open decoder - //if((ret = avcodec_open(self->decoder.context, self->decoder.codec)) < 0){ - // TSK_DEBUG_ERROR("Failed to open Theora decoder"); - // return ret; - //} - - return 0; + int size; + if(!self->decoder.codec && !(self->decoder.codec = avcodec_find_decoder(CODEC_ID_THEORA))) { + TSK_DEBUG_ERROR("Failed to find Theora decoder"); + return -1; + } + if(self->decoder.context) { + TSK_DEBUG_ERROR("Decoder already opened"); + return -1; + } + self->decoder.context = avcodec_alloc_context(); + avcodec_get_context_defaults(self->decoder.context); + + self->decoder.context->pix_fmt = PIX_FMT_YUV420P; + self->decoder.context->width = TMEDIA_CODEC_VIDEO(self)->in.width; + self->decoder.context->height = TMEDIA_CODEC_VIDEO(self)->in.height; + + // Picture (YUV 420) + if(!(self->decoder.picture = avcodec_alloc_frame())) { + TSK_DEBUG_ERROR("Failed to create decoder picture"); + return -2; + } + avcodec_get_frame_defaults(self->decoder.picture); + + size = avpicture_get_size(PIX_FMT_YUV420P, self->decoder.context->width, self->decoder.context->height); + if(!(self->decoder.accumulator = tsk_calloc((size + FF_INPUT_BUFFER_PADDING_SIZE), sizeof(uint8_t)))) { + TSK_DEBUG_ERROR("Failed to allocate decoder buffer"); + return -2; + } + + if(!(self->decoder.accumulator = tsk_calloc((size + FF_INPUT_BUFFER_PADDING_SIZE), sizeof(uint8_t)))) { + TSK_DEBUG_ERROR("Failed to allocate decoder buffer"); + return -2; + } + + // Open decoder + //if((ret = avcodec_open(self->decoder.context, self->decoder.codec)) < 0){ + // TSK_DEBUG_ERROR("Failed to open Theora decoder"); + // return ret; + //} + + return 0; } int tdav_codec_theora_close_encoder(tdav_codec_theora_t* self) { - if(self->encoder.context){ - avcodec_close(self->encoder.context); - av_free(self->encoder.context); - self->encoder.context = tsk_null; - } - if(self->encoder.picture){ - av_free(self->encoder.picture); - self->encoder.picture = tsk_null; - } - if(self->encoder.buffer){ - TSK_FREE(self->encoder.buffer); - } - return 0; + if(self->encoder.context) { + avcodec_close(self->encoder.context); + av_free(self->encoder.context); + self->encoder.context = tsk_null; + } + if(self->encoder.picture) { + av_free(self->encoder.picture); + self->encoder.picture = tsk_null; + } + if(self->encoder.buffer) { + TSK_FREE(self->encoder.buffer); + } + return 0; } int tdav_codec_theora_close_decoder(tdav_codec_theora_t* self) { - if(self->decoder.context){ - avcodec_close(self->decoder.context); - if(self->decoder.context->extradata){ - TSK_FREE(self->decoder.context->extradata); - self->decoder.context->extradata_size = 0; - } - av_free(self->decoder.context); - self->decoder.context = tsk_null; - } - if(self->decoder.picture){ - av_free(self->decoder.picture); - self->decoder.picture = tsk_null; - } - if(self->decoder.accumulator){ - TSK_FREE(self->decoder.accumulator); - } - return 0; + if(self->decoder.context) { + avcodec_close(self->decoder.context); + if(self->decoder.context->extradata) { + TSK_FREE(self->decoder.context->extradata); + self->decoder.context->extradata_size = 0; + } + av_free(self->decoder.context); + self->decoder.context = tsk_null; + } + if(self->decoder.picture) { + av_free(self->decoder.picture); + self->decoder.picture = tsk_null; + } + if(self->decoder.accumulator) { + TSK_FREE(self->decoder.accumulator); + } + return 0; } static void tdav_codec_theora_encap(tdav_codec_theora_t* theora, const uint8_t* pdata, tsk_size_t size) { - if((theora->encoder.conf_count < THEORA_CONF_SEND_COUNT) && theora->encoder.context && theora->encoder.context->extradata){ - if((theora->encoder.conf_last + (250 *theora->encoder.conf_count)) < tsk_time_now()){ - int hdr_size, i, exd_size = theora->encoder.context->extradata_size, conf_pkt_size = 0; - uint8_t *conf_pkt_ptr = tsk_null, *exd_ptr = theora->encoder.context->extradata; - for(i=0; i<3 && exd_size; i++){ - hdr_size = exd_ptr[0], hdr_size<<=8, hdr_size |= exd_ptr[1]; - exd_ptr += 2; - exd_size -= 2; - if(hdr_size > exd_size){ - TSK_DEBUG_ERROR("Invalid extradata"); - TSK_FREE(conf_pkt_ptr); - conf_pkt_size = 0; - } - - if(exd_ptr[0] == 0x80 || exd_ptr[0] == 0x82){ /* Ignore 'comment' which is equal to '0x81' */ - if((conf_pkt_ptr = tsk_realloc(conf_pkt_ptr, (conf_pkt_size + hdr_size)))){ - memcpy((conf_pkt_ptr + conf_pkt_size), exd_ptr, hdr_size); - conf_pkt_size += hdr_size; - } - } - exd_size -= hdr_size; - exd_ptr += hdr_size; - } - - /* Send the conf pack */ - if(conf_pkt_ptr && conf_pkt_size){ - /*TSK_DEBUG_INFO("Sending Configuration Packet");*/ - tdav_codec_theora_send(theora, conf_pkt_ptr, conf_pkt_size, Theora_Packed_Configuration_payload); - TSK_FREE(conf_pkt_ptr); - } - - theora->encoder.conf_last = tsk_time_now(); - theora->encoder.conf_count++; - } - } - - /* Send Theora Raw data */ - tdav_codec_theora_send(theora, pdata, size, Raw_Theora_payload); + if((theora->encoder.conf_count < THEORA_CONF_SEND_COUNT) && theora->encoder.context && theora->encoder.context->extradata) { + if((theora->encoder.conf_last + (250 *theora->encoder.conf_count)) < tsk_time_now()) { + int hdr_size, i, exd_size = theora->encoder.context->extradata_size, conf_pkt_size = 0; + uint8_t *conf_pkt_ptr = tsk_null, *exd_ptr = theora->encoder.context->extradata; + for(i=0; i<3 && exd_size; i++) { + hdr_size = exd_ptr[0], hdr_size<<=8, hdr_size |= exd_ptr[1]; + exd_ptr += 2; + exd_size -= 2; + if(hdr_size > exd_size) { + TSK_DEBUG_ERROR("Invalid extradata"); + TSK_FREE(conf_pkt_ptr); + conf_pkt_size = 0; + } + + if(exd_ptr[0] == 0x80 || exd_ptr[0] == 0x82) { /* Ignore 'comment' which is equal to '0x81' */ + if((conf_pkt_ptr = tsk_realloc(conf_pkt_ptr, (conf_pkt_size + hdr_size)))) { + memcpy((conf_pkt_ptr + conf_pkt_size), exd_ptr, hdr_size); + conf_pkt_size += hdr_size; + } + } + exd_size -= hdr_size; + exd_ptr += hdr_size; + } + + /* Send the conf pack */ + if(conf_pkt_ptr && conf_pkt_size) { + /*TSK_DEBUG_INFO("Sending Configuration Packet");*/ + tdav_codec_theora_send(theora, conf_pkt_ptr, conf_pkt_size, Theora_Packed_Configuration_payload); + TSK_FREE(conf_pkt_ptr); + } + + theora->encoder.conf_last = tsk_time_now(); + theora->encoder.conf_count++; + } + } + + /* Send Theora Raw data */ + tdav_codec_theora_send(theora, pdata, size, Raw_Theora_payload); } int tdav_codec_theora_send(tdav_codec_theora_t* self, const uint8_t* data, tsk_size_t size, theora_datatype_t tdt) -{ - /* 2.2. Payload Header - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Configuration Ident | F |TDT|# pkts.| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - uint8_t pay_hdr[THEORA_PAYLOAD_HEADER_SIZE/*4*/ + THEORA_PAYLOAD_LENGTH_SIZE/*2*/] = {0x01, 0x19, 0x83, 0x00, 0x00, 0x00}; - //uint8_t* pay_ptr = tsk_null; - tsk_size_t pay_size; - tsk_bool_t frag, first = tsk_true; - - pay_hdr[3] = (tdt & 0xFF) <<4; - - /* whether the packet will be fragmented or not */ - frag = (size > THEORA_RTP_PAYLOAD_SIZE); - - while(size){ - pay_size = TSK_MIN(THEORA_RTP_PAYLOAD_SIZE, size); - pay_hdr[4] = (uint8_t)(pay_size >> 8), pay_hdr[5] = (uint8_t)(pay_size & 0xFF); - - if(frag){ - if(first){ - first = tsk_false; - pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Start_Fragment <<6); - } - else{ /* could not be 'first' and 'last' */ - if(size<=THEORA_RTP_PAYLOAD_SIZE){ - /* Last frag */ - pay_hdr[3] &= 0x3F, pay_hdr[3] |= (End_Fragment <<6); - } - else{ - /* Continuation frag */ - pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Continuation_Fragment <<6); - } - } - } - else{ - pay_hdr[3] |= 0x01; /* 'pkts' */ - pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Not_Fragmented <<6); - } - - if(self->rtp.size < (pay_size + sizeof(pay_hdr))){ - if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (pay_size + sizeof(pay_hdr))))){ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - return -2; - } - self->rtp.size = (pay_size + sizeof(pay_hdr)); - } - - memcpy(self->rtp.ptr, pay_hdr, sizeof(pay_hdr)); - memcpy((self->rtp.ptr + sizeof(pay_hdr)), data, pay_size); - data += pay_size; - size -= pay_size; - - // Send data over the network - if(TMEDIA_CODEC_VIDEO(self)->out.callback){ - TMEDIA_CODEC_VIDEO(self)->out.result.buffer.ptr = self->rtp.ptr; - TMEDIA_CODEC_VIDEO(self)->out.result.buffer.size = (pay_size + sizeof(pay_hdr)); - TMEDIA_CODEC_VIDEO(self)->out.result.duration = (1./(double)TMEDIA_CODEC_VIDEO(self)->out.fps) * TMEDIA_CODEC(self)->plugin->rate; - TMEDIA_CODEC_VIDEO(self)->out.result.last_chunck = (size == 0); - TMEDIA_CODEC_VIDEO(self)->out.callback(&TMEDIA_CODEC_VIDEO(self)->out.result); - } - } - - return 0; +{ + /* 2.2. Payload Header + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Ident | F |TDT|# pkts.| + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + uint8_t pay_hdr[THEORA_PAYLOAD_HEADER_SIZE/*4*/ + THEORA_PAYLOAD_LENGTH_SIZE/*2*/] = {0x01, 0x19, 0x83, 0x00, 0x00, 0x00}; + //uint8_t* pay_ptr = tsk_null; + tsk_size_t pay_size; + tsk_bool_t frag, first = tsk_true; + + pay_hdr[3] = (tdt & 0xFF) <<4; + + /* whether the packet will be fragmented or not */ + frag = (size > THEORA_RTP_PAYLOAD_SIZE); + + while(size) { + pay_size = TSK_MIN(THEORA_RTP_PAYLOAD_SIZE, size); + pay_hdr[4] = (uint8_t)(pay_size >> 8), pay_hdr[5] = (uint8_t)(pay_size & 0xFF); + + if(frag) { + if(first) { + first = tsk_false; + pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Start_Fragment <<6); + } + else { /* could not be 'first' and 'last' */ + if(size<=THEORA_RTP_PAYLOAD_SIZE) { + /* Last frag */ + pay_hdr[3] &= 0x3F, pay_hdr[3] |= (End_Fragment <<6); + } + else { + /* Continuation frag */ + pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Continuation_Fragment <<6); + } + } + } + else { + pay_hdr[3] |= 0x01; /* 'pkts' */ + pay_hdr[3] &= 0x3F, pay_hdr[3] |= (Not_Fragmented <<6); + } + + if(self->rtp.size < (pay_size + sizeof(pay_hdr))) { + if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (pay_size + sizeof(pay_hdr))))) { + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + return -2; + } + self->rtp.size = (pay_size + sizeof(pay_hdr)); + } + + memcpy(self->rtp.ptr, pay_hdr, sizeof(pay_hdr)); + memcpy((self->rtp.ptr + sizeof(pay_hdr)), data, pay_size); + data += pay_size; + size -= pay_size; + + // Send data over the network + if(TMEDIA_CODEC_VIDEO(self)->out.callback) { + TMEDIA_CODEC_VIDEO(self)->out.result.buffer.ptr = self->rtp.ptr; + TMEDIA_CODEC_VIDEO(self)->out.result.buffer.size = (pay_size + sizeof(pay_hdr)); + TMEDIA_CODEC_VIDEO(self)->out.result.duration = (1./(double)TMEDIA_CODEC_VIDEO(self)->out.fps) * TMEDIA_CODEC(self)->plugin->rate; + TMEDIA_CODEC_VIDEO(self)->out.result.last_chunck = (size == 0); + TMEDIA_CODEC_VIDEO(self)->out.callback(&TMEDIA_CODEC_VIDEO(self)->out.result); + } + } + + return 0; } tsk_bool_t tdav_codec_ffmpeg_theora_is_supported() { - return (avcodec_find_encoder(CODEC_ID_THEORA) && avcodec_find_decoder(CODEC_ID_THEORA)); + return (avcodec_find_encoder(CODEC_ID_THEORA) && avcodec_find_decoder(CODEC_ID_THEORA)); } #endif /* HAVE_FFMPEG */
\ No newline at end of file |