Libav 0.7.1
|
00001 00030 #include "rtpdec_formats.h" 00031 #include "internal.h" 00032 #include "libavutil/avstring.h" 00033 #include "libavcodec/get_bits.h" 00034 #include <strings.h> 00035 00037 struct PayloadContext 00038 { 00039 int sizelength; 00040 int indexlength; 00041 int indexdeltalength; 00042 int profile_level_id; 00043 int streamtype; 00044 int objecttype; 00045 char *mode; 00046 00048 struct AUHeaders { 00049 int size; 00050 int index; 00051 int cts_flag; 00052 int cts; 00053 int dts_flag; 00054 int dts; 00055 int rap_flag; 00056 int streamstate; 00057 } *au_headers; 00058 int au_headers_allocated; 00059 int nb_au_headers; 00060 int au_headers_length_bytes; 00061 int cur_au_index; 00062 }; 00063 00064 typedef struct { 00065 const char *str; 00066 uint16_t type; 00067 uint32_t offset; 00068 } AttrNameMap; 00069 00070 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */ 00071 #define ATTR_NAME_TYPE_INT 0 00072 #define ATTR_NAME_TYPE_STR 1 00073 static const AttrNameMap attr_names[]= 00074 { 00075 { "SizeLength", ATTR_NAME_TYPE_INT, 00076 offsetof(PayloadContext, sizelength) }, 00077 { "IndexLength", ATTR_NAME_TYPE_INT, 00078 offsetof(PayloadContext, indexlength) }, 00079 { "IndexDeltaLength", ATTR_NAME_TYPE_INT, 00080 offsetof(PayloadContext, indexdeltalength) }, 00081 { "profile-level-id", ATTR_NAME_TYPE_INT, 00082 offsetof(PayloadContext, profile_level_id) }, 00083 { "StreamType", ATTR_NAME_TYPE_INT, 00084 offsetof(PayloadContext, streamtype) }, 00085 { "mode", ATTR_NAME_TYPE_STR, 00086 offsetof(PayloadContext, mode) }, 00087 { NULL, -1, -1 }, 00088 }; 00089 00090 static PayloadContext *new_context(void) 00091 { 00092 return av_mallocz(sizeof(PayloadContext)); 00093 } 00094 00095 static void free_context(PayloadContext * data) 00096 { 00097 int i; 00098 for (i = 0; i < data->nb_au_headers; i++) { 00099 /* according to rtp_parse_mp4_au, we treat multiple 00100 * au headers as one, so nb_au_headers is always 1. 00101 * loop anyway in case this changes. 00102 * (note: changes done carelessly might lead to a double free) 00103 */ 00104 av_free(&data->au_headers[i]); 00105 } 00106 av_free(data->mode); 00107 av_free(data); 00108 } 00109 00110 static int parse_fmtp_config(AVCodecContext * codec, char *value) 00111 { 00112 /* decode the hexa encoded parameter */ 00113 int len = ff_hex_to_data(NULL, value); 00114 av_free(codec->extradata); 00115 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); 00116 if (!codec->extradata) 00117 return AVERROR(ENOMEM); 00118 codec->extradata_size = len; 00119 ff_hex_to_data(codec->extradata, value); 00120 return 0; 00121 } 00122 00123 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf) 00124 { 00125 int au_headers_length, au_header_size, i; 00126 GetBitContext getbitcontext; 00127 00128 /* decode the first 2 bytes where the AUHeader sections are stored 00129 length in bits */ 00130 au_headers_length = AV_RB16(buf); 00131 00132 if (au_headers_length > RTP_MAX_PACKET_LENGTH) 00133 return -1; 00134 00135 data->au_headers_length_bytes = (au_headers_length + 7) / 8; 00136 00137 /* skip AU headers length section (2 bytes) */ 00138 buf += 2; 00139 00140 init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8); 00141 00142 /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */ 00143 au_header_size = data->sizelength + data->indexlength; 00144 if (au_header_size <= 0 || (au_headers_length % au_header_size != 0)) 00145 return -1; 00146 00147 data->nb_au_headers = au_headers_length / au_header_size; 00148 if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) { 00149 av_free(data->au_headers); 00150 data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers); 00151 data->au_headers_allocated = data->nb_au_headers; 00152 } 00153 00154 /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving) 00155 In my test, the FAAD decoder does not behave correctly when sending each AU one by one 00156 but does when sending the whole as one big packet... */ 00157 data->au_headers[0].size = 0; 00158 data->au_headers[0].index = 0; 00159 for (i = 0; i < data->nb_au_headers; ++i) { 00160 data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength); 00161 data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength); 00162 } 00163 00164 data->nb_au_headers = 1; 00165 00166 return 0; 00167 } 00168 00169 00170 /* Follows RFC 3640 */ 00171 static int aac_parse_packet(AVFormatContext *ctx, 00172 PayloadContext *data, 00173 AVStream *st, 00174 AVPacket *pkt, 00175 uint32_t *timestamp, 00176 const uint8_t *buf, int len, int flags) 00177 { 00178 if (rtp_parse_mp4_au(data, buf)) 00179 return -1; 00180 00181 buf += data->au_headers_length_bytes + 2; 00182 len -= data->au_headers_length_bytes + 2; 00183 00184 /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define 00185 one au_header */ 00186 av_new_packet(pkt, data->au_headers[0].size); 00187 memcpy(pkt->data, buf, data->au_headers[0].size); 00188 00189 pkt->stream_index = st->index; 00190 return 0; 00191 } 00192 00193 static int parse_fmtp(AVStream *stream, PayloadContext *data, 00194 char *attr, char *value) 00195 { 00196 AVCodecContext *codec = stream->codec; 00197 int res, i; 00198 00199 if (!strcmp(attr, "config")) { 00200 res = parse_fmtp_config(codec, value); 00201 00202 if (res < 0) 00203 return res; 00204 } 00205 00206 if (codec->codec_id == CODEC_ID_AAC) { 00207 /* Looking for a known attribute */ 00208 for (i = 0; attr_names[i].str; ++i) { 00209 if (!strcasecmp(attr, attr_names[i].str)) { 00210 if (attr_names[i].type == ATTR_NAME_TYPE_INT) { 00211 *(int *)((char *)data+ 00212 attr_names[i].offset) = atoi(value); 00213 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR) 00214 *(char **)((char *)data+ 00215 attr_names[i].offset) = av_strdup(value); 00216 } 00217 } 00218 } 00219 return 0; 00220 } 00221 00222 static int parse_sdp_line(AVFormatContext *s, int st_index, 00223 PayloadContext *data, const char *line) 00224 { 00225 const char *p; 00226 00227 if (av_strstart(line, "fmtp:", &p)) 00228 return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp); 00229 00230 return 0; 00231 } 00232 00233 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { 00234 .enc_name = "MP4V-ES", 00235 .codec_type = AVMEDIA_TYPE_VIDEO, 00236 .codec_id = CODEC_ID_MPEG4, 00237 .parse_sdp_a_line = parse_sdp_line, 00238 .alloc = NULL, 00239 .free = NULL, 00240 .parse_packet = NULL 00241 }; 00242 00243 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { 00244 .enc_name = "mpeg4-generic", 00245 .codec_type = AVMEDIA_TYPE_AUDIO, 00246 .codec_id = CODEC_ID_AAC, 00247 .parse_sdp_a_line = parse_sdp_line, 00248 .alloc = new_context, 00249 .free = free_context, 00250 .parse_packet = aac_parse_packet 00251 };