00001
00030 #include "rtpdec_formats.h"
00031 #include "internal.h"
00032 #include "libavutil/avstring.h"
00033 #include "libavcodec/get_bits.h"
00034
00036 struct PayloadContext
00037 {
00038 int sizelength;
00039 int indexlength;
00040 int indexdeltalength;
00041 int profile_level_id;
00042 int streamtype;
00043 int objecttype;
00044 char *mode;
00045
00047 struct AUHeaders {
00048 int size;
00049 int index;
00050 int cts_flag;
00051 int cts;
00052 int dts_flag;
00053 int dts;
00054 int rap_flag;
00055 int streamstate;
00056 } *au_headers;
00057 int au_headers_allocated;
00058 int nb_au_headers;
00059 int au_headers_length_bytes;
00060 int cur_au_index;
00061 };
00062
00063 typedef struct {
00064 const char *str;
00065 uint16_t type;
00066 uint32_t offset;
00067 } AttrNameMap;
00068
00069
00070 #define ATTR_NAME_TYPE_INT 0
00071 #define ATTR_NAME_TYPE_STR 1
00072 static const AttrNameMap attr_names[]=
00073 {
00074 { "SizeLength", ATTR_NAME_TYPE_INT,
00075 offsetof(PayloadContext, sizelength) },
00076 { "IndexLength", ATTR_NAME_TYPE_INT,
00077 offsetof(PayloadContext, indexlength) },
00078 { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
00079 offsetof(PayloadContext, indexdeltalength) },
00080 { "profile-level-id", ATTR_NAME_TYPE_INT,
00081 offsetof(PayloadContext, profile_level_id) },
00082 { "StreamType", ATTR_NAME_TYPE_INT,
00083 offsetof(PayloadContext, streamtype) },
00084 { "mode", ATTR_NAME_TYPE_STR,
00085 offsetof(PayloadContext, mode) },
00086 { NULL, -1, -1 },
00087 };
00088
00089 static PayloadContext *new_context(void)
00090 {
00091 return av_mallocz(sizeof(PayloadContext));
00092 }
00093
00094 static void free_context(PayloadContext * data)
00095 {
00096 int i;
00097 for (i = 0; i < data->nb_au_headers; i++) {
00098
00099
00100
00101
00102
00103 av_free(&data->au_headers[i]);
00104 }
00105 av_free(data->mode);
00106 av_free(data);
00107 }
00108
00109 static int parse_fmtp_config(AVCodecContext * codec, char *value)
00110 {
00111
00112 int len = ff_hex_to_data(NULL, value);
00113 av_free(codec->extradata);
00114 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00115 if (!codec->extradata)
00116 return AVERROR(ENOMEM);
00117 codec->extradata_size = len;
00118 ff_hex_to_data(codec->extradata, value);
00119 return 0;
00120 }
00121
00122 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
00123 {
00124 int au_headers_length, au_header_size, i;
00125 GetBitContext getbitcontext;
00126
00127
00128
00129 au_headers_length = AV_RB16(buf);
00130
00131 if (au_headers_length > RTP_MAX_PACKET_LENGTH)
00132 return -1;
00133
00134 data->au_headers_length_bytes = (au_headers_length + 7) / 8;
00135
00136
00137 buf += 2;
00138
00139 init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
00140
00141
00142 au_header_size = data->sizelength + data->indexlength;
00143 if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
00144 return -1;
00145
00146 data->nb_au_headers = au_headers_length / au_header_size;
00147 if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
00148 av_free(data->au_headers);
00149 data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
00150 data->au_headers_allocated = data->nb_au_headers;
00151 }
00152
00153
00154
00155
00156 data->au_headers[0].size = 0;
00157 data->au_headers[0].index = 0;
00158 for (i = 0; i < data->nb_au_headers; ++i) {
00159 data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
00160 data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
00161 }
00162
00163 data->nb_au_headers = 1;
00164
00165 return 0;
00166 }
00167
00168
00169
00170 static int aac_parse_packet(AVFormatContext *ctx,
00171 PayloadContext *data,
00172 AVStream *st,
00173 AVPacket *pkt,
00174 uint32_t *timestamp,
00175 const uint8_t *buf, int len, int flags)
00176 {
00177 if (rtp_parse_mp4_au(data, buf))
00178 return -1;
00179
00180 buf += data->au_headers_length_bytes + 2;
00181 len -= data->au_headers_length_bytes + 2;
00182
00183
00184
00185 av_new_packet(pkt, data->au_headers[0].size);
00186 memcpy(pkt->data, buf, data->au_headers[0].size);
00187
00188 pkt->stream_index = st->index;
00189 return 0;
00190 }
00191
00192 static int parse_fmtp(AVStream *stream, PayloadContext *data,
00193 char *attr, char *value)
00194 {
00195 AVCodecContext *codec = stream->codec;
00196 int res, i;
00197
00198 if (!strcmp(attr, "config")) {
00199 res = parse_fmtp_config(codec, value);
00200
00201 if (res < 0)
00202 return res;
00203 }
00204
00205 if (codec->codec_id == CODEC_ID_AAC) {
00206
00207 for (i = 0; attr_names[i].str; ++i) {
00208 if (!av_strcasecmp(attr, attr_names[i].str)) {
00209 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
00210 *(int *)((char *)data+
00211 attr_names[i].offset) = atoi(value);
00212 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
00213 *(char **)((char *)data+
00214 attr_names[i].offset) = av_strdup(value);
00215 }
00216 }
00217 }
00218 return 0;
00219 }
00220
00221 static int parse_sdp_line(AVFormatContext *s, int st_index,
00222 PayloadContext *data, const char *line)
00223 {
00224 const char *p;
00225
00226 if (av_strstart(line, "fmtp:", &p))
00227 return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
00228
00229 return 0;
00230 }
00231
00232 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
00233 .enc_name = "MP4V-ES",
00234 .codec_type = AVMEDIA_TYPE_VIDEO,
00235 .codec_id = CODEC_ID_MPEG4,
00236 .parse_sdp_a_line = parse_sdp_line,
00237 };
00238
00239 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
00240 .enc_name = "mpeg4-generic",
00241 .codec_type = AVMEDIA_TYPE_AUDIO,
00242 .codec_id = CODEC_ID_AAC,
00243 .parse_sdp_a_line = parse_sdp_line,
00244 .alloc = new_context,
00245 .free = free_context,
00246 .parse_packet = aac_parse_packet
00247 };