]> git.sesse.net Git - ffmpeg/blob - libavformat/rtpdec_xiph.c
oggspeexparse: fix array overread
[ffmpeg] / libavformat / rtpdec_xiph.c
1 /*
2  * Xiph RTP Protocols
3  * Copyright (c) 2009 Colin McQuillian
4  * Copyright (c) 2010 Josh Allmann
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 Xiph / RTP Code
26  * @author Colin McQuillan <m.niloc@gmail.com>
27  * @author Josh Allmann <joshua.allmann@gmail.com>
28  */
29
30 #include "libavutil/avassert.h"
31 #include "libavutil/avstring.h"
32 #include "libavutil/base64.h"
33 #include "libavcodec/bytestream.h"
34
35 #include "rtpdec.h"
36 #include "rtpdec_formats.h"
37
38 /**
39  * RTP/Xiph specific private data.
40  */
41 struct PayloadContext {
42     unsigned ident;             ///< 24-bit stream configuration identifier
43     uint32_t timestamp;
44     AVIOContext* fragment;    ///< buffer for split payloads
45     uint8_t *split_buf;
46     int split_pos, split_buf_len, split_buf_size;
47     int split_pkts;
48 };
49
50 static PayloadContext *xiph_new_context(void)
51 {
52     return av_mallocz(sizeof(PayloadContext));
53 }
54
55 static inline void free_fragment_if_needed(PayloadContext * data)
56 {
57     if (data->fragment) {
58         uint8_t* p;
59         avio_close_dyn_buf(data->fragment, &p);
60         av_free(p);
61         data->fragment = NULL;
62     }
63 }
64
65 static void xiph_free_context(PayloadContext * data)
66 {
67     free_fragment_if_needed(data);
68     av_free(data->split_buf);
69     av_free(data);
70 }
71
72 static int xiph_handle_packet(AVFormatContext * ctx,
73                               PayloadContext * data,
74                               AVStream * st,
75                               AVPacket * pkt,
76                               uint32_t * timestamp,
77                               const uint8_t * buf, int len, int flags)
78 {
79
80     int ident, fragmented, tdt, num_pkts, pkt_len;
81
82     if (!buf) {
83         if (!data->split_buf || data->split_pos + 2 > data->split_buf_len ||
84             data->split_pkts <= 0) {
85             av_log(ctx, AV_LOG_ERROR, "No more data to return\n");
86             return AVERROR_INVALIDDATA;
87         }
88         pkt_len = AV_RB16(data->split_buf + data->split_pos);
89         data->split_pos += 2;
90         if (data->split_pos + pkt_len > data->split_buf_len) {
91             av_log(ctx, AV_LOG_ERROR, "Not enough data to return\n");
92             return AVERROR_INVALIDDATA;
93         }
94         if (av_new_packet(pkt, pkt_len)) {
95             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
96             return AVERROR(ENOMEM);
97         }
98         pkt->stream_index = st->index;
99         memcpy(pkt->data, data->split_buf + data->split_pos, pkt_len);
100         data->split_pos += pkt_len;
101         data->split_pkts--;
102         return data->split_pkts > 0;
103     }
104
105     if (len < 6) {
106         av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
107         return AVERROR_INVALIDDATA;
108     }
109
110     // read xiph rtp headers
111     ident       = AV_RB24(buf);
112     fragmented  = buf[3] >> 6;
113     tdt         = (buf[3] >> 4) & 3;
114     num_pkts    = buf[3] & 0xf;
115     pkt_len     = AV_RB16(buf + 4);
116
117     if (pkt_len > len - 6) {
118         av_log(ctx, AV_LOG_ERROR,
119                "Invalid packet length %d in %d byte packet\n", pkt_len,
120                len);
121         return AVERROR_INVALIDDATA;
122     }
123
124     if (ident != data->ident) {
125         av_log(ctx, AV_LOG_ERROR,
126                "Unimplemented Xiph SDP configuration change detected\n");
127         return AVERROR_PATCHWELCOME;
128     }
129
130     if (tdt) {
131         av_log(ctx, AV_LOG_ERROR,
132                "Unimplemented RTP Xiph packet settings (%d,%d,%d)\n",
133                fragmented, tdt, num_pkts);
134         return AVERROR_PATCHWELCOME;
135     }
136
137     buf += 6; // move past header bits
138     len -= 6;
139
140     if (fragmented == 0) {
141         if (av_new_packet(pkt, pkt_len)) {
142             av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
143             return AVERROR(ENOMEM);
144         }
145         pkt->stream_index = st->index;
146         memcpy(pkt->data, buf, pkt_len);
147         buf += pkt_len;
148         len -= pkt_len;
149         num_pkts--;
150
151         if (num_pkts > 0) {
152             if (len > data->split_buf_size || !data->split_buf) {
153                 av_freep(&data->split_buf);
154                 data->split_buf_size = 2 * len;
155                 data->split_buf = av_malloc(data->split_buf_size);
156                 if (!data->split_buf) {
157                     av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
158                     av_free_packet(pkt);
159                     return AVERROR(ENOMEM);
160                 }
161             }
162             memcpy(data->split_buf, buf, len);
163             data->split_buf_len = len;
164             data->split_pos = 0;
165             data->split_pkts = num_pkts;
166             return 1;
167         }
168
169         return 0;
170
171     } else if (fragmented == 1) {
172         // start of xiph data fragment
173         int res;
174
175         // end packet has been lost somewhere, so drop buffered data
176         free_fragment_if_needed(data);
177
178         if((res = avio_open_dyn_buf(&data->fragment)) < 0)
179             return res;
180
181         avio_write(data->fragment, buf, pkt_len);
182         data->timestamp = *timestamp;
183
184     } else {
185         av_assert1(fragmented < 4);
186         if (data->timestamp != *timestamp) {
187             // skip if fragmented timestamp is incorrect;
188             // a start packet has been lost somewhere
189             free_fragment_if_needed(data);
190             av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n");
191             return AVERROR_INVALIDDATA;
192         }
193         if (!data->fragment) {
194             av_log(ctx, AV_LOG_WARNING,
195                    "Received packet without a start fragment; dropping.\n");
196             return AVERROR(EAGAIN);
197         }
198
199         // copy data to fragment buffer
200         avio_write(data->fragment, buf, pkt_len);
201
202         if (fragmented == 3) {
203             // end of xiph data packet
204             int ret = ff_rtp_finalize_packet(pkt, &data->fragment, st->index);
205             if (ret < 0) {
206                 av_log(ctx, AV_LOG_ERROR,
207                        "Error occurred when getting fragment buffer.");
208                 return ret;
209             }
210
211             return 0;
212         }
213     }
214
215    return AVERROR(EAGAIN);
216 }
217
218 /**
219  * Length encoding described in RFC5215 section 3.1.1.
220  */
221 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
222 {
223     int n = 0;
224     for (; *buf < buf_end; ++*buf) {
225         n <<= 7;
226         n += **buf & 0x7f;
227         if (!(**buf & 0x80)) {
228             ++*buf;
229             return n;
230         }
231     }
232     return 0;
233 }
234
235 /**
236  * Based off parse_packed_headers in Vorbis RTP
237  */
238 static int
239 parse_packed_headers(const uint8_t * packed_headers,
240                      const uint8_t * packed_headers_end,
241                      AVCodecContext * codec, PayloadContext * xiph_data)
242 {
243
244     unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
245     uint8_t *ptr;
246
247     if (packed_headers_end - packed_headers < 9) {
248         av_log(codec, AV_LOG_ERROR,
249                "Invalid %td byte packed header.",
250                packed_headers_end - packed_headers);
251         return AVERROR_INVALIDDATA;
252     }
253
254     num_packed         = bytestream_get_be32(&packed_headers);
255     xiph_data->ident   = bytestream_get_be24(&packed_headers);
256     length             = bytestream_get_be16(&packed_headers);
257     num_headers        = get_base128(&packed_headers, packed_headers_end);
258     length1            = get_base128(&packed_headers, packed_headers_end);
259     length2            = get_base128(&packed_headers, packed_headers_end);
260
261     if (num_packed != 1 || num_headers > 3) {
262         av_log(codec, AV_LOG_ERROR,
263                "Unimplemented number of headers: %d packed headers, %d headers\n",
264                num_packed, num_headers);
265         return AVERROR_PATCHWELCOME;
266     }
267
268     if (packed_headers_end - packed_headers != length ||
269         length1 > length || length2 > length - length1) {
270         av_log(codec, AV_LOG_ERROR,
271                "Bad packed header lengths (%d,%d,%td,%d)\n", length1,
272                length2, packed_headers_end - packed_headers, length);
273         return AVERROR_INVALIDDATA;
274     }
275
276     /* allocate extra space:
277      * -- length/255 +2 for xiphlacing
278      * -- one for the '2' marker
279      * -- FF_INPUT_BUFFER_PADDING_SIZE required */
280     extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
281
282     ptr = codec->extradata = av_malloc(extradata_alloc);
283     if (!ptr) {
284         av_log(codec, AV_LOG_ERROR, "Out of memory\n");
285         return AVERROR(ENOMEM);
286     }
287     *ptr++ = 2;
288     ptr += av_xiphlacing(ptr, length1);
289     ptr += av_xiphlacing(ptr, length2);
290     memcpy(ptr, packed_headers, length);
291     ptr += length;
292     codec->extradata_size = ptr - codec->extradata;
293     // clear out remaining parts of the buffer
294     memset(ptr, 0, extradata_alloc - codec->extradata_size);
295
296     return 0;
297 }
298
299 static int xiph_parse_fmtp_pair(AVStream* stream,
300                                 PayloadContext *xiph_data,
301                                 char *attr, char *value)
302 {
303     AVCodecContext *codec = stream->codec;
304     int result = 0;
305
306     if (!strcmp(attr, "sampling")) {
307         if (!strcmp(value, "YCbCr-4:2:0")) {
308             codec->pix_fmt = AV_PIX_FMT_YUV420P;
309         } else if (!strcmp(value, "YCbCr-4:4:2")) {
310             codec->pix_fmt = AV_PIX_FMT_YUV422P;
311         } else if (!strcmp(value, "YCbCr-4:4:4")) {
312             codec->pix_fmt = AV_PIX_FMT_YUV444P;
313         } else {
314             av_log(codec, AV_LOG_ERROR,
315                    "Unsupported pixel format %s\n", attr);
316             return AVERROR_INVALIDDATA;
317         }
318     } else if (!strcmp(attr, "width")) {
319         /* This is an integer between 1 and 1048561
320          * and MUST be in multiples of 16. */
321         codec->width = atoi(value);
322         return 0;
323     } else if (!strcmp(attr, "height")) {
324         /* This is an integer between 1 and 1048561
325          * and MUST be in multiples of 16. */
326         codec->height = atoi(value);
327         return 0;
328     } else if (!strcmp(attr, "delivery-method")) {
329         /* Possible values are: inline, in_band, out_band/specific_name. */
330         return AVERROR_PATCHWELCOME;
331     } else if (!strcmp(attr, "configuration-uri")) {
332         /* NOTE: configuration-uri is supported only under 2 conditions:
333          *--after the delivery-method tag
334          * --with a delivery-method value of out_band */
335         return AVERROR_PATCHWELCOME;
336     } else if (!strcmp(attr, "configuration")) {
337         /* NOTE: configuration is supported only AFTER the delivery-method tag
338          * The configuration value is a base64 encoded packed header */
339         uint8_t *decoded_packet = NULL;
340         int packet_size;
341         size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
342
343         if (decoded_alloc <= INT_MAX) {
344             decoded_packet = av_malloc(decoded_alloc);
345             if (decoded_packet) {
346                 packet_size =
347                     av_base64_decode(decoded_packet, value, decoded_alloc);
348
349                 result = parse_packed_headers
350                     (decoded_packet, decoded_packet + packet_size, codec,
351                     xiph_data);
352             } else {
353                 av_log(codec, AV_LOG_ERROR,
354                        "Out of memory while decoding SDP configuration.\n");
355                 result = AVERROR(ENOMEM);
356             }
357         } else {
358             av_log(codec, AV_LOG_ERROR, "Packet too large\n");
359             result = AVERROR_INVALIDDATA;
360         }
361         av_free(decoded_packet);
362     }
363     return result;
364 }
365
366 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index,
367                                PayloadContext *data, const char *line)
368 {
369     const char *p;
370
371     if (st_index < 0)
372         return 0;
373
374     if (av_strstart(line, "fmtp:", &p)) {
375         return ff_parse_fmtp(s->streams[st_index], data, p,
376                              xiph_parse_fmtp_pair);
377     }
378
379     return 0;
380 }
381
382 RTPDynamicProtocolHandler ff_theora_dynamic_handler = {
383     .enc_name         = "theora",
384     .codec_type       = AVMEDIA_TYPE_VIDEO,
385     .codec_id         = AV_CODEC_ID_THEORA,
386     .parse_sdp_a_line = xiph_parse_sdp_line,
387     .alloc            = xiph_new_context,
388     .free             = xiph_free_context,
389     .parse_packet     = xiph_handle_packet
390 };
391
392 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = {
393     .enc_name         = "vorbis",
394     .codec_type       = AVMEDIA_TYPE_AUDIO,
395     .codec_id         = AV_CODEC_ID_VORBIS,
396     .parse_sdp_a_line = xiph_parse_sdp_line,
397     .alloc            = xiph_new_context,
398     .free             = xiph_free_context,
399     .parse_packet     = xiph_handle_packet
400 };