summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c')
-rwxr-xr-xtinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c1295
1 files changed, 644 insertions, 651 deletions
diff --git a/tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c b/tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c
index e48cb00..7c99acd 100755
--- a/tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.c
+++ b/tinyDAV/src/codecs/mp4ves/tdav_codec_mp4ves.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.
*
@@ -54,103 +54,100 @@
#define MP4V_GOP_SIZE_IN_SECONDS 25
#define MP4V_RTP_PAYLOAD_SIZE 900
-typedef struct tdav_codec_mp4ves_s
-{
- TMEDIA_DECLARE_CODEC_VIDEO;
-
- int profile;
-
- struct{
- uint8_t* ptr;
- tsk_size_t size;
- } rtp;
-
- // Encoder
- struct{
- AVCodec* codec;
- AVCodecContext* context;
- AVFrame* picture;
- void* buffer;
- tsk_bool_t force_idr;
- int quality; // [1-31]
- int rotation;
- int32_t max_bw_kpbs;
- } encoder;
-
- // decoder
- struct{
- AVCodec* codec;
- AVCodecContext* context;
- AVFrame* picture;
-
- void* accumulator;
- uint8_t ebit;
- tsk_size_t accumulator_pos;
- uint16_t last_seq;
- } decoder;
+typedef struct tdav_codec_mp4ves_s {
+ TMEDIA_DECLARE_CODEC_VIDEO;
+
+ int profile;
+
+ struct {
+ uint8_t* ptr;
+ tsk_size_t size;
+ } rtp;
+
+ // Encoder
+ struct {
+ AVCodec* codec;
+ AVCodecContext* context;
+ AVFrame* picture;
+ void* buffer;
+ tsk_bool_t force_idr;
+ int quality; // [1-31]
+ int rotation;
+ int32_t max_bw_kpbs;
+ } encoder;
+
+ // decoder
+ struct {
+ AVCodec* codec;
+ AVCodecContext* context;
+ AVFrame* picture;
+
+ void* accumulator;
+ uint8_t ebit;
+ tsk_size_t accumulator_pos;
+ uint16_t last_seq;
+ } decoder;
}
tdav_codec_mp4ves_t;
// From ISO-IEC-14496-2
-typedef enum mp4v_codes_e
-{
- // To initiate a visual session (6.3.2)
- visual_object_sequence_start_code = 0x000001B0,
- // To terminate a visual session (6.3.2)
- visual_object_sequence_end_code = 0x000001B1,
- // To initiate a visual object (6.3.2)
- visual_object_start_code = 0x000001B5,
- // To identify the beginning of user data. The user data continues until receipt of another start code. (6.3.2.1)
- user_data_start_code = 0x000001B2,
- // The video_object_layer_start_code is a string of 32 bits. The first 28 bits are
- // ‘0000 0000 0000 0000 0000 0001 0010‘ in binary and the last 4-bits represent one of the values in the range of
- // ‘0000’ to ‘1111’ in binary. The video_object_layer_start_code marks a new video object layer. (6.3.3)
- video_object_layer_start_code = 0x0000012,
- // To identify the beginning of a GOV header (6.3.4)
- group_of_vop_start_code = 0x000001B3,
- // To mark the start of a video object plane (6.3.5 )
- vop_start_code = 0x000001B6,
+typedef enum mp4v_codes_e {
+ // To initiate a visual session (6.3.2)
+ visual_object_sequence_start_code = 0x000001B0,
+ // To terminate a visual session (6.3.2)
+ visual_object_sequence_end_code = 0x000001B1,
+ // To initiate a visual object (6.3.2)
+ visual_object_start_code = 0x000001B5,
+ // To identify the beginning of user data. The user data continues until receipt of another start code. (6.3.2.1)
+ user_data_start_code = 0x000001B2,
+ // The video_object_layer_start_code is a string of 32 bits. The first 28 bits are
+ // ‘0000 0000 0000 0000 0000 0001 0010‘ in binary and the last 4-bits represent one of the values in the range of
+ // ‘0000’ to ‘1111’ in binary. The video_object_layer_start_code marks a new video object layer. (6.3.3)
+ video_object_layer_start_code = 0x0000012,
+ // To identify the beginning of a GOV header (6.3.4)
+ group_of_vop_start_code = 0x000001B3,
+ // To mark the start of a video object plane (6.3.5 )
+ vop_start_code = 0x000001B6,
}
mp4v_start_code_t;
// From ISO-IEC-14496-2 Annex G
-typedef enum mp4v_profiles_e
-{
- /* Reserved = 0x00000000 */
- Simple_Profile_Level_1 = 1,
- Simple_Profile_Level_2 = 2,
- Simple_Profile_Level_3 = 3,
- /* Reserved 00000100 ? 00010000 */
- Simple_Scalable_Profile_Level_1 = 17,
- Simple_Scalable_Profile_Level_2 = 18,
- /* Reserved 00010011 ? = 0x00100000 */
- Core_Profile_Level_1 = 33,
- Core_Profile_Level_2 = 34,
- /* Reserved 00100011 ? = 0x00110001 */
- Main_Profile_Level_2 = 50,
- Main_Profile_Level_3 = 51,
- Main_Profile_Level_4 = 52,
- /* Reserved 00110101 ? = 0x01000001 */
- N_bit_Profile_Level_2 = 66,
- /* Reserved 01000011 ? = 0x01010000 */
- Scalable_Texture_Profile_Level_1 = 81,
- /* Reserved 01010010 ? 01100000 */
- Simple_Face_Animation_Profile_Level_1 = 97,
- Simple_Face_Animation_Profile_Level_2 = 98,
- Simple_FBA_Profile_Level_1 = 99,
- Simple_FBA_Profile_Level_2 = 100,
- /* Reserved 01100101 ? 01110000 */
- Basic_Animated_Texture_Profile_Level_1 = 113,
- Basic_Animated_Texture_Profile_Level_2 = 114,
- /* Reserved 01110011 ? 10000000 */
- Hybrid_Profile_Level_1 = 129,
- Hybrid_Profile_Level_2 = 130,
- /* Reserved 10000011 ? 10010000 */
- Advanced_Real_Time_Simple_Profile_Level_1 = 145,
- Advanced_Real_Time_Simple_Profile_Level_2 = 146,
- Advanced_Real_Time_Simple_Profile_Level_3 = 147,
- Advanced_Real_Time_Simple_Profile_Level_4 = 148,
- /* Reserved 10010101 ? 10100000 */
+typedef enum mp4v_profiles_e {
+ /* Reserved = 0x00000000 */
+ Simple_Profile_Level_1 = 1,
+ Simple_Profile_Level_2 = 2,
+ Simple_Profile_Level_3 = 3,
+ /* Reserved 00000100 ? 00010000 */
+ Simple_Scalable_Profile_Level_1 = 17,
+ Simple_Scalable_Profile_Level_2 = 18,
+ /* Reserved 00010011 ? = 0x00100000 */
+ Core_Profile_Level_1 = 33,
+ Core_Profile_Level_2 = 34,
+ /* Reserved 00100011 ? = 0x00110001 */
+ Main_Profile_Level_2 = 50,
+ Main_Profile_Level_3 = 51,
+ Main_Profile_Level_4 = 52,
+ /* Reserved 00110101 ? = 0x01000001 */
+ N_bit_Profile_Level_2 = 66,
+ /* Reserved 01000011 ? = 0x01010000 */
+ Scalable_Texture_Profile_Level_1 = 81,
+ /* Reserved 01010010 ? 01100000 */
+ Simple_Face_Animation_Profile_Level_1 = 97,
+ Simple_Face_Animation_Profile_Level_2 = 98,
+ Simple_FBA_Profile_Level_1 = 99,
+ Simple_FBA_Profile_Level_2 = 100,
+ /* Reserved 01100101 ? 01110000 */
+ Basic_Animated_Texture_Profile_Level_1 = 113,
+ Basic_Animated_Texture_Profile_Level_2 = 114,
+ /* Reserved 01110011 ? 10000000 */
+ Hybrid_Profile_Level_1 = 129,
+ Hybrid_Profile_Level_2 = 130,
+ /* Reserved 10000011 ? 10010000 */
+ Advanced_Real_Time_Simple_Profile_Level_1 = 145,
+ Advanced_Real_Time_Simple_Profile_Level_2 = 146,
+ Advanced_Real_Time_Simple_Profile_Level_3 = 147,
+ Advanced_Real_Time_Simple_Profile_Level_4 = 148,
+ /* Reserved 10010101 ? 10100000 */
}
mp4v_profiles_t;
@@ -166,580 +163,578 @@ static void tdav_codec_mp4ves_rtp_callback(tdav_codec_mp4ves_t *mp4v, const void
static int tdav_codec_mp4ves_set(tmedia_codec_t* self, const tmedia_param_t* param)
{
- tdav_codec_mp4ves_t* mp4ves = (tdav_codec_mp4ves_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:
- {
- mp4ves->encoder.force_idr = tsk_true;
- break;
- }
- case tmedia_codec_action_bw_down:
- {
- mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality + 1), 31);
- mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
- break;
- }
- case tmedia_codec_action_bw_up:
- {
- mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality - 1), 31);
- mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
- break;
- }
- }
- }
- else if(tsk_striequals(param->key, "rotation")){
- int rotation = *((int32_t*)param->value);
- if(mp4ves->encoder.rotation != rotation){
- if(self->opened){
- int ret;
- mp4ves->encoder.rotation = rotation;
- if((ret = tdav_codec_mp4ves_close_encoder(mp4ves))){
- return ret;
- }
- if((ret = tdav_codec_mp4ves_open_encoder(mp4ves))){
- return ret;
- }
- }
- }
- return 0;
- }
- }
- return -1;
+ tdav_codec_mp4ves_t* mp4ves = (tdav_codec_mp4ves_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: {
+ mp4ves->encoder.force_idr = tsk_true;
+ break;
+ }
+ case tmedia_codec_action_bw_down: {
+ mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality + 1), 31);
+ mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
+ break;
+ }
+ case tmedia_codec_action_bw_up: {
+ mp4ves->encoder.quality = TSK_CLAMP(1, (mp4ves->encoder.quality - 1), 31);
+ mp4ves->encoder.context->global_quality = FF_QP2LAMBDA * mp4ves->encoder.quality;
+ break;
+ }
+ }
+ }
+ else if(tsk_striequals(param->key, "rotation")) {
+ int rotation = *((int32_t*)param->value);
+ if(mp4ves->encoder.rotation != rotation) {
+ if(self->opened) {
+ int ret;
+ mp4ves->encoder.rotation = rotation;
+ if((ret = tdav_codec_mp4ves_close_encoder(mp4ves))) {
+ return ret;
+ }
+ if((ret = tdav_codec_mp4ves_open_encoder(mp4ves))) {
+ return ret;
+ }
+ }
+ }
+ return 0;
+ }
+ }
+ return -1;
}
int tdav_codec_mp4ves_open(tmedia_codec_t* self)
{
- int ret;
-
- tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
-
- if(!mp4v){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- /* the caller (base class) already checked that the codec is not opened */
-
-
- // Encoder
- if((ret = tdav_codec_mp4ves_open_encoder(mp4v))){
- return ret;
- }
-
- // Decoder
- if((ret = tdav_codec_mp4ves_open_decoder(mp4v))){
- return ret;
- }
-
- return 0;
+ int ret;
+
+ tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
+
+ if(!mp4v) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* the caller (base class) already checked that the codec is not opened */
+
+
+ // Encoder
+ if((ret = tdav_codec_mp4ves_open_encoder(mp4v))) {
+ return ret;
+ }
+
+ // Decoder
+ if((ret = tdav_codec_mp4ves_open_decoder(mp4v))) {
+ return ret;
+ }
+
+ return 0;
}
int tdav_codec_mp4ves_close(tmedia_codec_t* self)
{
- tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
+ tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
+
+ if(!mp4v) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- if(!mp4v){
- 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_mp4ves_close_encoder(mp4v);
- // Encoder
- tdav_codec_mp4ves_close_encoder(mp4v);
-
- // Decoder
- tdav_codec_mp4ves_close_decoder(mp4v);
+ // Decoder
+ tdav_codec_mp4ves_close_decoder(mp4v);
- return 0;
+ return 0;
}
tsk_size_t tdav_codec_mp4ves_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;
+ int ret;
+ int size;
- tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
+ tdav_codec_mp4ves_t* mp4v = (tdav_codec_mp4ves_t*)self;
- if(!self || !in_data || !in_size || !out_data){
- TSK_DEBUG_ERROR("Invalid parameter");
- return 0;
- }
+ if(!self || !in_data || !in_size || !out_data) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
- // wrap yuv420 buffer
- size = avpicture_fill((AVPicture *)mp4v->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, mp4v->encoder.context->width, mp4v->encoder.context->height);
- if(size != in_size){
- /* guard */
- TSK_DEBUG_ERROR("Invalid size");
- return 0;
- }
+ // wrap yuv420 buffer
+ size = avpicture_fill((AVPicture *)mp4v->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, mp4v->encoder.context->width, mp4v->encoder.context->height);
+ if(size != in_size) {
+ /* guard */
+ TSK_DEBUG_ERROR("Invalid size");
+ return 0;
+ }
- if(mp4v->encoder.force_idr){
+ if(mp4v->encoder.force_idr) {
#if LIBAVCODEC_VERSION_MAJOR <= 53
mp4v->encoder.picture->pict_type = FF_I_TYPE;
#else
mp4v->encoder.picture->pict_type = AV_PICTURE_TYPE_I;
#endif
- mp4v->encoder.force_idr = tsk_false;
- }
- else{
- mp4v->encoder.picture->pict_type = 0;// reset
- }
- mp4v->encoder.picture->pts = AV_NOPTS_VALUE;
- mp4v->encoder.picture->quality = mp4v->encoder.context->global_quality;
- ret = avcodec_encode_video(mp4v->encoder.context, mp4v->encoder.buffer, size, mp4v->encoder.picture);
- if(ret > 0){
- tdav_codec_mp4ves_encap(mp4v, mp4v->encoder.buffer, (tsk_size_t)ret);
- }
-
- return 0;
+ mp4v->encoder.force_idr = tsk_false;
+ }
+ else {
+ mp4v->encoder.picture->pict_type = 0;// reset
+ }
+ mp4v->encoder.picture->pts = AV_NOPTS_VALUE;
+ mp4v->encoder.picture->quality = mp4v->encoder.context->global_quality;
+ ret = avcodec_encode_video(mp4v->encoder.context, mp4v->encoder.buffer, size, mp4v->encoder.picture);
+ if(ret > 0) {
+ tdav_codec_mp4ves_encap(mp4v, mp4v->encoder.buffer, (tsk_size_t)ret);
+ }
+
+ return 0;
}
tsk_size_t tdav_codec_mp4ves_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)
-{
- tdav_codec_mp4ves_t* self = (tdav_codec_mp4ves_t*)_self;
- const trtp_rtp_header_t* rtp_hdr = proto_hdr;
-
- tsk_size_t xsize, retsize = 0;
- int got_picture_ptr;
- int ret;
-
- if(!self || !in_data || !in_size || !out_data || !self->decoder.context){
- TSK_DEBUG_ERROR("Invalid parameter");
- return 0;
- }
-
- // get expected size
- xsize = avpicture_get_size(self->decoder.context->pix_fmt, self->decoder.context->width, self->decoder.context->height);
-
- /* Packet lost? */
- if(self->decoder.last_seq != (rtp_hdr->seq_num - 1) && self->decoder.last_seq){
- if(self->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);
- }
- self->decoder.last_seq = rtp_hdr->seq_num;
-
- if((self->decoder.accumulator_pos + in_size) <= xsize){
- memcpy(&((uint8_t*)self->decoder.accumulator)[self->decoder.accumulator_pos], in_data, in_size);
- self->decoder.accumulator_pos += in_size;
- }
- else{
- TSK_DEBUG_WARN("Buffer overflow");
- self->decoder.accumulator_pos = 0;
- return 0;
- }
-
- if(rtp_hdr->marker){
- AVPacket packet;
- /* allocate destination buffer */
- if(*out_max_size <xsize){
- if(!(*out_data = tsk_realloc(*out_data, xsize))){
- TSK_DEBUG_ERROR("Failed to allocate new buffer");
- self->decoder.accumulator_pos = 0;
- *out_max_size = 0;
- return 0;
- }
- *out_max_size = xsize;
- }
-
- av_init_packet(&packet);
- packet.size = (int)self->decoder.accumulator_pos;
- packet.data = self->decoder.accumulator;
- ret = avcodec_decode_video2(self->decoder.context, self->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(self)->in.width = self->decoder.context->width;
- TMEDIA_CODEC_VIDEO(self)->in.height = self->decoder.context->height;
-
- /* copy picture into a linear buffer */
- avpicture_layout((AVPicture *)self->decoder.picture, self->decoder.context->pix_fmt, (int)self->decoder.context->width, (int)self->decoder.context->height,
- *out_data, (int)retsize);
- }
- /* in all cases: reset accumulator */
- self->decoder.accumulator_pos = 0;
- }
-
- return retsize;
+{
+ tdav_codec_mp4ves_t* self = (tdav_codec_mp4ves_t*)_self;
+ const trtp_rtp_header_t* rtp_hdr = proto_hdr;
+
+ tsk_size_t xsize, retsize = 0;
+ int got_picture_ptr;
+ int ret;
+
+ if(!self || !in_data || !in_size || !out_data || !self->decoder.context) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return 0;
+ }
+
+ // get expected size
+ xsize = avpicture_get_size(self->decoder.context->pix_fmt, self->decoder.context->width, self->decoder.context->height);
+
+ /* Packet lost? */
+ if(self->decoder.last_seq != (rtp_hdr->seq_num - 1) && self->decoder.last_seq) {
+ if(self->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);
+ }
+ self->decoder.last_seq = rtp_hdr->seq_num;
+
+ if((self->decoder.accumulator_pos + in_size) <= xsize) {
+ memcpy(&((uint8_t*)self->decoder.accumulator)[self->decoder.accumulator_pos], in_data, in_size);
+ self->decoder.accumulator_pos += in_size;
+ }
+ else {
+ TSK_DEBUG_WARN("Buffer overflow");
+ self->decoder.accumulator_pos = 0;
+ return 0;
+ }
+
+ if(rtp_hdr->marker) {
+ AVPacket packet;
+ /* allocate destination buffer */
+ if(*out_max_size <xsize) {
+ if(!(*out_data = tsk_realloc(*out_data, xsize))) {
+ TSK_DEBUG_ERROR("Failed to allocate new buffer");
+ self->decoder.accumulator_pos = 0;
+ *out_max_size = 0;
+ return 0;
+ }
+ *out_max_size = xsize;
+ }
+
+ av_init_packet(&packet);
+ packet.size = (int)self->decoder.accumulator_pos;
+ packet.data = self->decoder.accumulator;
+ ret = avcodec_decode_video2(self->decoder.context, self->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(self)->in.width = self->decoder.context->width;
+ TMEDIA_CODEC_VIDEO(self)->in.height = self->decoder.context->height;
+
+ /* copy picture into a linear buffer */
+ avpicture_layout((AVPicture *)self->decoder.picture, self->decoder.context->pix_fmt, (int)self->decoder.context->width, (int)self->decoder.context->height,
+ *out_data, (int)retsize);
+ }
+ /* in all cases: reset accumulator */
+ self->decoder.accumulator_pos = 0;
+ }
+
+ return retsize;
}
tsk_bool_t tdav_codec_mp4ves_sdp_att_match(const tmedia_codec_t* _self, const char* att_name, const char* att_value)
{
- tdav_codec_mp4ves_t *self = (tdav_codec_mp4ves_t *)_self;
-
- if(!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_false;
- }
-
- if(tsk_striequals(att_name, "fmtp")){
- tsk_params_L_t* params ;
- /* e.g. profile-level-id=1; xx=yy */
- if((params = tsk_params_fromstring(att_value, ";", tsk_true))){
- int val_int;
- if((val_int = tsk_params_get_param_value_as_int(params, "profile-level-id")) != -1){
- TSK_DEBUG_INFO("Proposed profile-level-id=%d", val_int);
- self->profile = val_int; // FIXME: Take the remote profile-level-id even if the bandwidth level doesn't match
- }
- TSK_OBJECT_SAFE_FREE(params);
- }
-
- switch (self->profile ) {
- case Simple_Profile_Level_1:
- TMEDIA_CODEC_VIDEO(self)->out.width = TMEDIA_CODEC_VIDEO(self)->in.width = 176; TMEDIA_CODEC_VIDEO(self)->in.height = TMEDIA_CODEC_VIDEO(self)->out.height = 144;
- break;
- case Simple_Profile_Level_2:
- case Simple_Profile_Level_3:
- default:
- TMEDIA_CODEC_VIDEO(self)->out.width = TMEDIA_CODEC_VIDEO(self)->in.width = 352; TMEDIA_CODEC_VIDEO(self)->in.height = TMEDIA_CODEC_VIDEO(self)->out.height = 288;
- break;
- }
- }
- 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(self)->pref_size, &in_width, &in_height, &out_width, &out_height) != 0){
- return tsk_false;
- }
- TMEDIA_CODEC_VIDEO(self)->in.width = in_width;
- TMEDIA_CODEC_VIDEO(self)->in.height = in_height;
- TMEDIA_CODEC_VIDEO(self)->out.width = out_width;
- TMEDIA_CODEC_VIDEO(self)->out.height = out_height;
- }
-
- return tsk_true;
+ tdav_codec_mp4ves_t *self = (tdav_codec_mp4ves_t *)_self;
+
+ if(!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ if(tsk_striequals(att_name, "fmtp")) {
+ tsk_params_L_t* params ;
+ /* e.g. profile-level-id=1; xx=yy */
+ if((params = tsk_params_fromstring(att_value, ";", tsk_true))) {
+ int val_int;
+ if((val_int = tsk_params_get_param_value_as_int(params, "profile-level-id")) != -1) {
+ TSK_DEBUG_INFO("Proposed profile-level-id=%d", val_int);
+ self->profile = val_int; // FIXME: Take the remote profile-level-id even if the bandwidth level doesn't match
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ switch (self->profile ) {
+ case Simple_Profile_Level_1:
+ TMEDIA_CODEC_VIDEO(self)->out.width = TMEDIA_CODEC_VIDEO(self)->in.width = 176;
+ TMEDIA_CODEC_VIDEO(self)->in.height = TMEDIA_CODEC_VIDEO(self)->out.height = 144;
+ break;
+ case Simple_Profile_Level_2:
+ case Simple_Profile_Level_3:
+ default:
+ TMEDIA_CODEC_VIDEO(self)->out.width = TMEDIA_CODEC_VIDEO(self)->in.width = 352;
+ TMEDIA_CODEC_VIDEO(self)->in.height = TMEDIA_CODEC_VIDEO(self)->out.height = 288;
+ break;
+ }
+ }
+ 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(self)->pref_size, &in_width, &in_height, &out_width, &out_height) != 0) {
+ return tsk_false;
+ }
+ TMEDIA_CODEC_VIDEO(self)->in.width = in_width;
+ TMEDIA_CODEC_VIDEO(self)->in.height = in_height;
+ TMEDIA_CODEC_VIDEO(self)->out.width = out_width;
+ TMEDIA_CODEC_VIDEO(self)->out.height = out_height;
+ }
+
+ return tsk_true;
}
char* tdav_codec_mp4ves_sdp_att_get(const tmedia_codec_t* _self, const char* att_name)
{
- tdav_codec_mp4ves_t *self = (tdav_codec_mp4ves_t *)_self;
-
- if(tsk_striequals(att_name, "fmtp")){
- char* fmtp = tsk_null;
- switch(_self->bl){//FIXME: deprecated
- case tmedia_bl_low:
- default:
- self->profile = Simple_Profile_Level_1;
- break;
- case tmedia_bl_medium:
- self->profile = Simple_Profile_Level_2;
- break;
- case tmedia_bl_hight:
- case tmedia_bl_unrestricted:
- self->profile = Simple_Profile_Level_3;
- break;
- }
- tsk_sprintf(&fmtp, "profile-level-id=%d", self->profile);
- return fmtp;
- }
- else if(tsk_striequals(att_name, "imageattr")){
- return tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(self)->pref_size,
- TMEDIA_CODEC_VIDEO(self)->in.width, TMEDIA_CODEC_VIDEO(self)->in.height, TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height);
- }
- return tsk_null;
+ tdav_codec_mp4ves_t *self = (tdav_codec_mp4ves_t *)_self;
+
+ if(tsk_striequals(att_name, "fmtp")) {
+ char* fmtp = tsk_null;
+ switch(_self->bl) { //FIXME: deprecated
+ case tmedia_bl_low:
+ default:
+ self->profile = Simple_Profile_Level_1;
+ break;
+ case tmedia_bl_medium:
+ self->profile = Simple_Profile_Level_2;
+ break;
+ case tmedia_bl_hight:
+ case tmedia_bl_unrestricted:
+ self->profile = Simple_Profile_Level_3;
+ break;
+ }
+ tsk_sprintf(&fmtp, "profile-level-id=%d", self->profile);
+ return fmtp;
+ }
+ else if(tsk_striequals(att_name, "imageattr")) {
+ return tmedia_get_video_imageattr(TMEDIA_CODEC_VIDEO(self)->pref_size,
+ TMEDIA_CODEC_VIDEO(self)->in.width, TMEDIA_CODEC_VIDEO(self)->in.height, TMEDIA_CODEC_VIDEO(self)->out.width, TMEDIA_CODEC_VIDEO(self)->out.height);
+ }
+ return tsk_null;
}
/* ============ Internal functions ================= */
int tdav_codec_mp4ves_open_encoder(tdav_codec_mp4ves_t* self)
{
- int ret, size;
- int32_t max_bw_kpbs;
- if(!self->encoder.codec && !(self->encoder.codec = avcodec_find_encoder(CODEC_ID_MPEG4))){
- TSK_DEBUG_ERROR("Failed to find mp4v encoder");
- return -1;
- }
-
- if(self->encoder.context){
- TSK_DEBUG_ERROR("Encoder already opened");
- 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)->in.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;
- self->encoder.context->noise_reduction = 250;
- self->encoder.context->flags |= CODEC_FLAG_QSCALE;
- self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality;
-
- 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
- self->encoder.context->rtp_payload_size = MP4V_RTP_PAYLOAD_SIZE;
- self->encoder.context->opaque = tsk_null;
- self->encoder.context->profile = self->profile>>4;
- self->encoder.context->level = self->profile & 0x0F;
- self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->in.fps * MP4V_GOP_SIZE_IN_SECONDS);
- self->encoder.context->max_b_frames = 0;
- self->encoder.context->b_frame_strategy = 1;
+ int ret, size;
+ int32_t max_bw_kpbs;
+ if(!self->encoder.codec && !(self->encoder.codec = avcodec_find_encoder(CODEC_ID_MPEG4))) {
+ TSK_DEBUG_ERROR("Failed to find mp4v encoder");
+ return -1;
+ }
+
+ if(self->encoder.context) {
+ TSK_DEBUG_ERROR("Encoder already opened");
+ 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)->in.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;
+ self->encoder.context->noise_reduction = 250;
+ self->encoder.context->flags |= CODEC_FLAG_QSCALE;
+ self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality;
+
+ 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
+ self->encoder.context->rtp_payload_size = MP4V_RTP_PAYLOAD_SIZE;
+ self->encoder.context->opaque = tsk_null;
+ self->encoder.context->profile = self->profile>>4;
+ self->encoder.context->level = self->profile & 0x0F;
+ self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->in.fps * MP4V_GOP_SIZE_IN_SECONDS);
+ self->encoder.context->max_b_frames = 0;
+ self->encoder.context->b_frame_strategy = 1;
self->encoder.context->flags |= CODEC_FLAG_AC_PRED;
- // Picture (YUV 420)
- if(!(self->encoder.picture = avcodec_alloc_frame())){
- TSK_DEBUG_ERROR("Failed to create MP4V-ES 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 MP4V-ES encoder buffer");
- return -2;
- }
-
- // Open encoder
- if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0){
- TSK_DEBUG_ERROR("Failed to open MP4V-ES encoder");
- return ret;
- }
-
- TSK_DEBUG_INFO("[MP4V-ES] bitrate=%d bps", self->encoder.context->bit_rate);
-
- return ret;
+ // Picture (YUV 420)
+ if(!(self->encoder.picture = avcodec_alloc_frame())) {
+ TSK_DEBUG_ERROR("Failed to create MP4V-ES 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 MP4V-ES encoder buffer");
+ return -2;
+ }
+
+ // Open encoder
+ if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0) {
+ TSK_DEBUG_ERROR("Failed to open MP4V-ES encoder");
+ return ret;
+ }
+
+ TSK_DEBUG_INFO("[MP4V-ES] bitrate=%d bps", self->encoder.context->bit_rate);
+
+ return ret;
}
int tdav_codec_mp4ves_open_decoder(tdav_codec_mp4ves_t* self)
{
- int ret, size;
-
- if(!self->decoder.codec && !(self->decoder.codec = avcodec_find_decoder(CODEC_ID_MPEG4))){
- TSK_DEBUG_ERROR("Failed to find MP4V-ES 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)->out.width;
- self->decoder.context->height = TMEDIA_CODEC_VIDEO(self)->out.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 MP4V-ES decoder");
- return ret;
- }
-
+ int ret, size;
+
+ if(!self->decoder.codec && !(self->decoder.codec = avcodec_find_decoder(CODEC_ID_MPEG4))) {
+ TSK_DEBUG_ERROR("Failed to find MP4V-ES 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)->out.width;
+ self->decoder.context->height = TMEDIA_CODEC_VIDEO(self)->out.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 MP4V-ES decoder");
+ return ret;
+ }
+
self->decoder.last_seq = 0;
- return ret;
+ return ret;
}
int tdav_codec_mp4ves_close_encoder(tdav_codec_mp4ves_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);
- }
- 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);
+ }
+ if(self->encoder.buffer) {
+ TSK_FREE(self->encoder.buffer);
+ }
+ return 0;
}
int tdav_codec_mp4ves_close_decoder(tdav_codec_mp4ves_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_mp4ves_encap(tdav_codec_mp4ves_t* mp4v, const uint8_t* pdata, tsk_size_t size)
{
- uint32_t scode; // start code
-
- if(size <= 4/*32bits: start code size*/){
- TSK_DEBUG_ERROR("Too short");
- return;
- }
- // first 32bits
- scode = tnet_htonl_2(pdata);
-
-/* RFC 3016 - 3.3 Examples of packetized MPEG-4 Visual bitstream
-
- VS= Visual Object Sequence
- VO= Visual Object
- VOL= Visual Object Layer
- VOP= Visual Object Plane
- GOV= Group of Visual Object Plane
- VP= Video Plane
-
- +------+------+------+------+
-(a) | RTP | VS | VO | VOL |
- |header|header|header|header|
- +------+------+------+------+
-
- +------+------+------+------+------------+
-(b) | RTP | VS | VO | VOL |Video Packet|
- |header|header|header|header| |
- +------+------+------+------+------------+
-
- +------+-----+------------------+
-(c) | RTP | GOV |Video Object Plane|
- |header| | |
- +------+-----+------------------+
-
- +------+------+------------+ +------+------+------------+
-(d) | RTP | VOP |Video Packet| | RTP | VP |Video Packet|
- |header|header| (1) | |header|header| (2) |
- +------+------+------------+ +------+------+------------+
-
- +------+------+------------+------+------------+------+------------+
-(e) | RTP | VP |Video Packet| VP |Video Packet| VP |Video Packet|
- |header|header| (1) |header| (2) |header| (3) |
- +------+------+------------+------+------------+------+------------+
-
- +------+------+------------+ +------+------------+
-(f) | RTP | VOP |VOP fragment| | RTP |VOP fragment|
- |header|header| (1) | |header| (2) | ___
- +------+------+------------+ +------+------------+
-
- Figure 2 - Examples of RTP packetized MPEG-4 Visual bitstream
-*/
-
-/* RFC 3016 - 3.2 Fragmentation of MPEG-4 Visual bitstream
-
- A fragmented MPEG-4 Visual bitstream is mapped directly onto the RTP
- payload without any addition of extra header fields or any removal of
- Visual syntax elements. The Combined Configuration/Elementary
- streams mode is used.
-
- In the following, header means one of the following:
-
- - Configuration information (Visual Object Sequence Header, Visual
- Object Header and Video Object Layer Header)
- - visual_object_sequence_end_code
- - The header of the entry point function for an elementary stream
- (Group_of_VideoObjectPlane() or the header of VideoObjectPlane(),
- video_plane_with_short_header(), MeshObject() or FaceObject())
- - The video packet header (video_packet_header() excluding
- next_resync_marker())
- - The header of gob_layer()
- See 6.2.1 "Start codes" of ISO/IEC 14496-2 [2][9][4] for the
- definition of the configuration information and the entry point
- functions.
-*/
-
- switch(scode){
- case visual_object_sequence_start_code:
- case visual_object_start_code:
- case user_data_start_code:
- case video_object_layer_start_code:
- case group_of_vop_start_code:
- case vop_start_code:
- {
- register uint32_t i, last_index = 0;
- int startcode = 0xffffffff;
-
- if(scode == visual_object_sequence_start_code && size >=5){
- //uint8_t profile_and_level_indication = pdata[4]; /* IEC 14496-2: 6.3.2 Visual Object Sequence and Visual Object */
- // TSK_DEBUG_INFO("profile_and_level_indication=%d", profile_and_level_indication);
- }
-
- if(size < MP4V_RTP_PAYLOAD_SIZE){
- goto last;
- }
-
- for(i = 4; i<(size - 4); i++){
- startcode = (startcode <<8) | pdata[i];
- switch(startcode){
- case visual_object_sequence_start_code:
- case group_of_vop_start_code:
- case vop_start_code:
- tdav_codec_mp4ves_rtp_callback(mp4v, pdata + last_index, (i - last_index), (last_index == size));
- last_index = i;
- }
- }
+ uint32_t scode; // start code
+
+ if(size <= 4/*32bits: start code size*/) {
+ TSK_DEBUG_ERROR("Too short");
+ return;
+ }
+ // first 32bits
+ scode = tnet_htonl_2(pdata);
+
+ /* RFC 3016 - 3.3 Examples of packetized MPEG-4 Visual bitstream
+
+ VS= Visual Object Sequence
+ VO= Visual Object
+ VOL= Visual Object Layer
+ VOP= Visual Object Plane
+ GOV= Group of Visual Object Plane
+ VP= Video Plane
+
+ +------+------+------+------+
+ (a) | RTP | VS | VO | VOL |
+ |header|header|header|header|
+ +------+------+------+------+
+
+ +------+------+------+------+------------+
+ (b) | RTP | VS | VO | VOL |Video Packet|
+ |header|header|header|header| |
+ +------+------+------+------+------------+
+
+ +------+-----+------------------+
+ (c) | RTP | GOV |Video Object Plane|
+ |header| | |
+ +------+-----+------------------+
+
+ +------+------+------------+ +------+------+------------+
+ (d) | RTP | VOP |Video Packet| | RTP | VP |Video Packet|
+ |header|header| (1) | |header|header| (2) |
+ +------+------+------------+ +------+------+------------+
+
+ +------+------+------------+------+------------+------+------------+
+ (e) | RTP | VP |Video Packet| VP |Video Packet| VP |Video Packet|
+ |header|header| (1) |header| (2) |header| (3) |
+ +------+------+------------+------+------------+------+------------+
+
+ +------+------+------------+ +------+------------+
+ (f) | RTP | VOP |VOP fragment| | RTP |VOP fragment|
+ |header|header| (1) | |header| (2) | ___
+ +------+------+------------+ +------+------------+
+
+ Figure 2 - Examples of RTP packetized MPEG-4 Visual bitstream
+ */
+
+ /* RFC 3016 - 3.2 Fragmentation of MPEG-4 Visual bitstream
+
+ A fragmented MPEG-4 Visual bitstream is mapped directly onto the RTP
+ payload without any addition of extra header fields or any removal of
+ Visual syntax elements. The Combined Configuration/Elementary
+ streams mode is used.
+
+ In the following, header means one of the following:
+
+ - Configuration information (Visual Object Sequence Header, Visual
+ Object Header and Video Object Layer Header)
+ - visual_object_sequence_end_code
+ - The header of the entry point function for an elementary stream
+ (Group_of_VideoObjectPlane() or the header of VideoObjectPlane(),
+ video_plane_with_short_header(), MeshObject() or FaceObject())
+ - The video packet header (video_packet_header() excluding
+ next_resync_marker())
+ - The header of gob_layer()
+ See 6.2.1 "Start codes" of ISO/IEC 14496-2 [2][9][4] for the
+ definition of the configuration information and the entry point
+ functions.
+ */
+
+ switch(scode) {
+ case visual_object_sequence_start_code:
+ case visual_object_start_code:
+ case user_data_start_code:
+ case video_object_layer_start_code:
+ case group_of_vop_start_code:
+ case vop_start_code: {
+ register uint32_t i, last_index = 0;
+ int startcode = 0xffffffff;
+
+ if(scode == visual_object_sequence_start_code && size >=5) {
+ //uint8_t profile_and_level_indication = pdata[4]; /* IEC 14496-2: 6.3.2 Visual Object Sequence and Visual Object */
+ // TSK_DEBUG_INFO("profile_and_level_indication=%d", profile_and_level_indication);
+ }
+
+ if(size < MP4V_RTP_PAYLOAD_SIZE) {
+ goto last;
+ }
+
+ for(i = 4; i<(size - 4); i++) {
+ startcode = (startcode <<8) | pdata[i];
+ switch(startcode) {
+ case visual_object_sequence_start_code:
+ case group_of_vop_start_code:
+ case vop_start_code:
+ tdav_codec_mp4ves_rtp_callback(mp4v, pdata + last_index, (i - last_index), (last_index == size));
+ last_index = i;
+ }
+ }
last:
- if(last_index < size){
- tdav_codec_mp4ves_rtp_callback(mp4v, pdata + last_index, (size - last_index), tsk_true);
- }
- break;
- }
- default:
- TSK_DEBUG_ERROR("%x is an invalide start code", scode);
- break;
- }
+ if(last_index < size) {
+ tdav_codec_mp4ves_rtp_callback(mp4v, pdata + last_index, (size - last_index), tsk_true);
+ }
+ break;
+ }
+ default:
+ TSK_DEBUG_ERROR("%x is an invalide start code", scode);
+ break;
+ }
}
static void tdav_codec_mp4ves_rtp_callback(tdav_codec_mp4ves_t *mp4v, const void *data, tsk_size_t size, tsk_bool_t marker)
{
- // Send data over the network
- if(TMEDIA_CODEC_VIDEO(mp4v)->out.callback){
- TMEDIA_CODEC_VIDEO(mp4v)->out.result.buffer.ptr = data;
- TMEDIA_CODEC_VIDEO(mp4v)->out.result.buffer.size = size;
- TMEDIA_CODEC_VIDEO(mp4v)->out.result.duration = (uint32_t)((1./(double)TMEDIA_CODEC_VIDEO(mp4v)->out.fps) * TMEDIA_CODEC(mp4v)->plugin->rate);
- TMEDIA_CODEC_VIDEO(mp4v)->out.result.last_chunck = marker;
- TMEDIA_CODEC_VIDEO(mp4v)->out.callback(&TMEDIA_CODEC_VIDEO(mp4v)->out.result);
- }
+ // Send data over the network
+ if(TMEDIA_CODEC_VIDEO(mp4v)->out.callback) {
+ TMEDIA_CODEC_VIDEO(mp4v)->out.result.buffer.ptr = data;
+ TMEDIA_CODEC_VIDEO(mp4v)->out.result.buffer.size = size;
+ TMEDIA_CODEC_VIDEO(mp4v)->out.result.duration = (uint32_t)((1./(double)TMEDIA_CODEC_VIDEO(mp4v)->out.fps) * TMEDIA_CODEC(mp4v)->plugin->rate);
+ TMEDIA_CODEC_VIDEO(mp4v)->out.result.last_chunck = marker;
+ TMEDIA_CODEC_VIDEO(mp4v)->out.callback(&TMEDIA_CODEC_VIDEO(mp4v)->out.result);
+ }
}
@@ -748,70 +743,68 @@ static void tdav_codec_mp4ves_rtp_callback(tdav_codec_mp4ves_t *mp4v, const void
/* constructor */
static tsk_object_t* tdav_codec_mp4ves_ctor(tsk_object_t * _self, va_list * app)
{
- tdav_codec_mp4ves_t *self = _self;
- if(self){
- /* init base: called by tmedia_codec_create() */
- /* init self */
- self->profile = DEFAULT_PROFILE_LEVEL_ID;
- self->encoder.quality = 1;
- self->encoder.max_bw_kpbs = tmedia_defaults_get_bandwidth_video_upload_max();
- }
- return self;
+ tdav_codec_mp4ves_t *self = _self;
+ if(self) {
+ /* init base: called by tmedia_codec_create() */
+ /* init self */
+ self->profile = DEFAULT_PROFILE_LEVEL_ID;
+ self->encoder.quality = 1;
+ self->encoder.max_bw_kpbs = tmedia_defaults_get_bandwidth_video_upload_max();
+ }
+ return self;
}
/* destructor */
static tsk_object_t* tdav_codec_mp4ves_dtor(tsk_object_t * _self)
-{
- tdav_codec_mp4ves_t *self = _self;
- if(self){
- /* deinit base */
- tmedia_codec_video_deinit(self); // will close the codec if opened
- /* deinit self */
- TSK_FREE(self->rtp.ptr);
- self->rtp.size = 0;
- }
-
- return self;
+{
+ tdav_codec_mp4ves_t *self = _self;
+ if(self) {
+ /* deinit base */
+ tmedia_codec_video_deinit(self); // will close the codec if opened
+ /* deinit self */
+ TSK_FREE(self->rtp.ptr);
+ self->rtp.size = 0;
+ }
+
+ return self;
}
/* object definition */
-static const tsk_object_def_t tdav_codec_mp4ves_def_s =
-{
- sizeof(tdav_codec_mp4ves_t),
- tdav_codec_mp4ves_ctor,
- tdav_codec_mp4ves_dtor,
- tmedia_codec_cmp,
+static const tsk_object_def_t tdav_codec_mp4ves_def_s = {
+ sizeof(tdav_codec_mp4ves_t),
+ tdav_codec_mp4ves_ctor,
+ tdav_codec_mp4ves_dtor,
+ tmedia_codec_cmp,
};
/* plugin definition*/
-static const tmedia_codec_plugin_def_t tdav_codec_mp4ves_plugin_def_s =
-{
- &tdav_codec_mp4ves_def_s,
-
- tmedia_video,
- tmedia_codec_id_mp4ves_es,
- "MP4V-ES",
- "MP4V-ES Codec",
- TMEDIA_CODEC_FORMAT_MP4V_ES,
- tsk_true,
- 90000, // rate
-
- /* audio */
- { 0 },
-
- /* video (width, height, fps) */
- {176, 144, 0},// fps is @deprecated
-
- tdav_codec_mp4ves_set,
- tdav_codec_mp4ves_open,
- tdav_codec_mp4ves_close,
- tdav_codec_mp4ves_encode,
- tdav_codec_mp4ves_decode,
- tdav_codec_mp4ves_sdp_att_match,
- tdav_codec_mp4ves_sdp_att_get
+static const tmedia_codec_plugin_def_t tdav_codec_mp4ves_plugin_def_s = {
+ &tdav_codec_mp4ves_def_s,
+
+ tmedia_video,
+ tmedia_codec_id_mp4ves_es,
+ "MP4V-ES",
+ "MP4V-ES Codec",
+ TMEDIA_CODEC_FORMAT_MP4V_ES,
+ tsk_true,
+ 90000, // rate
+
+ /* audio */
+ { 0 },
+
+ /* video (width, height, fps) */
+ {176, 144, 0},// fps is @deprecated
+
+ tdav_codec_mp4ves_set,
+ tdav_codec_mp4ves_open,
+ tdav_codec_mp4ves_close,
+ tdav_codec_mp4ves_encode,
+ tdav_codec_mp4ves_decode,
+ tdav_codec_mp4ves_sdp_att_match,
+ tdav_codec_mp4ves_sdp_att_get
};
const tmedia_codec_plugin_def_t *tdav_codec_mp4ves_plugin_def_t = &tdav_codec_mp4ves_plugin_def_s;
tsk_bool_t tdav_codec_ffmpeg_mp4ves_is_supported()
{
- return (avcodec_find_encoder(CODEC_ID_MPEG4) && avcodec_find_decoder(CODEC_ID_MPEG4));
+ return (avcodec_find_encoder(CODEC_ID_MPEG4) && avcodec_find_decoder(CODEC_ID_MPEG4));
}
#endif /* HAVE_FFMPEG */
OpenPOWER on IntegriCloud