loco: return meaningful error codes.
[ffmpeg.git] / libavformat / rtpdec_mpeg4.c
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 Libav.
7  *
8  * Libav 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  * Libav 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 Libav; 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 MPEG4 / RTP Code
26  * @author Fabrice Bellard
27  * @author Romain Degez
28  */
29
30 #include "rtpdec_formats.h"
31 #include "internal.h"
32 #include "libavutil/avstring.h"
33 #include "libavcodec/get_bits.h"
34
35 /** Structure listing useful vars to parse RTP packet payload */
36 struct PayloadContext {
37     int sizelength;
38     int indexlength;
39     int indexdeltalength;
40     int profile_level_id;
41     int streamtype;
42     int objecttype;
43     char *mode;
44
45     /** mpeg 4 AU headers */
46     struct AUHeaders {
47         int size;
48         int index;
49         int cts_flag;
50         int cts;
51         int dts_flag;
52         int dts;
53         int rap_flag;
54         int streamstate;
55     } *au_headers;
56     int au_headers_allocated;
57     int nb_au_headers;
58     int au_headers_length_bytes;
59     int cur_au_index;
60 };
61
62 typedef struct {
63     const char *str;
64     uint16_t    type;
65     uint32_t    offset;
66 } AttrNameMap;
67
68 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
69 #define ATTR_NAME_TYPE_INT 0
70 #define ATTR_NAME_TYPE_STR 1
71 static const AttrNameMap attr_names[] = {
72     { "SizeLength",       ATTR_NAME_TYPE_INT,
73       offsetof(PayloadContext, sizelength) },
74     { "IndexLength",      ATTR_NAME_TYPE_INT,
75       offsetof(PayloadContext, indexlength) },
76     { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
77       offsetof(PayloadContext, indexdeltalength) },
78     { "profile-level-id", ATTR_NAME_TYPE_INT,
79       offsetof(PayloadContext, profile_level_id) },
80     { "StreamType",       ATTR_NAME_TYPE_INT,
81       offsetof(PayloadContext, streamtype) },
82     { "mode",             ATTR_NAME_TYPE_STR,
83       offsetof(PayloadContext, mode) },
84     { NULL, -1, -1 },
85 };
86
87 static PayloadContext *new_context(void)
88 {
89     return av_mallocz(sizeof(PayloadContext));
90 }
91
92 static void free_context(PayloadContext *data)
93 {
94     av_free(data->au_headers);
95     av_free(data->mode);
96     av_free(data);
97 }
98
99 static int parse_fmtp_config(AVCodecContext *codec, char *value)
100 {
101     /* decode the hexa encoded parameter */
102     int len = ff_hex_to_data(NULL, value);
103     av_free(codec->extradata);
104     codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
105     if (!codec->extradata)
106         return AVERROR(ENOMEM);
107     codec->extradata_size = len;
108     ff_hex_to_data(codec->extradata, value);
109     return 0;
110 }
111
112 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
113 {
114     int au_headers_length, au_header_size, i;
115     GetBitContext getbitcontext;
116
117     /* decode the first 2 bytes where the AUHeader sections are stored
118        length in bits */
119     au_headers_length = AV_RB16(buf);
120
121     if (au_headers_length > RTP_MAX_PACKET_LENGTH)
122       return -1;
123
124     data->au_headers_length_bytes = (au_headers_length + 7) / 8;
125
126     /* skip AU headers length section (2 bytes) */
127     buf += 2;
128
129     init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
130
131     /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
132     au_header_size = data->sizelength + data->indexlength;
133     if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
134         return -1;
135
136     data->nb_au_headers = au_headers_length / au_header_size;
137     if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
138         av_free(data->au_headers);
139         data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
140         data->au_headers_allocated = data->nb_au_headers;
141     }
142
143     /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving)
144        In my test, the FAAD decoder does not behave correctly when sending each AU one by one
145        but does when sending the whole as one big packet...  */
146     data->au_headers[0].size = 0;
147     data->au_headers[0].index = 0;
148     for (i = 0; i < data->nb_au_headers; ++i) {
149         data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
150         data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
151     }
152
153     data->nb_au_headers = 1;
154
155     return 0;
156 }
157
158
159 /* Follows RFC 3640 */
160 static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
161                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
162                             const uint8_t *buf, int len, uint16_t seq,
163                             int flags)
164 {
165     if (rtp_parse_mp4_au(data, buf))
166         return -1;
167
168     buf += data->au_headers_length_bytes + 2;
169     len -= data->au_headers_length_bytes + 2;
170
171     /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define
172                     one au_header */
173     av_new_packet(pkt, data->au_headers[0].size);
174     memcpy(pkt->data, buf, data->au_headers[0].size);
175
176     pkt->stream_index = st->index;
177     return 0;
178 }
179
180 static int parse_fmtp(AVStream *stream, PayloadContext *data,
181                       char *attr, char *value)
182 {
183     AVCodecContext *codec = stream->codec;
184     int res, i;
185
186     if (!strcmp(attr, "config")) {
187         res = parse_fmtp_config(codec, value);
188
189         if (res < 0)
190             return res;
191     }
192
193     if (codec->codec_id == AV_CODEC_ID_AAC) {
194         /* Looking for a known attribute */
195         for (i = 0; attr_names[i].str; ++i) {
196             if (!av_strcasecmp(attr, attr_names[i].str)) {
197                 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
198                     *(int *)((char *)data+
199                         attr_names[i].offset) = atoi(value);
200                 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
201                     *(char **)((char *)data+
202                         attr_names[i].offset) = av_strdup(value);
203             }
204         }
205     }
206     return 0;
207 }
208
209 static int parse_sdp_line(AVFormatContext *s, int st_index,
210                           PayloadContext *data, const char *line)
211 {
212     const char *p;
213
214     if (st_index < 0)
215         return 0;
216
217     if (av_strstart(line, "fmtp:", &p))
218         return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
219
220     return 0;
221 }
222
223 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
224     .enc_name           = "MP4V-ES",
225     .codec_type         = AVMEDIA_TYPE_VIDEO,
226     .codec_id           = AV_CODEC_ID_MPEG4,
227     .parse_sdp_a_line   = parse_sdp_line,
228 };
229
230 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
231     .enc_name           = "mpeg4-generic",
232     .codec_type         = AVMEDIA_TYPE_AUDIO,
233     .codec_id           = AV_CODEC_ID_AAC,
234     .parse_sdp_a_line   = parse_sdp_line,
235     .alloc              = new_context,
236     .free               = free_context,
237     .parse_packet       = aac_parse_packet
238 };