2 * Common code for the RTP depacketization of MPEG-4 formats.
3 * Copyright (c) 2010 Fabrice Bellard
6 * This file is part of FFmpeg.
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.
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.
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
25 * @brief MPEG4 / RTP Code
26 * @author Fabrice Bellard
27 * @author Romain Degez
30 #include "rtpdec_formats.h"
32 #include "libavutil/attributes.h"
33 #include "libavutil/avstring.h"
34 #include "libavcodec/get_bits.h"
36 /** Structure listing useful vars to parse RTP packet payload */
37 struct PayloadContext
{
46 /** mpeg 4 AU headers */
57 int au_headers_allocated
;
59 int au_headers_length_bytes
;
62 uint8_t buf
[RTP_MAX_PACKET_LENGTH
];
63 int buf_pos
, buf_size
;
72 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
73 #define ATTR_NAME_TYPE_INT 0
74 #define ATTR_NAME_TYPE_STR 1
75 static const AttrNameMap attr_names
[] = {
76 { "SizeLength", ATTR_NAME_TYPE_INT
,
77 offsetof(PayloadContext
, sizelength
) },
78 { "IndexLength", ATTR_NAME_TYPE_INT
,
79 offsetof(PayloadContext
, indexlength
) },
80 { "IndexDeltaLength", ATTR_NAME_TYPE_INT
,
81 offsetof(PayloadContext
, indexdeltalength
) },
82 { "profile-level-id", ATTR_NAME_TYPE_INT
,
83 offsetof(PayloadContext
, profile_level_id
) },
84 { "StreamType", ATTR_NAME_TYPE_INT
,
85 offsetof(PayloadContext
, streamtype
) },
86 { "mode", ATTR_NAME_TYPE_STR
,
87 offsetof(PayloadContext
, mode
) },
91 static PayloadContext
*new_context(void)
93 return av_mallocz(sizeof(PayloadContext
));
96 static void free_context(PayloadContext
*data
)
98 av_free(data
->au_headers
);
103 static int parse_fmtp_config(AVCodecContext
*codec
, char *value
)
105 /* decode the hexa encoded parameter */
106 int len
= ff_hex_to_data(NULL
, value
);
107 av_free(codec
->extradata
);
108 if (ff_alloc_extradata(codec
, len
))
109 return AVERROR(ENOMEM
);
110 ff_hex_to_data(codec
->extradata
, value
);
114 static int rtp_parse_mp4_au(PayloadContext
*data
, const uint8_t *buf
, int len
)
116 int au_headers_length
, au_header_size
, i
;
117 GetBitContext getbitcontext
;
120 return AVERROR_INVALIDDATA
;
122 /* decode the first 2 bytes where the AUHeader sections are stored
124 au_headers_length
= AV_RB16(buf
);
126 if (au_headers_length
> RTP_MAX_PACKET_LENGTH
)
129 data
->au_headers_length_bytes
= (au_headers_length
+ 7) / 8;
131 /* skip AU headers length section (2 bytes) */
135 if (len
< data
->au_headers_length_bytes
)
136 return AVERROR_INVALIDDATA
;
138 init_get_bits(&getbitcontext
, buf
, data
->au_headers_length_bytes
* 8);
140 /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
141 au_header_size
= data
->sizelength
+ data
->indexlength
;
142 if (au_header_size
<= 0 || (au_headers_length
% au_header_size
!= 0))
145 data
->nb_au_headers
= au_headers_length
/ au_header_size
;
146 if (!data
->au_headers
|| data
->au_headers_allocated
< data
->nb_au_headers
) {
147 av_free(data
->au_headers
);
148 data
->au_headers
= av_malloc(sizeof(struct AUHeaders
) * data
->nb_au_headers
);
149 if (!data
->au_headers
)
150 return AVERROR(ENOMEM
);
151 data
->au_headers_allocated
= data
->nb_au_headers
;
154 for (i
= 0; i
< data
->nb_au_headers
; ++i
) {
155 data
->au_headers
[i
].size
= get_bits_long(&getbitcontext
, data
->sizelength
);
156 data
->au_headers
[i
].index
= get_bits_long(&getbitcontext
, data
->indexlength
);
163 /* Follows RFC 3640 */
164 static int aac_parse_packet(AVFormatContext
*ctx
, PayloadContext
*data
,
165 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
166 const uint8_t *buf
, int len
, uint16_t seq
,
172 if (data
->cur_au_index
> data
->nb_au_headers
)
173 return AVERROR_INVALIDDATA
;
174 if (data
->buf_size
- data
->buf_pos
< data
->au_headers
[data
->cur_au_index
].size
)
175 return AVERROR_INVALIDDATA
;
176 if ((ret
= av_new_packet(pkt
, data
->au_headers
[data
->cur_au_index
].size
)) < 0)
178 memcpy(pkt
->data
, &data
->buf
[data
->buf_pos
], data
->au_headers
[data
->cur_au_index
].size
);
179 data
->buf_pos
+= data
->au_headers
[data
->cur_au_index
].size
;
180 pkt
->stream_index
= st
->index
;
181 data
->cur_au_index
++;
182 return data
->cur_au_index
< data
->nb_au_headers
;
185 if (rtp_parse_mp4_au(data
, buf
, len
))
188 buf
+= data
->au_headers_length_bytes
+ 2;
189 len
-= data
->au_headers_length_bytes
+ 2;
191 if (len
< data
->au_headers
[0].size
)
192 return AVERROR_INVALIDDATA
;
193 if ((ret
= av_new_packet(pkt
, data
->au_headers
[0].size
)) < 0)
195 memcpy(pkt
->data
, buf
, data
->au_headers
[0].size
);
196 len
-= data
->au_headers
[0].size
;
197 buf
+= data
->au_headers
[0].size
;
198 pkt
->stream_index
= st
->index
;
200 if (len
> 0 && data
->nb_au_headers
> 1) {
201 data
->buf_size
= FFMIN(len
, sizeof(data
->buf
));
202 memcpy(data
->buf
, buf
, data
->buf_size
);
203 data
->cur_au_index
= 1;
211 static int parse_fmtp(AVFormatContext
*s
,
212 AVStream
*stream
, PayloadContext
*data
,
213 char *attr
, char *value
)
215 AVCodecContext
*codec
= stream
->codec
;
218 if (!strcmp(attr
, "config")) {
219 res
= parse_fmtp_config(codec
, value
);
225 if (codec
->codec_id
== AV_CODEC_ID_AAC
) {
226 /* Looking for a known attribute */
227 for (i
= 0; attr_names
[i
].str
; ++i
) {
228 if (!av_strcasecmp(attr
, attr_names
[i
].str
)) {
229 if (attr_names
[i
].type
== ATTR_NAME_TYPE_INT
) {
230 *(int *)((char *)data
+
231 attr_names
[i
].offset
) = atoi(value
);
232 } else if (attr_names
[i
].type
== ATTR_NAME_TYPE_STR
)
233 *(char **)((char *)data
+
234 attr_names
[i
].offset
) = av_strdup(value
);
241 static int parse_sdp_line(AVFormatContext
*s
, int st_index
,
242 PayloadContext
*data
, const char *line
)
249 if (av_strstart(line
, "fmtp:", &p
))
250 return ff_parse_fmtp(s
, s
->streams
[st_index
], data
, p
, parse_fmtp
);
255 static av_cold
int init_video(AVFormatContext
*s
, int st_index
,
256 PayloadContext
*data
)
260 s
->streams
[st_index
]->need_parsing
= AVSTREAM_PARSE_FULL
;
264 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler
= {
265 .enc_name
= "MP4V-ES",
266 .codec_type
= AVMEDIA_TYPE_VIDEO
,
267 .codec_id
= AV_CODEC_ID_MPEG4
,
269 .parse_sdp_a_line
= parse_sdp_line
,
272 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler
= {
273 .enc_name
= "mpeg4-generic",
274 .codec_type
= AVMEDIA_TYPE_AUDIO
,
275 .codec_id
= AV_CODEC_ID_AAC
,
276 .parse_sdp_a_line
= parse_sdp_line
,
277 .alloc
= new_context
,
278 .free
= free_context
,
279 .parse_packet
= aac_parse_packet