diff options
Diffstat (limited to 'branches/1.0/tinyDAV/src/codecs/h264')
-rw-r--r-- | branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264.c | 871 | ||||
-rw-r--r-- | branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264_rtp.c | 356 |
2 files changed, 0 insertions, 1227 deletions
diff --git a/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264.c b/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264.c deleted file mode 100644 index 1f4be60..0000000 --- a/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264.c +++ /dev/null @@ -1,871 +0,0 @@ -/* -* Copyright (C) 2009-2010 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. -* -*/ - -/**@file tdav_codec_h264.c - * @brief H.264 codec plugin - * RTP payloader/depayloader follows RFC 3984 - * - * @author Mamadou Diop <diopmamadou(at)doubango.org> - * - * @date Created: Sat Nov 8 16:54:58 2009 mdiop - */ -#include "tinydav/codecs/h264/tdav_codec_h264.h" - -#if HAVE_FFMPEG && (!defined(HAVE_H264) || HAVE_H264) - -#include "tinydav/codecs/h264/tdav_codec_h264_rtp.h" -#include "tinydav/video/tdav_converter_video.h" - -#include "tinyrtp/rtp/trtp_rtp_packet.h" - -#include "tsk_params.h" -#include "tsk_memory.h" -#include "tsk_debug.h" - -#define H264_PACKETIZATION_MODE Non_Interleaved_Mode -#define H264_MAX_BR 452 -#define H264_MAX_MBPS 11880 - -int tdav_codec_h264_init(tdav_codec_h264_t* self, tdav_codec_h264_profile_t profile); -int tdav_codec_h264_deinit(tdav_codec_h264_t* self); -tdav_codec_h264_profile_t tdav_codec_h264_get_profile(const char* fmtp); - -static void tdav_codec_h264_encap(const tdav_codec_h264_t* h264, const uint8_t* pdata, tsk_size_t size); - -/* ============ H.264 Base Profile X.X Plugin interface functions ================= */ - -#define tdav_codec_h264_fmtp_set tsk_null /* FIXME: should be removed from all plugins (useless) */ - -int tdav_codec_h264_open(tmedia_codec_t* self) -{ - int ret; - int size; - float bitRate; - - tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; - - if(!h264){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* the caller (base class) already checked that the codec is not opened */ - - - // - // Encoder - // - h264->encoder.context = avcodec_alloc_context(); - avcodec_get_context_defaults(h264->encoder.context); - -#if TDAV_UNDER_WINDOWS - h264->encoder.context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); -#endif - - h264->encoder.context->pix_fmt = PIX_FMT_YUV420P; - h264->encoder.context->time_base.num = 1; - h264->encoder.context->time_base.den = TMEDIA_CODEC_VIDEO(h264)->fps; - h264->encoder.context->width = TMEDIA_CODEC_VIDEO(h264)->width; - h264->encoder.context->height = TMEDIA_CODEC_VIDEO(h264)->height; - - h264->encoder.context->rc_lookahead = 0; - - //h264->encoder.context->refs = 1; - h264->encoder.context->scenechange_threshold = 0; - h264->encoder.context->me_subpel_quality = 0; - h264->encoder.context->partitions = X264_PART_I4X4 | X264_PART_I8X8 | X264_PART_P8X8 | X264_PART_B8X8; - h264->encoder.context->me_method = ME_EPZS; - h264->encoder.context->trellis = 0; - - h264->encoder.context->me_range = 16; - h264->encoder.context->max_qdiff = 4; - h264->encoder.context->mb_qmin = h264->encoder.context->qmin = 10; - h264->encoder.context->mb_qmax = h264->encoder.context->qmax = 51; - h264->encoder.context->qcompress = 0.6f; - h264->encoder.context->mb_decision = FF_MB_DECISION_SIMPLE; - h264->encoder.context->flags2 |= CODEC_FLAG2_FASTPSKIP; - h264->encoder.context->flags |= CODEC_FLAG_LOOP_FILTER; - h264->encoder.context->flags |= CODEC_FLAG_GLOBAL_HEADER; - h264->encoder.context->max_b_frames = 0; - h264->encoder.context->b_frame_strategy = 1; - h264->encoder.context->chromaoffset = 0; - - switch(h264->profile){ - case tdav_codec_h264_bp10: - default: - h264->encoder.context->profile = FF_PROFILE_H264_BASELINE; - h264->encoder.context->level = 10; - bitRate = 128000.f; - break; - case tdav_codec_h264_bp20: - h264->encoder.context->profile = FF_PROFILE_H264_BASELINE; - h264->encoder.context->level = 20; - bitRate = 491400.f; - break; - case tdav_codec_h264_bp30: - h264->encoder.context->profile = FF_PROFILE_H264_BASELINE; - h264->encoder.context->level = 30; - bitRate = 2725300.f; - break; - } - - h264->encoder.context->crf = 22; - h264->encoder.context->thread_count = 0; - h264->encoder.context->rtp_payload_size = H264_RTP_PAYLOAD_SIZE; - h264->encoder.context->opaque = tsk_null; - //h264->encoder.context->bit_rate = (int) (bitRate * 0.80f); - //h264->encoder.context->bit_rate_tolerance = (int) (bitRate * 0.20f); - h264->encoder.context->gop_size = TMEDIA_CODEC_VIDEO(h264)->fps*4; // Each 4 second(s) - - - // Picture (YUV 420) - if(!(h264->encoder.picture = avcodec_alloc_frame())){ - TSK_DEBUG_ERROR("Failed to create encoder picture"); - return -2; - } - avcodec_get_frame_defaults(h264->encoder.picture); - - - size = avpicture_get_size(PIX_FMT_YUV420P, h264->encoder.context->width, h264->encoder.context->height); - if(!(h264->encoder.buffer = tsk_calloc(size, sizeof(uint8_t)))){ - TSK_DEBUG_ERROR("Failed to allocate encoder buffer"); - return -2; - } - - // Open encoder - if((ret = avcodec_open(h264->encoder.context, h264->encoder.codec)) < 0){ - TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(h264)->plugin->desc); - return ret; - } - - // - // Decoder - // - h264->decoder.context = avcodec_alloc_context(); - avcodec_get_context_defaults(h264->decoder.context); - - h264->decoder.context->pix_fmt = PIX_FMT_YUV420P; - h264->decoder.context->flags2 |= CODEC_FLAG2_FAST; - h264->decoder.context->width = TMEDIA_CODEC_VIDEO(h264)->width; - h264->decoder.context->height = TMEDIA_CODEC_VIDEO(h264)->height; - -#if TDAV_UNDER_WINDOWS - h264->decoder.context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); -#endif - - // Picture (YUV 420) - if(!(h264->decoder.picture = avcodec_alloc_frame())){ - TSK_DEBUG_ERROR("Failed to create decoder picture"); - return -2; - } - avcodec_get_frame_defaults(h264->decoder.picture); - - size = avpicture_get_size(PIX_FMT_YUV420P, h264->decoder.context->width, h264->decoder.context->height); - if(!(h264->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(h264->decoder.context, h264->decoder.codec)) < 0){ - TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(h264)->plugin->desc); - return ret; - } - - return 0; -} - -int tdav_codec_h264_close(tmedia_codec_t* self) -{ - tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; - - if(!h264){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - /* the caller (base class) already checked that the codec is opened */ - - // - // Encoder - // - if(h264->encoder.context){ - avcodec_close(h264->encoder.context); - av_free(h264->encoder.context); - } - if(h264->encoder.picture){ - av_free(h264->encoder.picture); - } - if(h264->encoder.buffer){ - TSK_FREE(h264->encoder.buffer); - } - - // - // Decoder - // - if(h264->decoder.context){ - avcodec_close(h264->decoder.context); - av_free(h264->decoder.context); - } - if(h264->decoder.picture){ - av_free(h264->decoder.picture); - } - if(h264->decoder.accumulator){ - TSK_FREE(h264->decoder.accumulator); - h264->decoder.accumulator_pos = 0; - } - - return 0; -} - -tsk_size_t tdav_codec_h264_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 = 0; - int size; - - tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; - - if(!self || !in_data || !in_size || !out_data){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - if(!self->opened){ - TSK_DEBUG_ERROR("Codec not opened"); - return 0; - } - - // wrap yuv420 buffer - size = avpicture_fill((AVPicture *)h264->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, h264->encoder.context->width, h264->encoder.context->height); - if(size != in_size){ - /* guard */ - TSK_DEBUG_ERROR("Invalid size"); - return 0; - } - /* Flip */ -#if FLIP_ENCODED_PICT - tdav_converter_video_flip(h264->encoder.picture, h264->encoder.context->height); -#endif - - if((h264->encoder.frame_count < (int)TMEDIA_CODEC_VIDEO(h264)->fps*3) - && ((h264->encoder.frame_count++%TMEDIA_CODEC_VIDEO(h264)->fps)==0)){ - - // You must patch FFmpeg to switch from X264_TYPE_AUTO to X264_TYPE_IDR - h264->encoder.picture->pict_type = FF_I_TYPE; - tdav_codec_h264_encap(h264, h264->encoder.context->extradata, (tsk_size_t)h264->encoder.context->extradata_size); - } - else{ - // Encode data - h264->encoder.picture->pts = AV_NOPTS_VALUE; - ret = avcodec_encode_video(h264->encoder.context, h264->encoder.buffer, size, h264->encoder.picture); - if(ret >0){ - tdav_codec_h264_encap(h264, h264->encoder.buffer, (tsk_size_t)ret); - } - h264->encoder.picture->pict_type = 0;//reset - } - - return 0; -} - -tsk_size_t tdav_codec_h264_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_h264_t* h264 = (tdav_codec_h264_t*)self; - const trtp_rtp_header_t* rtp_hdr = proto_hdr; - - const uint8_t* pay_ptr = tsk_null; - tsk_size_t pay_size = 0; - int ret; - tsk_bool_t append_scp; - tsk_size_t xsize, retsize = 0; - int got_picture_ptr; - - if(!h264 || !in_data || !in_size || !out_data || !h264->decoder.context){ - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - //TSK_DEBUG_INFO("SeqNo=%hu", rtp_hdr->seq_num); - - /* Packet lost? */ - if(h264->decoder.last_seq != (rtp_hdr->seq_num - 1) && h264->decoder.last_seq){ - if(h264->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); - } - h264->decoder.last_seq = rtp_hdr->seq_num; - - - /* 5.3. NAL Unit Octet Usage - +---------------+ - |0|1|2|3|4|5|6|7| - +-+-+-+-+-+-+-+-+ - |F|NRI| Type | - +---------------+ - */ - if(*((uint8_t*)in_data) >> 7){ - TSK_DEBUG_WARN("F=1"); - /* reset accumulator */ - h264->decoder.accumulator = 0; - return 0; - } - - /* get payload */ - if((ret = tdav_codec_h264_get_pay(in_data, in_size, (const void**)&pay_ptr, &pay_size, &append_scp)) || !pay_ptr || !pay_size){ - TSK_DEBUG_ERROR("Depayloader failed to get H.264 content"); - return 0; - } - xsize = avpicture_get_size(h264->decoder.context->pix_fmt, h264->decoder.context->width, h264->decoder.context->height); - - if((int)(h264->decoder.accumulator_pos + pay_size) <= xsize){ - if(append_scp){ - memcpy(&((uint8_t*)h264->decoder.accumulator)[h264->decoder.accumulator_pos], H264_START_CODE_PREFIX, sizeof(H264_START_CODE_PREFIX)); - h264->decoder.accumulator_pos += sizeof(H264_START_CODE_PREFIX); - } - - memcpy(&((uint8_t*)h264->decoder.accumulator)[h264->decoder.accumulator_pos], pay_ptr, pay_size); - h264->decoder.accumulator_pos += pay_size; - } - else{ - TSK_DEBUG_WARN("Buffer overflow"); - h264->decoder.accumulator_pos = 0; - return 0; - } - - if(rtp_hdr->marker){ - AVPacket packet; - - - /* decode the picture */ - av_init_packet(&packet); - packet.size = h264->decoder.accumulator_pos; - packet.data = h264->decoder.accumulator; - ret = avcodec_decode_video2(h264->decoder.context, h264->decoder.picture, &got_picture_ptr, &packet); - - if(ret <0){ - TSK_DEBUG_ERROR("=============Failed to decode the buffer"); - } - else if(got_picture_ptr){ -#if FLIP_DECODED_PICT - tdav_converter_video_flip(h264->decoder.picture, h264->decoder.context->height); -#endif - /* fill out */ - if(*out_max_size<xsize){ - if((*out_data = tsk_realloc(*out_data, xsize))){ - *out_max_size = xsize; - } - else{ - *out_max_size = 0; - return 0; - } - } - retsize = xsize; - avpicture_layout((AVPicture *)h264->decoder.picture, h264->decoder.context->pix_fmt, h264->decoder.context->width, h264->decoder.context->height, - *out_data, retsize); - } - h264->decoder.accumulator_pos = 0; - } - - return retsize; -} - -tsk_bool_t tdav_codec_h264_fmtp_match(const tmedia_codec_t* codec, const char* fmtp) -{ - tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)codec; - tsk_params_L_t* params = tsk_null; - int val_int; - const char* val_str; - tsk_bool_t ret = tsk_true; - tdav_codec_h264_profile_t profile; - - if(!h264){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_false; - } - - TSK_DEBUG_INFO("Trying to match [%s]", fmtp); - - /* Check whether the profile match (If the profile is missing, then we consider that it's ok) */ - if(((profile = tdav_codec_h264_get_profile(fmtp)) != tdav_codec_h264_bp99) && (profile != h264->profile)){ - TSK_DEBUG_INFO("Profile not matching"); - return tsk_false; - } - - /* e.g. profile-level-id=42e00a; packetization-mode=1; max-br=452; max-mbps=11880 */ - if((params = tsk_params_fromstring(fmtp, ";", tsk_true))){ - - /* === max-br ===*/ - if((val_int = tsk_params_get_param_value_as_int(params, "max-br")) != -1){ - // should compare "max-br"? - TMEDIA_CODEC_VIDEO(h264)->max_br = val_int*1000; - } - - /* === max-mbps ===*/ - if((val_int = tsk_params_get_param_value_as_int(params, "max-mbps")) != -1){ - // should compare "max-mbps"? - TMEDIA_CODEC_VIDEO(h264)->max_mbps = val_int*1000; - } - - /* === packetization-mode ===*/ - if((val_int = tsk_params_get_param_value_as_int(params, "packetization-mode")) != -1){ - if((packetization_mode_t)val_int == Single_NAL_Unit_Mode || (packetization_mode_t)val_int == Non_Interleaved_Mode){ - h264->pack_mode = (packetization_mode_t)val_int; - } - else{ - TSK_DEBUG_INFO("packetization-mode not matching"); - ret = tsk_false; - goto bail; - } - } - - /* === profile-level-id ===*/ - if((val_str = tsk_params_get_param_value(params, "profile-level-id"))){ - level_idc_t l_idc; - /* profile-idc and level-idc already tested by tdav_codec_h264_get_profile() */ - tdav_codec_h264_parse_profile(val_str, tsk_null, tsk_null, &l_idc); - switch(l_idc){ - case level_idc_1_0: - case level_idc_1_b: - case level_idc_1_1: - TMEDIA_CODEC_VIDEO(h264)->width = 176, TMEDIA_CODEC_VIDEO(h264)->height = 144; - break; - default: - TMEDIA_CODEC_VIDEO(h264)->width = 352, TMEDIA_CODEC_VIDEO(h264)->height = 288; - //TMEDIA_CODEC_VIDEO(h264)->width = 704, TMEDIA_CODEC_VIDEO(h264)->height = 480; - break; - } - } - } - -bail: - TSK_OBJECT_SAFE_FREE(params); - return ret; -} - -char* tdav_codec_h264_fmtp_get(const tmedia_codec_t* self) -{ - tdav_codec_h264_t* h264 = (tdav_codec_h264_t*)self; - char* fmtp = tsk_null; - - if(!h264){ - TSK_DEBUG_ERROR("Invalid parameter"); - return tsk_null; - } - - switch(h264->profile){ - case tdav_codec_h264_bp10: - fmtp = tsk_strdup("profile-level-id=42e00a"); - break; - case tdav_codec_h264_bp20: - fmtp = tsk_strdup("profile-level-id=42e014"); - break; - case tdav_codec_h264_bp30: - fmtp = tsk_strdup("profile-level-id=42e01e"); - break; - } - - if(fmtp){ - tsk_strcat_2(&fmtp, "; packetization-mode=%d; max-br=%d; max-mbps=%d", - h264->pack_mode, TMEDIA_CODEC_VIDEO(h264)->max_br/1000, TMEDIA_CODEC_VIDEO(h264)->max_mbps/1000); - } - - return fmtp; -} - - - - -/* ============ H.264 Base Profile 1.0 Plugin interface ================= */ - -/* constructor */ -static tsk_object_t* tdav_codec_h264_bp10_ctor(tsk_object_t * self, va_list * app) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* init base: called by tmedia_codec_create() */ - /* init self */ - tdav_codec_h264_init(h264, tdav_codec_h264_bp10); - } - return self; -} -/* destructor */ -static tsk_object_t* tdav_codec_h264_bp10_dtor(tsk_object_t * self) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* deinit base */ - tmedia_codec_video_deinit(self); - /* deinit self */ - tdav_codec_h264_deinit(h264); - - } - - return self; -} -/* object definition */ -static const tsk_object_def_t tdav_codec_h264_bp10_def_s = -{ - sizeof(tdav_codec_h264_t), - tdav_codec_h264_bp10_ctor, - tdav_codec_h264_bp10_dtor, - tmedia_codec_cmp, -}; -/* plugin definition*/ -static const tmedia_codec_plugin_def_t tdav_codec_h264_bp10_plugin_def_s = -{ - &tdav_codec_h264_bp10_def_s, - - tmedia_video, - "H264", - "H264 Base Profile 1.0", - TMEDIA_CODEC_FORMAT_H264_BP10, - tsk_true, - 90000, // rate - - /* audio */ - { 0 }, - - /* video */ - {176, 144, 15}, - - tdav_codec_h264_open, - tdav_codec_h264_close, - tdav_codec_h264_encode, - tdav_codec_h264_decode, - tdav_codec_h264_fmtp_match, - tdav_codec_h264_fmtp_get, - tdav_codec_h264_fmtp_set -}; -const tmedia_codec_plugin_def_t *tdav_codec_h264_bp10_plugin_def_t = &tdav_codec_h264_bp10_plugin_def_s; - - -/* ============ H.264 Base Profile 2.0 Plugin interface ================= */ - -/* constructor */ -static tsk_object_t* tdav_codec_h264_bp20_ctor(tsk_object_t * self, va_list * app) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* init base: called by tmedia_codec_create() */ - /* init self */ - tdav_codec_h264_init(h264, tdav_codec_h264_bp20); - } - return self; -} -/* destructor */ -static tsk_object_t* tdav_codec_h264_bp20_dtor(tsk_object_t * self) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* deinit base */ - tmedia_codec_video_deinit(self); - /* deinit self */ - tdav_codec_h264_deinit(h264); - - } - - return self; -} -/* object definition */ -static const tsk_object_def_t tdav_codec_h264_bp20_def_s = -{ - sizeof(tdav_codec_h264_t), - tdav_codec_h264_bp20_ctor, - tdav_codec_h264_bp20_dtor, - tmedia_codec_cmp, -}; -/* plugin definition*/ -static const tmedia_codec_plugin_def_t tdav_codec_h264_bp20_plugin_def_s = -{ - &tdav_codec_h264_bp20_def_s, - - tmedia_video, - "H264", - "H264 Base Profile 2.0", - TMEDIA_CODEC_FORMAT_H264_BP20, - tsk_true, - 90000, // rate - - /* audio */ - { 0 }, - - /* video */ - {352, 288, 15}, - - tdav_codec_h264_open, - tdav_codec_h264_close, - tdav_codec_h264_encode, - tdav_codec_h264_decode, - tdav_codec_h264_fmtp_match, - tdav_codec_h264_fmtp_get, - tdav_codec_h264_fmtp_set -}; -const tmedia_codec_plugin_def_t *tdav_codec_h264_bp20_plugin_def_t = &tdav_codec_h264_bp20_plugin_def_s; - - -/* ============ H.264 Base Profile 3.0 Plugin interface ================= */ - -/* constructor */ -static tsk_object_t* tdav_codec_h264_bp30_ctor(tsk_object_t * self, va_list * app) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* init base: called by tmedia_codec_create() */ - /* init self */ - tdav_codec_h264_init(h264, tdav_codec_h264_bp30); - } - return self; -} -/* destructor */ -static tsk_object_t* tdav_codec_h264_bp30_dtor(tsk_object_t * self) -{ - tdav_codec_h264_t *h264 = self; - if(h264){ - /* deinit base */ - tmedia_codec_video_deinit(self); - /* deinit self */ - tdav_codec_h264_deinit(h264); - - } - - return self; -} -/* object definition */ -static const tsk_object_def_t tdav_codec_h264_bp30_def_s = -{ - sizeof(tdav_codec_h264_t), - tdav_codec_h264_bp30_ctor, - tdav_codec_h264_bp30_dtor, - tmedia_codec_cmp, -}; -/* plugin definition*/ -static const tmedia_codec_plugin_def_t tdav_codec_h264_bp30_plugin_def_s = -{ - &tdav_codec_h264_bp30_def_s, - - tmedia_video, - "H264", - "H264 Base Profile 3.0", - TMEDIA_CODEC_FORMAT_H264_BP30, - tsk_true, - 90000, // rate - - /* audio */ - { 0 }, - - /* video */ - {352, 288, 15}, - - tdav_codec_h264_open, - tdav_codec_h264_close, - tdav_codec_h264_encode, - tdav_codec_h264_decode, - tdav_codec_h264_fmtp_match, - tdav_codec_h264_fmtp_get, - tdav_codec_h264_fmtp_set -}; -const tmedia_codec_plugin_def_t *tdav_codec_h264_bp30_plugin_def_t = &tdav_codec_h264_bp30_plugin_def_s; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/* ============ Common To all H264 codecs ================= */ - -int tdav_codec_h264_init(tdav_codec_h264_t* self, tdav_codec_h264_profile_t profile) -{ - int ret = 0; - - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - self->pack_mode = H264_PACKETIZATION_MODE; - self->profile = profile; - TMEDIA_CODEC_VIDEO(self)->max_mbps = H264_MAX_MBPS*1000; - TMEDIA_CODEC_VIDEO(self)->max_br = H264_MAX_BR*1000; - - // At this time self->plugin is Null - TMEDIA_CODEC_VIDEO(self)->width = 176; - TMEDIA_CODEC_VIDEO(self)->height = 144; - TMEDIA_CODEC_VIDEO(self)->fps = 15; - - if(!(self->encoder.codec = avcodec_find_encoder(CODEC_ID_H264))){ - TSK_DEBUG_ERROR("Failed to find H.264 encoder"); - ret = -2; - } - - if(!(self->decoder.codec = avcodec_find_decoder(CODEC_ID_H264))){ - TSK_DEBUG_ERROR("Failed to find H.264 decoder"); - ret = -3; - } - - /* allocations MUST be done by open() */ - return ret; -} - -int tdav_codec_h264_deinit(tdav_codec_h264_t* self) -{ - if(!self){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - self->encoder.codec = tsk_null; - self->decoder.codec = tsk_null; - - // FFMpeg resources are destroyed by close() - - - TSK_FREE(self->rtp.ptr); - self->rtp.size = 0; - - return 0; -} - -tdav_codec_h264_profile_t tdav_codec_h264_get_profile(const char* fmtp) -{ - tdav_codec_h264_profile_t profile = tdav_codec_h264_bp99; - tsk_size_t size = tsk_strlen(fmtp); - int start, end; - - if((start = tsk_strindexOf(fmtp, size, "profile-level-id")) !=-1){ - tsk_param_t* param; - if((end = tsk_strindexOf((fmtp+start), (size-start), ";")) == -1){ - end = size; - } - - if((param = tsk_params_parse_param((fmtp+start), (end-start)))){ - profile_idc_t p_idc; - level_idc_t l_idc; - if(param->value){ - tsk_strtrim_both(¶m->value); - } - - tdav_codec_h264_parse_profile(param->value, &p_idc, tsk_null, &l_idc); - - switch(p_idc){ - case profile_idc_baseline: - switch(l_idc){ - case level_idc_1_0: - case level_idc_1_b: - case level_idc_1_1: - case level_idc_1_2: - case level_idc_1_3: - profile = tdav_codec_h264_bp10; - break; - case level_idc_2_0: - case level_idc_2_1: - case level_idc_2_2: - profile = tdav_codec_h264_bp20; - break; - case level_idc_3_0: - profile = tdav_codec_h264_bp30; - break; - } - break; - case profile_idc_extended: - case profile_idc_main: - case profile_idc_high: - default: - /* Not supported */ - break; - } - - TSK_OBJECT_SAFE_FREE(param); - } - } - return profile; -} - -static void tdav_codec_h264_encap(const tdav_codec_h264_t* h264, const uint8_t* pdata, tsk_size_t size) -{ - register uint32_t i; - uint32_t last_scp, prev_scp; - static uint32_t size_of_scp = sizeof(H264_START_CODE_PREFIX); /* we know it's equal to 4 ..but */ - - if(!pdata || !size){ - return; - } - - last_scp = 0, prev_scp = 0; -/* -#if 1 - if(size < H264_RTP_PAYLOAD_SIZE){ - goto last; - } -#else - goto last; -#endif -*/ - for(i = size_of_scp; i<(size - size_of_scp); i++){ - if(pdata[i] == H264_START_CODE_PREFIX[0] && pdata[i+1] == H264_START_CODE_PREFIX[1] && pdata[i+2] == H264_START_CODE_PREFIX[2] && pdata[i+3] == H264_START_CODE_PREFIX[3]){ /* Found Start Code Prefix */ - prev_scp = last_scp; - if((i - last_scp) >= H264_RTP_PAYLOAD_SIZE || 1){ - tdav_codec_h264_rtp_callback((tdav_codec_h264_t*) h264, pdata + prev_scp, - (i - prev_scp), (prev_scp == size)); - } - last_scp = i; - } - } -//last: - if(last_scp < size){ - tdav_codec_h264_rtp_callback((tdav_codec_h264_t*) h264, pdata + last_scp, - (size - last_scp), tsk_true); - } -} - -#endif /* HAVE_FFMPEG */ diff --git a/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264_rtp.c b/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264_rtp.c deleted file mode 100644 index a750ccf..0000000 --- a/branches/1.0/tinyDAV/src/codecs/h264/tdav_codec_h264_rtp.c +++ /dev/null @@ -1,356 +0,0 @@ -/* -* Copyright (C) 2009-2010 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. -* -*/ - -/**@file tdav_codec_h264_rtp.c - * @brief H.264 payloader/depayloder as per RFC 3984 - * - * @author Mamadou Diop <diopmamadou(at)doubango.org> - * - * @date Created: Sat Nov 8 16:54:58 2009 mdiop - */ -#include "tinydav/codecs/h264/tdav_codec_h264_rtp.h" - -#include "tinydav/codecs/h264/tdav_codec_h264.h" - -#if HAVE_FFMPEG && (!defined(HAVE_H264) || HAVE_H264) - -#include "tinymedia/tmedia_codec.h" - -#include "tsk_string.h" -#include "tsk_debug.h" - -#include "tsk_memory.h" -#include <string.h> /* strlen() */ -#include <stdlib.h> /* strtol() */ - -/* -* ITU H.264 - http://www.itu.int/rec/T-REC-H.264-200903-S/en -*/ - -uint8_t H264_START_CODE_PREFIX[4] = { 0x00, 0x00, 0x00, 0x01 }; - -#define H264_NAL_UNIT_TYPE_HEADER_SIZE 1 -#define H264_F_UNIT_TYPE_HEADER_SIZE 1 -#define H264_FUA_HEADER_SIZE 2 -#define H264_FUB_HEADER_SIZE 4 -#define H264_NAL_AGG_MAX_SIZE 65535 - -int tdav_codec_h264_get_fua_pay(const uint8_t* in_data, tsk_size_t in_size, const void** out_data, tsk_size_t *out_size, tsk_bool_t* append_scp); -int tdav_codec_h264_get_nalunit_pay(const uint8_t* in_data, tsk_size_t in_size, const void** out_data, tsk_size_t *out_size); - -// profile_level_id MUST be a "null-terminated" string -int tdav_codec_h264_parse_profile(const char* profile_level_id, profile_idc_t *p_idc, profile_iop_t *p_iop, level_idc_t *l_idc) -{ - uint32_t value; - - if(tsk_strlen(profile_level_id) != 6){ - TSK_DEBUG_ERROR("I say [%s] is an invalid profile-level-id", profile_level_id); - return -1; - } - - value = strtol(profile_level_id, tsk_null, 16); - - /* profile-idc */ - if(p_idc){ - switch((value >> 16)){ - case profile_idc_baseline: - *p_idc = profile_idc_baseline; - break; - case profile_idc_extended: - *p_idc = profile_idc_extended; - break; - case profile_idc_main: - *p_idc = profile_idc_main; - break; - case profile_idc_high: - *p_idc = profile_idc_high; - break; - default: - *p_idc = profile_idc_none; - break; - } - } - - /* profile-iop */ - if(p_iop){ - p_iop->constraint_set0_flag = ((value >> 8) & 0x80)>>7; - p_iop->constraint_set1_flag = ((value >> 8) & 0x40)>>6; - p_iop->constraint_set2_flag = ((value >> 8) & 0x20)>>5; - p_iop->reserved_zero_5bits = ((value >> 8) & 0x1F); - } - - /* level-idc */ - if(l_idc){ - switch((value & 0xFF)){ - case level_idc_1_0: - *l_idc = level_idc_1_0; - break; - case level_idc_1_b: - *l_idc = level_idc_1_b; - break; - case level_idc_1_1: - *l_idc = level_idc_1_1; - break; - case level_idc_1_2: - *l_idc = level_idc_1_2; - break; - case level_idc_1_3: - *l_idc = level_idc_1_3; - break; - case level_idc_2_0: - *l_idc = level_idc_2_0; - break; - case level_idc_2_1: - *l_idc = level_idc_2_1; - break; - case level_idc_2_2: - *l_idc = level_idc_2_2; - break; - case level_idc_3_0: - *l_idc = level_idc_3_0; - break; - default: - *l_idc = level_idc_none; - break; - } - } - - return 0; -} - -int tdav_codec_h264_get_pay(const void* in_data, tsk_size_t in_size, const void** out_data, tsk_size_t *out_size, tsk_bool_t* append_scp) -{ - const uint8_t* pdata = in_data; - if(!in_data || !in_size || !out_data || !out_size){ - TSK_DEBUG_ERROR("Invalid parameter"); - return -1; - } - - *out_data = tsk_null; - *out_size = 0; - *append_scp = tsk_true; - - /* 5.3. NAL Unit Octet Usage - +---------------+ - |0|1|2|3|4|5|6|7| - +-+-+-+-+-+-+-+-+ - |F|NRI| Type | - +---------------+ - */ - switch((pdata[0] & 0x1F)){ - case undefined_0: - case undefined_30: - case undefined_31: - case stap_a: - case stap_b: - case mtap16: - case mtap24: - break; - case fu_a: - return tdav_codec_h264_get_fua_pay(pdata, in_size, out_data, out_size, append_scp); - case fu_b: - return -1; - default: /* NAL unit (1-23) */ - return tdav_codec_h264_get_nalunit_pay(pdata, in_size, out_data, out_size); - } - - TSK_DEBUG_WARN("%d not supported as valid NAL Unit type", (*pdata & 0x1F)); - return -1; -} - - -int tdav_codec_h264_get_fua_pay(const uint8_t* in_data, tsk_size_t in_size, const void** out_data, tsk_size_t *out_size, tsk_bool_t* append_scp) -{ - if(in_size <=2){ - TSK_DEBUG_ERROR("Too short"); - return -1; - } - /* RFC 3984 - 5.8. Fragmentation Units (FUs) - - 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 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | FU indicator | FU header | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | - | | - | FU payload | - | | - | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | :...OPTIONAL RTP padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - The FU indicator octet has the following format: - - +---------------+ - |0|1|2|3|4|5|6|7| - +-+-+-+-+-+-+-+-+ - |F|NRI| Type | - +---------------+ - - The FU header has the following format: - - +---------------+ - |0|1|2|3|4|5|6|7| - +-+-+-+-+-+-+-+-+ - |S|E|R| Type | - +---------------+ - */ - - if((in_data[1] & 0x80) == 0x80 /*S*/){ - /* discard "FU indicator" - S: 1 bit - When set to one, the Start bit indicates the start of a fragmented - NAL unit. When the following FU payload is not the start of a - fragmented NAL unit payload, the Start bit is set to zero. - */ - if(in_size> H264_NAL_UNIT_TYPE_HEADER_SIZE){ - uint8_t hdr; - *out_data = (in_data + H264_NAL_UNIT_TYPE_HEADER_SIZE); - *out_size = (in_size - H264_NAL_UNIT_TYPE_HEADER_SIZE); - - // F, NRI and Type - hdr = (in_data[0] & 0xe0) /* F,NRI from "FU indicator"*/ | (in_data[1] & 0x1f) /* type from "FU header" */; - *((uint8_t*)*out_data) = hdr; - // Need to append Start Code Prefix - *append_scp = tsk_true; - } - else{ - TSK_DEBUG_ERROR("Too short"); - return -1; - } - } - else{ - /* "FU indicator" and "FU header" */ - if(in_size> H264_FUA_HEADER_SIZE){ - *out_data = (in_data + H264_FUA_HEADER_SIZE); - *out_size = (in_size - H264_FUA_HEADER_SIZE); - *append_scp = tsk_false; - } - else{ - TSK_DEBUG_ERROR("Too short"); - return -1; - } - } - - return 0; -} - -int tdav_codec_h264_get_nalunit_pay(const uint8_t* in_data, tsk_size_t in_size, const void** out_data, tsk_size_t *out_size) -{ - -/* 5.6. Single NAL Unit Packet - - 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 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |F|NRI| type | | - +-+-+-+-+-+-+-+-+ | - | | - | Bytes 2..n of a Single NAL unit | - | | - | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | :...OPTIONAL RTP padding | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - - *out_data = in_data; - *out_size = in_size; - - return 0; -} - -#if TDAV_UNDER_WINDOWS -# include "tsk_thread.h" -#endif -void tdav_codec_h264_rtp_callback(struct tdav_codec_h264_s *self, const void *data, tsk_size_t size, tsk_bool_t marker) -{ - uint8_t* pdata = (uint8_t*)data; - - if(size>4 && pdata[0] == H264_START_CODE_PREFIX[0] && pdata[1] == H264_START_CODE_PREFIX[1]){ - if(pdata[2] == H264_START_CODE_PREFIX[3]){ - pdata += 3, size -= 3; - } - else if(pdata[2] == H264_START_CODE_PREFIX[2] && pdata[3] == H264_START_CODE_PREFIX[3]){ - pdata += 4, size -= 4; - } - } - - //TSK_DEBUG_INFO("==> SCP %2x %2x %2x %2x", pdata[0], pdata[1], pdata[2], pdata[3]); - - if(size < H264_RTP_PAYLOAD_SIZE){ - /* Can be packet in a Single Nal Unit */ - // Send data over the network - if(TMEDIA_CODEC_VIDEO(self)->callback){ - TMEDIA_CODEC_VIDEO(self)->callback(TMEDIA_CODEC_VIDEO(self)->callback_data, pdata, size, (3003* (30/TMEDIA_CODEC_VIDEO(self)->fps)), marker); - } - } - else if(size > H264_NAL_UNIT_TYPE_HEADER_SIZE){ -#if TDAV_UNDER_WINDOWS - tsk_bool_t burst = ((size/H264_RTP_PAYLOAD_SIZE) > 5); - int count = 0; -#endif - /* Should be Fragmented as FUA */ - uint8_t fua_hdr[H264_FUA_HEADER_SIZE]; /* "FU indicator" and "FU header" - 2bytes */ - fua_hdr[0] = pdata[0] & 0x60/* F=0 */, fua_hdr[0] |= fu_a; - fua_hdr[1] = 0x80/* S=1,E=0,R=0 */, fua_hdr[1] |= pdata[0] & 0x1f; /* type */ - // discard header - pdata += H264_NAL_UNIT_TYPE_HEADER_SIZE; - size -= H264_NAL_UNIT_TYPE_HEADER_SIZE; - - while(size){ - tsk_size_t packet_size = TSK_MIN(H264_RTP_PAYLOAD_SIZE, size); - - if(self->rtp.size < (packet_size + H264_FUA_HEADER_SIZE)){ - if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (packet_size + H264_FUA_HEADER_SIZE)))){ - TSK_DEBUG_ERROR("Failed to allocate new buffer"); - return; - } - self->rtp.size = (packet_size + H264_FUA_HEADER_SIZE); - } - // set E bit - if((size - packet_size) == 0){ - // Last packet - fua_hdr[1] |= 0x40; - } - // copy FUA header - memcpy(self->rtp.ptr, fua_hdr, H264_FUA_HEADER_SIZE); - // reset "S" bit - fua_hdr[1] &= 0x7F; - // copy data - memcpy((self->rtp.ptr + H264_FUA_HEADER_SIZE), pdata, packet_size); - pdata += packet_size; - size -= packet_size; - - // send data - if(TMEDIA_CODEC_VIDEO(self)->callback){ - TMEDIA_CODEC_VIDEO(self)->callback(TMEDIA_CODEC_VIDEO(self)->callback_data, self->rtp.ptr, (packet_size + H264_FUA_HEADER_SIZE), (3003* (30/TMEDIA_CODEC_VIDEO(self)->fps)), (size == 0)); -#if TDAV_UNDER_WINDOWS// FIXME: WinSock problem: Why do we get packet lost (burst case only)? - if(burst && (++count % 2 == 0)){ - tsk_thread_sleep(1); // 1 millisecond - } -#endif - } - } - } -} - -#endif /* HAVE_FFMPEG */
\ No newline at end of file |