blob: 994ab49251769f8bdddbb9246237f1d18a10483c
1 | /* |
2 | * Common code for the RTP depacketization of MPEG-4 formats. |
3 | * Copyright (c) 2010 Fabrice Bellard |
4 | * Romain Degez |
5 | * |
6 | * This file is part of FFmpeg. |
7 | * |
8 | * FFmpeg is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2.1 of the License, or (at your option) any later version. |
12 | * |
13 | * FFmpeg is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with FFmpeg; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | */ |
22 | |
23 | /** |
24 | * @file |
25 | * @brief MPEG-4 / RTP Code |
26 | * @author Fabrice Bellard |
27 | * @author Romain Degez |
28 | */ |
29 | |
30 | #include "rtpdec_formats.h" |
31 | #include "internal.h" |
32 | #include "libavutil/attributes.h" |
33 | #include "libavutil/avstring.h" |
34 | #include "libavcodec/get_bits.h" |
35 | |
36 | #define MAX_AAC_HBR_FRAME_SIZE 8191 |
37 | |
38 | /** Structure listing useful vars to parse RTP packet payload */ |
39 | struct PayloadContext { |
40 | int sizelength; |
41 | int indexlength; |
42 | int indexdeltalength; |
43 | int profile_level_id; |
44 | int streamtype; |
45 | int objecttype; |
46 | char *mode; |
47 | |
48 | /** mpeg 4 AU headers */ |
49 | struct AUHeaders { |
50 | int size; |
51 | int index; |
52 | int cts_flag; |
53 | int cts; |
54 | int dts_flag; |
55 | int dts; |
56 | int rap_flag; |
57 | int streamstate; |
58 | } *au_headers; |
59 | int au_headers_allocated; |
60 | int nb_au_headers; |
61 | int au_headers_length_bytes; |
62 | int cur_au_index; |
63 | |
64 | uint8_t buf[FFMAX(RTP_MAX_PACKET_LENGTH, MAX_AAC_HBR_FRAME_SIZE)]; |
65 | int buf_pos, buf_size; |
66 | uint32_t timestamp; |
67 | }; |
68 | |
69 | typedef struct AttrNameMap { |
70 | const char *str; |
71 | uint16_t type; |
72 | uint32_t offset; |
73 | } AttrNameMap; |
74 | |
75 | /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */ |
76 | #define ATTR_NAME_TYPE_INT 0 |
77 | #define ATTR_NAME_TYPE_STR 1 |
78 | static const AttrNameMap attr_names[] = { |
79 | { "SizeLength", ATTR_NAME_TYPE_INT, |
80 | offsetof(PayloadContext, sizelength) }, |
81 | { "IndexLength", ATTR_NAME_TYPE_INT, |
82 | offsetof(PayloadContext, indexlength) }, |
83 | { "IndexDeltaLength", ATTR_NAME_TYPE_INT, |
84 | offsetof(PayloadContext, indexdeltalength) }, |
85 | { "profile-level-id", ATTR_NAME_TYPE_INT, |
86 | offsetof(PayloadContext, profile_level_id) }, |
87 | { "StreamType", ATTR_NAME_TYPE_INT, |
88 | offsetof(PayloadContext, streamtype) }, |
89 | { "mode", ATTR_NAME_TYPE_STR, |
90 | offsetof(PayloadContext, mode) }, |
91 | { NULL, -1, -1 }, |
92 | }; |
93 | |
94 | static void close_context(PayloadContext *data) |
95 | { |
96 | av_freep(&data->au_headers); |
97 | av_freep(&data->mode); |
98 | } |
99 | |
100 | static int parse_fmtp_config(AVCodecParameters *par, const char *value) |
101 | { |
102 | /* decode the hexa encoded parameter */ |
103 | int len = ff_hex_to_data(NULL, value); |
104 | av_freep(&par->extradata); |
105 | if (ff_alloc_extradata(par, len)) |
106 | return AVERROR(ENOMEM); |
107 | ff_hex_to_data(par->extradata, value); |
108 | return 0; |
109 | } |
110 | |
111 | static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf, int len) |
112 | { |
113 | int au_headers_length, au_header_size, i; |
114 | GetBitContext getbitcontext; |
115 | |
116 | if (len < 2) |
117 | return AVERROR_INVALIDDATA; |
118 | |
119 | /* decode the first 2 bytes where the AUHeader sections are stored |
120 | length in bits */ |
121 | au_headers_length = AV_RB16(buf); |
122 | |
123 | if (au_headers_length > RTP_MAX_PACKET_LENGTH) |
124 | return -1; |
125 | |
126 | data->au_headers_length_bytes = (au_headers_length + 7) / 8; |
127 | |
128 | /* skip AU headers length section (2 bytes) */ |
129 | buf += 2; |
130 | len -= 2; |
131 | |
132 | if (len < data->au_headers_length_bytes) |
133 | return AVERROR_INVALIDDATA; |
134 | |
135 | init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8); |
136 | |
137 | /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */ |
138 | au_header_size = data->sizelength + data->indexlength; |
139 | if (au_header_size <= 0 || (au_headers_length % au_header_size != 0)) |
140 | return -1; |
141 | |
142 | data->nb_au_headers = au_headers_length / au_header_size; |
143 | if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) { |
144 | av_free(data->au_headers); |
145 | data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers); |
146 | if (!data->au_headers) |
147 | return AVERROR(ENOMEM); |
148 | data->au_headers_allocated = data->nb_au_headers; |
149 | } |
150 | |
151 | for (i = 0; i < data->nb_au_headers; ++i) { |
152 | data->au_headers[i].size = get_bits_long(&getbitcontext, data->sizelength); |
153 | data->au_headers[i].index = get_bits_long(&getbitcontext, data->indexlength); |
154 | } |
155 | |
156 | return 0; |
157 | } |
158 | |
159 | |
160 | /* Follows RFC 3640 */ |
161 | static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data, |
162 | AVStream *st, AVPacket *pkt, uint32_t *timestamp, |
163 | const uint8_t *buf, int len, uint16_t seq, |
164 | int flags) |
165 | { |
166 | int ret; |
167 | |
168 | |
169 | if (!buf) { |
170 | if (data->cur_au_index > data->nb_au_headers) { |
171 | av_log(ctx, AV_LOG_ERROR, "Invalid parser state\n"); |
172 | return AVERROR_INVALIDDATA; |
173 | } |
174 | if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size) { |
175 | av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n"); |
176 | return AVERROR_INVALIDDATA; |
177 | } |
178 | if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0) { |
179 | av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); |
180 | return ret; |
181 | } |
182 | memcpy(pkt->data, &data->buf[data->buf_pos], data->au_headers[data->cur_au_index].size); |
183 | data->buf_pos += data->au_headers[data->cur_au_index].size; |
184 | pkt->stream_index = st->index; |
185 | data->cur_au_index++; |
186 | |
187 | if (data->cur_au_index == data->nb_au_headers) { |
188 | data->buf_pos = 0; |
189 | return 0; |
190 | } |
191 | |
192 | return 1; |
193 | } |
194 | |
195 | if (rtp_parse_mp4_au(data, buf, len)) { |
196 | av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n"); |
197 | return -1; |
198 | } |
199 | |
200 | buf += data->au_headers_length_bytes + 2; |
201 | len -= data->au_headers_length_bytes + 2; |
202 | if (data->nb_au_headers == 1 && len < data->au_headers[0].size) { |
203 | /* Packet is fragmented */ |
204 | |
205 | if (!data->buf_pos) { |
206 | if (data->au_headers[0].size > MAX_AAC_HBR_FRAME_SIZE) { |
207 | av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n"); |
208 | return AVERROR_INVALIDDATA; |
209 | } |
210 | |
211 | data->buf_size = data->au_headers[0].size; |
212 | data->timestamp = *timestamp; |
213 | } |
214 | |
215 | if (data->timestamp != *timestamp || |
216 | data->au_headers[0].size != data->buf_size || |
217 | data->buf_pos + len > MAX_AAC_HBR_FRAME_SIZE) { |
218 | data->buf_pos = 0; |
219 | data->buf_size = 0; |
220 | av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n"); |
221 | return AVERROR_INVALIDDATA; |
222 | } |
223 | |
224 | memcpy(&data->buf[data->buf_pos], buf, len); |
225 | data->buf_pos += len; |
226 | |
227 | if (!(flags & RTP_FLAG_MARKER)) |
228 | return AVERROR(EAGAIN); |
229 | |
230 | if (data->buf_pos != data->buf_size) { |
231 | data->buf_pos = 0; |
232 | av_log(ctx, AV_LOG_ERROR, "Missed some packets, discarding frame\n"); |
233 | return AVERROR_INVALIDDATA; |
234 | } |
235 | |
236 | data->buf_pos = 0; |
237 | ret = av_new_packet(pkt, data->buf_size); |
238 | if (ret < 0) { |
239 | av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); |
240 | return ret; |
241 | } |
242 | pkt->stream_index = st->index; |
243 | |
244 | memcpy(pkt->data, data->buf, data->buf_size); |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | if (len < data->au_headers[0].size) { |
250 | av_log(ctx, AV_LOG_ERROR, "First AU larger than packet size\n"); |
251 | return AVERROR_INVALIDDATA; |
252 | } |
253 | if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0) { |
254 | av_log(ctx, AV_LOG_ERROR, "Out of memory\n"); |
255 | return ret; |
256 | } |
257 | memcpy(pkt->data, buf, data->au_headers[0].size); |
258 | len -= data->au_headers[0].size; |
259 | buf += data->au_headers[0].size; |
260 | pkt->stream_index = st->index; |
261 | |
262 | if (len > 0 && data->nb_au_headers > 1) { |
263 | data->buf_size = FFMIN(len, sizeof(data->buf)); |
264 | memcpy(data->buf, buf, data->buf_size); |
265 | data->cur_au_index = 1; |
266 | data->buf_pos = 0; |
267 | return 1; |
268 | } |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | static int parse_fmtp(AVFormatContext *s, |
274 | AVStream *stream, PayloadContext *data, |
275 | const char *attr, const char *value) |
276 | { |
277 | AVCodecParameters *par = stream->codecpar; |
278 | int res, i; |
279 | |
280 | if (!strcmp(attr, "config")) { |
281 | res = parse_fmtp_config(par, value); |
282 | |
283 | if (res < 0) |
284 | return res; |
285 | } |
286 | |
287 | if (par->codec_id == AV_CODEC_ID_AAC) { |
288 | /* Looking for a known attribute */ |
289 | for (i = 0; attr_names[i].str; ++i) { |
290 | if (!av_strcasecmp(attr, attr_names[i].str)) { |
291 | if (attr_names[i].type == ATTR_NAME_TYPE_INT) { |
292 | int val = atoi(value); |
293 | if (val > 32) { |
294 | av_log(s, AV_LOG_ERROR, |
295 | "The %s field size is invalid (%d)\n", |
296 | attr, val); |
297 | return AVERROR_INVALIDDATA; |
298 | } |
299 | *(int *)((char *)data+ |
300 | attr_names[i].offset) = val; |
301 | } else if (attr_names[i].type == ATTR_NAME_TYPE_STR) { |
302 | char *val = av_strdup(value); |
303 | if (!val) |
304 | return AVERROR(ENOMEM); |
305 | *(char **)((char *)data+ |
306 | attr_names[i].offset) = val; |
307 | } |
308 | } |
309 | } |
310 | } |
311 | return 0; |
312 | } |
313 | |
314 | static int parse_sdp_line(AVFormatContext *s, int st_index, |
315 | PayloadContext *data, const char *line) |
316 | { |
317 | const char *p; |
318 | |
319 | if (st_index < 0) |
320 | return 0; |
321 | |
322 | if (av_strstart(line, "fmtp:", &p)) |
323 | return ff_parse_fmtp(s, s->streams[st_index], data, p, parse_fmtp); |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { |
329 | .enc_name = "MP4V-ES", |
330 | .codec_type = AVMEDIA_TYPE_VIDEO, |
331 | .codec_id = AV_CODEC_ID_MPEG4, |
332 | .need_parsing = AVSTREAM_PARSE_FULL, |
333 | .priv_data_size = sizeof(PayloadContext), |
334 | .parse_sdp_a_line = parse_sdp_line, |
335 | }; |
336 | |
337 | RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { |
338 | .enc_name = "mpeg4-generic", |
339 | .codec_type = AVMEDIA_TYPE_AUDIO, |
340 | .codec_id = AV_CODEC_ID_AAC, |
341 | .priv_data_size = sizeof(PayloadContext), |
342 | .parse_sdp_a_line = parse_sdp_line, |
343 | .close = close_context, |
344 | .parse_packet = aac_parse_packet, |
345 | }; |
346 |