/* * Copyright (C) 2010-2011 Mamadou Diop. * * Contact: Mamadou Diop * * 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_h263.c * @brief H.263-1996 and H.263-1998 codec plugins. * RTP payloader follows RFC 4629 for H263+ and RFC 2190 for H263. * * @author Mamadou Diop * */ #include "tinydav/codecs/h263/tdav_codec_h263.h" #if HAVE_FFMPEG #include "tinydav/video/tdav_converter_video.h" #include "tinyrtp/rtp/trtp_rtp_packet.h" #include "tnet_endianness.h" #include "tinymedia/tmedia_params.h" #include "tinymedia/tmedia_defaults.h" #include "tsk_string.h" #include "tsk_time.h" #include "tsk_memory.h" #include "tsk_debug.h" #include #define TDAV_H263_GOP_SIZE_IN_SECONDS 25 #define RTP_PAYLOAD_SIZE 750 #define H263P_HEADER_SIZE 2 #define H263_HEADER_MODE_A_SIZE 4 #define H263_HEADER_MODE_B_SIZE 8 #define H263_HEADER_MODE_C_SIZE 12 #define tdav_codec_h263p_set tdav_codec_h263_set #define tdav_codec_h263p_open tdav_codec_h263_open #define tdav_codec_h263p_close tdav_codec_h263_close #define tdav_codec_h263p_encode tdav_codec_h263_encode #define tdav_codec_h263p_sdp_att_match tdav_codec_h263_sdp_att_match #define tdav_codec_h263p_sdp_att_get tdav_codec_h263_sdp_att_get #define tdav_codec_h263pp_set tdav_codec_h263_set #define tdav_codec_h263pp_open tdav_codec_h263_open #define tdav_codec_h263pp_close tdav_codec_h263_close #define tdav_codec_h263pp_encode tdav_codec_h263_encode #define tdav_codec_h263pp_decode tdav_codec_h263_decode #define tdav_codec_h263pp_sdp_att_match tdav_codec_h263_sdp_att_match #define tdav_codec_h263pp_sdp_att_get tdav_codec_h263_sdp_att_get #define TDAV_CODEC_H263(self) ((tdav_codec_h263_t*)(self)) typedef enum tdav_codec_h263_type_e { tdav_codec_h263_1996, tdav_codec_h263_1998, tdav_codec_h263_2000, } tdav_codec_h263_type_t; /** H.263-1996 codec */ typedef struct tdav_codec_h263_s { TMEDIA_DECLARE_CODEC_VIDEO; tdav_codec_h263_type_t type; struct { uint8_t* ptr; tsk_size_t size; } rtp; // Encoder struct { AVCodec* codec; AVCodecContext* context; AVFrame* picture; void* buffer; tsk_bool_t force_idr; int32_t quality; // [1-31] 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_h263_t; #define TDAV_DECLARE_CODEC_H263 tdav_codec_h263_t __codec_h263__ static int tdav_codec_h263_init(tdav_codec_h263_t* self, tdav_codec_h263_type_t type, enum AVCodecID encoder, enum AVCodecID decoder); static int tdav_codec_h263_deinit(tdav_codec_h263_t* self); static int tdav_codec_h263_open_encoder(tdav_codec_h263_t* self); static int tdav_codec_h263_open_decoder(tdav_codec_h263_t* self); static int tdav_codec_h263_close_encoder(tdav_codec_h263_t* self); static int tdav_codec_h263_close_decoder(tdav_codec_h263_t* self); /** H.263-1998 codec */ typedef struct tdav_codec_h263p_s { TDAV_DECLARE_CODEC_H263; } tdav_codec_h263p_t; /** H.263-2000 codec */ typedef struct tdav_codec_h263pp_s { TDAV_DECLARE_CODEC_H263; } tdav_codec_h263pp_t; static void tdav_codec_h263_rtp_callback(tdav_codec_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t marker); static void tdav_codec_h263p_rtp_callback(tdav_codec_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t frag, tsk_bool_t marker); static void tdav_codec_h263_encap(const tdav_codec_h263_t* h263, const uint8_t* pdata, tsk_size_t size); /* ============ Common To all H263 codecs ================= */ static int tdav_codec_h263_set(tmedia_codec_t* self, const tmedia_param_t* param) { tdav_codec_h263_t* h263 = (tdav_codec_h263_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: { h263->encoder.force_idr = tsk_true; break; } case tmedia_codec_action_bw_down: { h263->encoder.quality = TSK_CLAMP(1, (h263->encoder.quality + 1), 31); h263->encoder.context->global_quality = FF_QP2LAMBDA * h263->encoder.quality; break; } case tmedia_codec_action_bw_up: { h263->encoder.quality = TSK_CLAMP(1, (h263->encoder.quality - 1), 31); h263->encoder.context->global_quality = FF_QP2LAMBDA * h263->encoder.quality; break; } } return 0; } } return -1; } int tdav_codec_h263_init(tdav_codec_h263_t* self, tdav_codec_h263_type_t type, enum AVCodecID encoder, enum AVCodecID decoder) { int ret = 0; if(!self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } self->type = type; self->encoder.quality = 1; if(!(self->encoder.codec = avcodec_find_encoder(encoder))) { TSK_DEBUG_ERROR("Failed to find [%d]encoder", encoder); ret = -2; } if(!(self->decoder.codec = avcodec_find_decoder(decoder))) { TSK_DEBUG_ERROR("Failed to find [%d] decoder", decoder); ret = -3; } self->encoder.max_bw_kpbs = tmedia_defaults_get_bandwidth_video_upload_max(); /* allocations MUST be done by open() */ return ret; } int tdav_codec_h263_deinit(tdav_codec_h263_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; } /* ============ H.263-1996 Plugin interface ================= */ // // H.263-1996 object definition // static int tdav_codec_h263_open(tmedia_codec_t* self) { int ret; tdav_codec_h263_t* h263 = (tdav_codec_h263_t*)self; if(!h263) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } /* the caller (base class) already checked that the codec is not opened */ // Encoder if((ret = tdav_codec_h263_open_encoder(h263))) { return ret; } // Decoder if((ret = tdav_codec_h263_open_decoder(h263))) { return ret; } return ret; } static int tdav_codec_h263_close(tmedia_codec_t* self) { tdav_codec_h263_t* h263 = (tdav_codec_h263_t*)self; int ret; if(!h263) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } /* the caller (base class) already checked that the codec is opened */ // Encoder ret = tdav_codec_h263_close_encoder(h263); // Decoder ret = tdav_codec_h263_close_decoder(h263); return ret; } static tsk_size_t tdav_codec_h263_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_h263_t* h263 = (tdav_codec_h263_t*)self; if(!self || !in_data || !in_size || !out_data) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } // wrap yuv420 buffer size = avpicture_fill((AVPicture *)h263->encoder.picture, (uint8_t*)in_data, PIX_FMT_YUV420P, h263->encoder.context->width, h263->encoder.context->height); if(size != in_size) { /* guard */ TSK_DEBUG_ERROR("Invalid size"); return 0; } #if LIBAVCODEC_VERSION_MAJOR <= 53 h263->encoder.picture->pict_type = h263->encoder.force_idr ? FF_I_TYPE : 0; #else h263->encoder.picture->pict_type = h263->encoder.force_idr ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE; #endif h263->encoder.picture->pts = AV_NOPTS_VALUE; h263->encoder.picture->quality = h263->encoder.context->global_quality; ret = avcodec_encode_video(h263->encoder.context, h263->encoder.buffer, size, h263->encoder.picture); if(ret > 0) { tdav_codec_h263_encap(h263, h263->encoder.buffer, (tsk_size_t)ret); } h263->encoder.force_idr = tsk_false; return 0; } static tsk_size_t tdav_codec_h263_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) { uint8_t F, P, sbit, ebit; const uint8_t* pdata = in_data; 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_h263_t* h263 = (tdav_codec_h263_t*)self; const trtp_rtp_header_t* rtp_hdr = proto_hdr; tsk_bool_t is_idr = tsk_false; if(!self || !in_data || !in_size || !out_data || !h263->decoder.context) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } /* RFC 2190 get F and P bits, used to determine the header Mode (A, B or C) F: 1 bit The flag bit indicates the mode of the payload header. F=0, mode A; F=1, mode B or mode C depending on P bit defined below. P: 1 bit Optional PB-frames mode as defined by the H.263 [4]. "0" implies normal I or P frame, "1" PB-frames. When F=1, P also indicates modes: mode B if P=0, mode C if P=1. I: 1 bit. Picture coding type, bit 9 in PTYPE defined by H.263[4], "0" is intra-coded, "1" is inter-coded. */ F = *pdata >> 7; P = (*pdata >> 6) & 0x01; /* SBIT and EBIT */ sbit = (*pdata >> 3) & 0x0F; ebit = (*pdata & 0x07); if(F == 0) { /* MODE A 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|P|SBIT |EBIT | SRC |I|U|S|A|R |DBQ| TRB | TR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ hdr_size = H263_HEADER_MODE_A_SIZE; is_idr = (in_size >= 2) && !(pdata[1] & 0x10) /* I==1 */; } else if(P == 0) { // F=1 and P=0 /* MODE B 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|P|SBIT |EBIT | SRC | QUANT | GOBN | MBA |R | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |I|U|S|A| HMV1 | VMV1 | HMV2 | VMV2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ hdr_size = H263_HEADER_MODE_B_SIZE; is_idr = (in_size >= 5) && !(pdata[4] & 0x80) /* I==1 */; } else { // F=1 and P=1 /* MODE C 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|P|SBIT |EBIT | SRC | QUANT | GOBN | MBA |R | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |I|U|S|A| HMV1 | VMV1 | HMV2 | VMV2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RR |DBQ| TRB | TR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ hdr_size = H263_HEADER_MODE_C_SIZE; is_idr = (in_size >= 5) && !(pdata[4] & 0x80) /* I==1 */; } /* Check size */ if(in_size < hdr_size) { TSK_DEBUG_ERROR("Too short"); return 0; } pay_ptr = (pdata + hdr_size); pay_size = (in_size - hdr_size); xsize = avpicture_get_size(h263->decoder.context->pix_fmt, h263->decoder.context->width, h263->decoder.context->height); /* Packet lost? */ if(h263->decoder.last_seq != (rtp_hdr->seq_num - 1) && h263->decoder.last_seq) { if(h263->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("[H.263] Packet loss, seq_num=%d", rtp_hdr->seq_num); } h263->decoder.last_seq = rtp_hdr->seq_num; if((int)(h263->decoder.accumulator_pos + pay_size) <= xsize) { if((h263->decoder.ebit + sbit) == 8) { /* Perfect one Byte to clean up */ if(h263->decoder.accumulator_pos) { ((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos-1] = (((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos-1] & (0xFF << h263->decoder.ebit)) | (*pay_ptr & (0xFF >> sbit)); } pay_ptr++, pay_size--; } h263->decoder.ebit = ebit; memcpy(&((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos], pay_ptr, pay_size); h263->decoder.accumulator_pos += pay_size; } else { TSK_DEBUG_WARN("Buffer overflow"); h263->decoder.accumulator_pos = 0; return 0; } if(rtp_hdr->marker) { AVPacket packet; /* allocate destination buffer */ if(*out_max_size decoder.accumulator_pos = 0; *out_max_size = 0; return 0; } *out_max_size = xsize; } av_init_packet(&packet); packet.size = (int)h263->decoder.accumulator_pos; packet.data = h263->decoder.accumulator; ret = avcodec_decode_video2(h263->decoder.context, h263->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; // Is it IDR frame? if(is_idr && TMEDIA_CODEC_VIDEO(self)->in.callback) { TSK_DEBUG_INFO("Decoded H.263 IDR"); TMEDIA_CODEC_VIDEO(self)->in.result.type = tmedia_video_decode_result_type_idr; TMEDIA_CODEC_VIDEO(self)->in.result.proto_hdr = proto_hdr; TMEDIA_CODEC_VIDEO(self)->in.callback(&TMEDIA_CODEC_VIDEO(self)->in.result); } TMEDIA_CODEC_VIDEO(h263)->in.width = h263->decoder.context->width; TMEDIA_CODEC_VIDEO(h263)->in.height = h263->decoder.context->height; /* copy picture into a linear buffer */ avpicture_layout((AVPicture *)h263->decoder.picture, h263->decoder.context->pix_fmt, (int)h263->decoder.context->width, (int)h263->decoder.context->height, *out_data, (int)retsize); } /* in all cases: reset accumulator */ h263->decoder.accumulator_pos = 0; } return retsize; } static tsk_bool_t tdav_codec_h263_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value) { if(tsk_striequals(att_name, "fmtp")) { unsigned width, height, fps; if(tmedia_parse_video_fmtp(att_value, TMEDIA_CODEC_VIDEO(codec)->pref_size, &width, &height, &fps)) { TSK_DEBUG_ERROR("Failed to match fmtp=%s", att_value); return tsk_false; } TMEDIA_CODEC_VIDEO(codec)->in.width = TMEDIA_CODEC_VIDEO(codec)->out.width = width; TMEDIA_CODEC_VIDEO(codec)->in.height = TMEDIA_CODEC_VIDEO(codec)->out.height = height; TMEDIA_CODEC_VIDEO(codec)->in.fps = TMEDIA_CODEC_VIDEO(codec)->out.fps = fps; } #if 0 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; } #endif return tsk_true; } static char* tdav_codec_h263_sdp_att_get(const tmedia_codec_t* codec, const char* att_name) { if(tsk_striequals(att_name, "fmtp")) { tmedia_pref_video_size_t cif_vs; if(tmedia_video_get_closest_cif_size(TMEDIA_CODEC_VIDEO(codec)->pref_size, &cif_vs)) { TSK_DEBUG_ERROR("Failed to get closest CIF family size"); return tsk_null; } return tmedia_get_video_fmtp(cif_vs); } #if 0 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); } #endif return tsk_null; } /* constructor */ static tsk_object_t* tdav_codec_h263_ctor(tsk_object_t * self, va_list * app) { tdav_codec_h263_t *h263 = self; if(h263) { /* init base: called by tmedia_codec_create() */ /* init self */ tdav_codec_h263_init(TDAV_CODEC_H263(self), tdav_codec_h263_1996, CODEC_ID_H263, CODEC_ID_H263); } return self; } /* destructor */ static tsk_object_t* tdav_codec_h263_dtor(tsk_object_t * self) { tdav_codec_h263_t *h263 = self; if(h263) { /* deinit base */ tmedia_codec_video_deinit(h263); /* deinit self */ tdav_codec_h263_deinit(TDAV_CODEC_H263(self)); } return self; } /* object definition */ static const tsk_object_def_t tdav_codec_h263_def_s = { sizeof(tdav_codec_h263_t), tdav_codec_h263_ctor, tdav_codec_h263_dtor, tmedia_codec_cmp, }; /* plugin definition*/ static const tmedia_codec_plugin_def_t tdav_codec_h263_plugin_def_s = { &tdav_codec_h263_def_s, tmedia_video, tmedia_codec_id_h263, "H263", "H263-1996 codec (FFmpeg)", TMEDIA_CODEC_FORMAT_H263, tsk_false, 90000, // rate /* audio */ { 0 }, /* video */ {176, 144, 15}, tdav_codec_h263_set, tdav_codec_h263_open, tdav_codec_h263_close, tdav_codec_h263_encode, tdav_codec_h263_decode, tdav_codec_h263_sdp_att_match, tdav_codec_h263_sdp_att_get }; const tmedia_codec_plugin_def_t *tdav_codec_h263_plugin_def_t = &tdav_codec_h263_plugin_def_s; /* ============ H.263-1998 Plugin interface ================= */ // // H.263-1998 object definition // static tsk_size_t tdav_codec_h263p_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) { uint8_t P, V, PLEN, PEBIT; uint8_t* pdata = (uint8_t*)in_data; const uint8_t* pay_ptr; tsk_size_t pay_size; int hdr_size = H263P_HEADER_SIZE; tsk_size_t xsize, retsize = 0; int got_picture_ptr; int ret; tdav_codec_h263_t* h263 = (tdav_codec_h263_t*)self; const trtp_rtp_header_t* rtp_hdr = proto_hdr; if(!self || !in_data || !in_size || ((int)in_size <= hdr_size) || !out_data || !h263->decoder.context) { TSK_DEBUG_ERROR("Invalid parameter"); return 0; } /* rfc4629 - 5.1. General H.263+ Payload Header 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RR |P|V| PLEN |PEBIT| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ P = (pdata[0] & 0x04)>>2; V = (pdata[0] & 0x02)>>1; PLEN = (((pdata[0] & 0x01)<<5) | pdata[1]>>3); PEBIT = pdata[1] & 0x07; if(V) { /* Indicates the presence of an 8-bit field containing information for Video Redundancy Coding (VRC), which follows immediately after the initial 16 bits of the payload header, if present. For syntax and semantics of that 8-bit VRC field, see Section 5.2. */ } if(PLEN) { /* Length, in bytes, of the extra picture header. If no extra picture header is attached, PLEN is 0. If PLEN>0, the extra picture header is attached immediately following the rest of the payload header. Note that the length reflects the omission of the first two bytes of the picture start code (PSC). See Section 6.1. */ hdr_size += PLEN; if(PEBIT) { /* Indicates the number of bits that shall be ignored in the last byte of the picture header. If PLEN is not zero, the ignored bits shall be the least significant bits of the byte. If PLEN is zero, then PEBIT shall also be zero. */ TSK_DEBUG_WARN("PEBIT ignored"); } } if(P) { /* MUST be done after PLEN and PEBIT */ /* Indicates the picture start or a picture segment (GOB/Slice) start or a video sequence end (EOS or EOSBS). Two bytes of zero bits then have to be prefixed to the payload of such a packet to compose a complete picture/GOB/slice/EOS/EOSBS start code. This bit allows the omission of the two first bytes of the start codes, thus improving the compression ratio. */ hdr_size -= 2; pdata[hdr_size] = 0x00, pdata[hdr_size + 1] = 0x00; } pay_ptr = (pdata + hdr_size); pay_size = (in_size - hdr_size); xsize = avpicture_get_size(h263->decoder.context->pix_fmt, h263->decoder.context->width, h263->decoder.context->height); /* Packet lost? */ if(h263->decoder.last_seq != (rtp_hdr->seq_num - 1) && h263->decoder.last_seq) { if(h263->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("[H.263+] Packet loss, seq_num=%d", rtp_hdr->seq_num); } h263->decoder.last_seq = rtp_hdr->seq_num; if((int)(h263->decoder.accumulator_pos + pay_size) <= xsize) { /* PEBIT is ignored */ memcpy(&((uint8_t*)h263->decoder.accumulator)[h263->decoder.accumulator_pos], pay_ptr, pay_size); h263->decoder.accumulator_pos += pay_size; } else { TSK_DEBUG_WARN("Buffer overflow"); h263->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"); *out_max_size = 0; h263->decoder.accumulator_pos = 0; return 0; } *out_max_size = xsize; } /* decode the picture */ av_init_packet(&packet); packet.size = (int)h263->decoder.accumulator_pos; packet.data = h263->decoder.accumulator; ret = avcodec_decode_video2(h263->decoder.context, h263->decoder.picture, &got_picture_ptr, &packet); if(ret <0 || !got_picture_ptr) { TSK_DEBUG_WARN("Failed to decode the buffer"); } else { retsize = xsize; TMEDIA_CODEC_VIDEO(h263)->in.width = h263->decoder.context->width; TMEDIA_CODEC_VIDEO(h263)->in.height = h263->decoder.context->height; /* copy picture into a linear buffer */ avpicture_layout((AVPicture *)h263->decoder.picture, h263->decoder.context->pix_fmt, (int)h263->decoder.context->width, (int)h263->decoder.context->height, *out_data, (int)retsize); } /* in all cases: reset accumulator */ h263->decoder.accumulator_pos = 0; } return retsize; } /* constructor */ static tsk_object_t* tdav_codec_h263p_ctor(tsk_object_t * self, va_list * app) { tdav_codec_h263p_t *h263p = self; if(h263p) { /* init base: called by tmedia_codec_create() */ /* init self */ tdav_codec_h263_init(TDAV_CODEC_H263(self), tdav_codec_h263_1998, CODEC_ID_H263P, CODEC_ID_H263); } return self; } /* destructor */ static tsk_object_t* tdav_codec_h263p_dtor(tsk_object_t * self) { tdav_codec_h263p_t *h263p = self; if(h263p) { /* deinit base */ tmedia_codec_video_deinit(h263p); /* deinit self */ tdav_codec_h263_deinit(TDAV_CODEC_H263(self)); } return self; } /* object definition */ static const tsk_object_def_t tdav_codec_h263p_def_s = { sizeof(tdav_codec_h263p_t), tdav_codec_h263p_ctor, tdav_codec_h263p_dtor, tmedia_codec_cmp, }; /* plugin definition*/ static const tmedia_codec_plugin_def_t tdav_codec_h263p_plugin_def_s = { &tdav_codec_h263p_def_s, tmedia_video, tmedia_codec_id_h263p, "H263-1998", "H263-1998 codec (FFmpeg)", TMEDIA_CODEC_FORMAT_H263_1998, tsk_true, 90000, // rate /* audio */ { 0 }, /* video (width, height, fps) */ {176, 144, 0},// fps is @deprecated tdav_codec_h263p_set, tdav_codec_h263p_open, tdav_codec_h263p_close, tdav_codec_h263p_encode, tdav_codec_h263p_decode, tdav_codec_h263p_sdp_att_match, tdav_codec_h263p_sdp_att_get }; const tmedia_codec_plugin_def_t *tdav_codec_h263p_plugin_def_t = &tdav_codec_h263p_plugin_def_s; /* ============ H.263-2000 Plugin interface ================= */ // // H.263-2000 object definition // /* constructor */ static tsk_object_t* tdav_codec_h263pp_ctor(tsk_object_t * self, va_list * app) { tdav_codec_h263pp_t *h263pp = self; if(h263pp) { /* init base: called by tmedia_codec_create() */ /* init self */ tdav_codec_h263_init(TDAV_CODEC_H263(self), tdav_codec_h263_2000, CODEC_ID_H263P, CODEC_ID_H263); } return self; } /* destructor */ static tsk_object_t* tdav_codec_h263pp_dtor(tsk_object_t * self) { tdav_codec_h263pp_t *h263pp = self; if(h263pp) { /* deinit base */ tmedia_codec_video_deinit(h263pp); /* deinit self */ tdav_codec_h263_deinit(TDAV_CODEC_H263(self)); } return self; } /* object definition */ static const tsk_object_def_t tdav_codec_h263pp_def_s = { sizeof(tdav_codec_h263pp_t), tdav_codec_h263pp_ctor, tdav_codec_h263pp_dtor, tmedia_codec_cmp, }; /* plugin definition*/ static const tmedia_codec_plugin_def_t tdav_codec_h263pp_plugin_def_s = { &tdav_codec_h263pp_def_s, tmedia_video, tmedia_codec_id_h263pp, "H263-2000", "H263-2000 codec (FFmpeg)", TMEDIA_CODEC_FORMAT_H263_2000, tsk_true, 90000, // rate /* audio */ { 0 }, /* video (width, height, fps)*/ {176, 144, 0},// fps is @deprecated tdav_codec_h263pp_set, tdav_codec_h263pp_open, tdav_codec_h263pp_close, tdav_codec_h263pp_encode, tdav_codec_h263pp_decode, tdav_codec_h263pp_sdp_att_match, tdav_codec_h263pp_sdp_att_get }; const tmedia_codec_plugin_def_t *tdav_codec_h263pp_plugin_def_t = &tdav_codec_h263pp_plugin_def_s; int tdav_codec_h263_open_encoder(tdav_codec_h263_t* self) { int ret; int size; int32_t max_bw_kpbs; 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)->out.fps; self->encoder.context->width = TMEDIA_CODEC_VIDEO(self)->out.width; self->encoder.context->height = TMEDIA_CODEC_VIDEO(self)->out.height; self->encoder.context->qmin = 10; self->encoder.context->qmax = 51; #if LIBAVCODEC_VERSION_MAJOR <= 53 self->encoder.context->mb_qmin = self->encoder.context->qmin; self->encoder.context->mb_qmax = self->encoder.context->qmax; #endif self->encoder.context->mb_decision = FF_MB_DECISION_RD; 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->rc_lookahead = 0; self->encoder.context->rtp_payload_size = RTP_PAYLOAD_SIZE; self->encoder.context->opaque = tsk_null; self->encoder.context->gop_size = (TMEDIA_CODEC_VIDEO(self)->out.fps * TDAV_H263_GOP_SIZE_IN_SECONDS); self->encoder.context->flags |= CODEC_FLAG_QSCALE; self->encoder.context->global_quality = FF_QP2LAMBDA * self->encoder.quality; self->encoder.context->max_b_frames = 0; // 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); //if((ret = avpicture_alloc((AVPicture*)self->encoder.picture, PIX_FMT_YUV420P, self->encoder.context->width, self->encoder.context->height))){ // TSK_DEBUG_ERROR("Failed to allocate encoder picture"); // return ret; //} 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; } // RTP Callback switch(self->type) { case tdav_codec_h263_1996: { // H263 - 1996 break; } case tdav_codec_h263_1998: { // H263 - 1998 #if defined(CODEC_FLAG_H263P_UMV) self->encoder.context->flags |= CODEC_FLAG_H263P_UMV; // Annex D+ #endif self->encoder.context->flags |= CODEC_FLAG_AC_PRED; // Annex I and T self->encoder.context->flags |= CODEC_FLAG_LOOP_FILTER; // Annex J #if defined(CODEC_FLAG_H263P_SLICE_STRUCT) self->encoder.context->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; // Annex K #endif #if defined(CODEC_FLAG_H263P_AIV) self->encoder.context->flags |= CODEC_FLAG_H263P_AIV; // Annex S #endif break; } case tdav_codec_h263_2000: { // H263 - 2000 #if defined(CODEC_FLAG_H263P_UMV) self->encoder.context->flags |= CODEC_FLAG_H263P_UMV; // Annex D+ #endif self->encoder.context->flags |= CODEC_FLAG_AC_PRED; // Annex I and T self->encoder.context->flags |= CODEC_FLAG_LOOP_FILTER; // Annex J #if defined(CODEC_FLAG_H263P_SLICE_STRUCT) self->encoder.context->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; // Annex K #endif #if defined(CODEC_FLAG_H263P_AIV) self->encoder.context->flags |= CODEC_FLAG_H263P_AIV; // Annex S #endif break; } } // Open encoder if((ret = avcodec_open(self->encoder.context, self->encoder.codec)) < 0) { TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(self)->plugin->desc); return ret; } TSK_DEBUG_INFO("[H.263] bitrate=%d bps", self->encoder.context->bit_rate); return ret; } int tdav_codec_h263_open_decoder(tdav_codec_h263_t* self) { int ret, size; 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; } // Open decoder if((ret = avcodec_open(self->decoder.context, self->decoder.codec)) < 0) { TSK_DEBUG_ERROR("Failed to open [%s] codec", TMEDIA_CODEC(self)->plugin->desc); return ret; } self->decoder.last_seq = 0; return ret; } int tdav_codec_h263_close_encoder(tdav_codec_h263_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; } int tdav_codec_h263_close_decoder(tdav_codec_h263_t* self) { if(self->decoder.context) { avcodec_close(self->decoder.context); 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); self->decoder.accumulator_pos = 0; } return 0; } /* ============ Callbacks ================= */ static void tdav_codec_h263_encap(const tdav_codec_h263_t* h263, const uint8_t* pdata, tsk_size_t size) { tsk_bool_t frag = tsk_false; register uint32_t i, last_index = 0; if(size < RTP_PAYLOAD_SIZE) { goto last; } for(i = 4; i<(size - 4); i++) { if(pdata[i] == 0x00 && pdata[i+1] == 0x00 && pdata[i+2]>=0x80) { /* PSC or (GBSC) found */ if((i - last_index) >= RTP_PAYLOAD_SIZE || tsk_true/* FIXME */) { switch(h263->type) { case tdav_codec_h263_1996: tdav_codec_h263_rtp_callback((tdav_codec_h263_t*) h263, pdata+last_index, (i - last_index), (last_index == size)); break; default: tdav_codec_h263p_rtp_callback((tdav_codec_h263_t*) h263, pdata + last_index, (i - last_index), frag, (last_index == size)); frag = tsk_true; break; } last_index = i; } } } last: if(last_index < size) { switch(h263->type) { case tdav_codec_h263_1996: tdav_codec_h263_rtp_callback((tdav_codec_h263_t*) h263, pdata + last_index, (size - last_index), tsk_true); break; default: tdav_codec_h263p_rtp_callback((tdav_codec_h263_t*) h263, pdata + last_index, (size - last_index), frag, tsk_true); break; } } } static void tdav_codec_h263_rtp_callback(tdav_codec_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t marker) { uint8_t* pdata = (uint8_t*)data; if(self->rtp.size < (size + H263_HEADER_MODE_A_SIZE)) { if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (size + H263_HEADER_MODE_A_SIZE)))) { TSK_DEBUG_ERROR("Failed to allocate new buffer"); return; } self->rtp.size = (size + H263_HEADER_MODE_A_SIZE); } memcpy((self->rtp.ptr + H263_HEADER_MODE_A_SIZE), data, size); /* http://eu.sabotage.org/www/ITU/H/H0263e.pdf section 5.1 * 5.1.1 Picture Start Code (PSC) (22 bits) - PSC is a word of 22 bits. Its value is 0000 0000 0000 0000 1 00000. * * 5.1.1 Picture Start Code (PSC) (22 bits) * 5.1.2 Temporal Reference (TR) (8 bits) * 5.1.3 Type Information (PTYPE) (Variable Length) * – Bit 1: Always "1", in order to avoid start code emulation. * – Bit 2: Always "0", for distinction with Recommendation H.261. * – Bit 3: Split screen indicator, "0" off, "1" on. * – Bit 4: Document camera indicator, "0" off, "1" on. * – Bit 5: Full Picture Freeze Release, "0" off, "1" on. * – Bits 6-8: Source Format, "000" forbidden, "001" sub-QCIF, "010" QCIF, "011" CIF, "100" 4CIF, "101" 16CIF, "110" reserved, "111" extended PTYPE. If bits 6-8 are not equal to "111", which indicates an extended PTYPE (PLUSPTYPE), the following five bits are also present in PTYPE: – Bit 9: Picture Coding Type, "0" INTRA (I-picture), "1" INTER (P-picture). – Bit 10: Optional Unrestricted Motion Vector mode (see Annex D), "0" off, "1" on. – Bit 11: Optional Syntax-based Arithmetic Coding mode (see Annex E), "0" off, "1" on. – Bit 12: Optional Advanced Prediction mode (see Annex F), "0" off, "1" on. – Bit 13: Optional PB-frames mode (see Annex G), "0" normal I- or P-picture, "1" PB-frame. */ if(pdata[0] == 0x00 && pdata[1] == 0x00 && (pdata[2] & 0xfc)==0x80) { /* PSC */ /* RFC 2190 -5.1 Mode A 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|P|SBIT |EBIT | SRC |I|U|S|A|R |DBQ| TRB | TR | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ SRC : 3 bits Source format, bit 6,7 and 8 in PTYPE defined by H.263 [4], specifies the resolution of the current picture. I: 1 bit. Picture coding type, bit 9 in PTYPE defined by H.263[4], "0" is intra-coded, "1" is inter-coded. */ // PDATA[4] ======> Bits 3-10 of PTYPE uint32_t rtp_hdr = 0; uint8_t format, pict_type; // Source Format = 4,5,6 format = (pdata[4] & 0x3C)>>2; // Picture Coding Type = 7 pict_type = (pdata[4] & 0x02)>>1; // RTP mode A header ((uint8_t*)&rtp_hdr)[1] = (format <<5) | (pict_type << 4); //rtp_hdr = tnet_htonl(rtp_hdr); memcpy(self->rtp.ptr, &rtp_hdr, sizeof(rtp_hdr)); } // 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 = (size + H263_HEADER_MODE_A_SIZE); TMEDIA_CODEC_VIDEO(self)->out.result.duration = (uint32_t)((1./(double)TMEDIA_CODEC_VIDEO(self)->out.fps) * TMEDIA_CODEC(self)->plugin->rate); TMEDIA_CODEC_VIDEO(self)->out.result.last_chunck = marker; TMEDIA_CODEC_VIDEO(self)->out.callback(&TMEDIA_CODEC_VIDEO(self)->out.result); } } static void tdav_codec_h263p_rtp_callback(tdav_codec_h263_t *self, const void *data, tsk_size_t size, tsk_bool_t frag, tsk_bool_t marker) { uint8_t* pdata = (uint8_t*)data; //uint8_t rtp_hdr[2] = {0x00, 0x00}; //tsk_bool_t eos = tsk_false; const void* _ptr = tsk_null; tsk_size_t _size = 0; //static tsk_bool_t frag = tsk_false; //tsk_bool_t found_gob = tsk_false; /* RFC 4629 - 5.1. General H.263+ Payload Header The H.263+ payload header is structured as follows: 0 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RR |P|V| PLEN |PEBIT| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ /* http://eu.sabotage.org/www/ITU/H/H0263e.pdf * * 5.1.1 Picture Start Code (PSC) (22 bits) * ->PSC is a word of 22 bits. Its value is 0000 0000 0000 0000 1 00000. * 5.1.27 End Of Sequence (EOS) (22 bits) * ->A codeword of 22 bits. Its value is 0000 0000 0000 0000 1 11111 * 5.2.2 Group of Block Start Code (GBSC) (17 bits) * ->A word of 17 bits. Its value is 0000 0000 0000 0000 1 * C.4.1 End Of Sub-Bitstream code (EOSBS) (23 bits) * ->The EOSBS code is a codeword of 23 bits. Its value is 0000 0000 0000 0000 1 11110 0 * * * 5.2.3 Group Number (GN) (5 bits) * -> last 5 bits */ //if(pdata[0] == 0x00 && pdata[1] == 0x00 && pdata[2] >= 0x80){ /* PSC or EOS or GBSC */ // uint8_t GN = ((pdata[2]>>2) & 0x1F); // found_gob = tsk_true; // //TSK_DEBUG_INFO("GN=%u", pdata[2]); // // /* RFC 4629 - 6.1.1. Packets that begin with a Picture Start Code // A packet that begins at the location of a Picture, GOB, slice, EOS, // or EOSBS start code shall omit the first two (all zero) bytes from // the H.263+ bitstream and signify their presence by setting P=1 in the // payload header. // */ // if(GN == 0x00){ /* PSC 00000 */ // /* Use the two first bytes as RTP header */ // //pdata[0] |= 0x04; // P=1 // /* // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | RR |1|V|0|0|0|0|0|0|0|0|0| bitstream data without the : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // : first two 0 bytes of the PSC // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // */ // //TSK_DEBUG_INFO("H263 - PSC"); // } // else if(GN == 0x1F){ /* EOS 11111 */ // /* Use the two first bytes as RTP header */ // //pdata[0] |= 0x04; // P=1 // eos = tsk_true; // /* RFC 4629 - 6.1.3. Packets that begin with an EOS or EOSBS Code // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | RR |1|V|0|0|0|0|0|0|0|0|0|1|1|1|1|1|1|0|0| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // */ // //TSK_DEBUG_INFO("H263 - EOS"); // } // else /*if((GN >> 4) == 0x01)*/{ /* GBSC 10000 */ // /* Use the two first bytes as RTP header */ // //pdata[0] |= 0x04; // P=1 // // /* RFC 4629 - 6.1.2. Packets that begin with GBSC or SSC // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | RR |1|V|0 0 1 0 0 1|PEBIT|1 0 0 0 0 0| picture header : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // : starting with TR, PTYPE ... | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... | bitstream : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // : data starting with GBSC/SSC without its first two 0 bytes // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // */ // //TSK_DEBUG_INFO("H263 - GBSC"); // found_gob = tsk_false; // } // //else if(EOSBS) -> Not Supported //} //else{ // /* 6.2. Encapsulating Follow-on Packet (P=0) */ // int i = 0; // i++; //} //if(/*eos*/!found_gob && frag){ // if(self->rtp.size < (size + 2/* H263+ Header size */)){ // if(!(self->rtp.ptr = tsk_realloc(self->rtp.ptr, (size + 2)))){ // TSK_DEBUG_ERROR("Failed to allocate new buffer"); // return; // } // self->rtp.size = (size + 2); // } // /* RFC 4629 - 6. Packetization Schemes */ // //rtp_hdr[0] |= 0x00; // //memcpy(self->rtp.ptr, rtp_hdr/* zeros-> is it corretc? */, 2); // //memcpy((self->rtp.ptr + 2), pdata, size); // //_ptr = self->rtp.ptr; // //_size = (size + 2); // pdata[0] |= pdata[2] > 0x80 ? 0x04 : 0x04; // _ptr = pdata; // _size = size; //} //else{ // pdata[0] |= pdata[2] > 0x80 ? 0x04 : 0x04; // _ptr = pdata; // _size = size; //} // FIXME pdata[0] |= pdata[2] > 0x80 ? 0x04 : 0x04; _ptr = pdata; _size = size; // Send data over the network if(TMEDIA_CODEC_VIDEO(self)->out.callback) { TMEDIA_CODEC_VIDEO(self)->out.result.buffer.ptr = _ptr; TMEDIA_CODEC_VIDEO(self)->out.result.buffer.size = _size; TMEDIA_CODEC_VIDEO(self)->out.result.duration = (uint32_t)((1./(double)TMEDIA_CODEC_VIDEO(self)->out.fps) * TMEDIA_CODEC(self)->plugin->rate); TMEDIA_CODEC_VIDEO(self)->out.result.last_chunck = marker; TMEDIA_CODEC_VIDEO(self)->out.callback(&TMEDIA_CODEC_VIDEO(self)->out.result); } } tsk_bool_t tdav_codec_ffmpeg_h263_is_supported() { return (avcodec_find_encoder(CODEC_ID_H263) && avcodec_find_decoder(CODEC_ID_H263)); } tsk_bool_t tdav_codec_ffmpeg_h263p_is_supported() { return (avcodec_find_encoder(CODEC_ID_H263P) && avcodec_find_decoder(CODEC_ID_H263)); } tsk_bool_t tdav_codec_ffmpeg_h263pp_is_supported() { return tdav_codec_ffmpeg_h263p_is_supported(); } #endif /* HAVE_FFMPEG */