Browse code

RTP depacketization of Theora

Patch by Josh Allmann (joshua allmann gmail com)

Originally committed as revision 22636 to svn://svn.ffmpeg.org/ffmpeg/trunk

Josh Allmann authored on 2010/03/23 01:26:29
Showing 6 changed files
... ...
@@ -64,6 +64,7 @@ version <next>:
64 64
 - HE-AAC v1 decoder
65 65
 - Kega Game Video (KGV1) decoder
66 66
 - VorbisComment writing for FLAC, Ogg FLAC and Ogg Speex files
67
+- RTP depacketization of Theora
67 68
 
68 69
 
69 70
 
... ...
@@ -223,6 +223,7 @@ OBJS-$(CONFIG_SDP_DEMUXER)               += rtsp.o        \
223 223
                                             rtpdec_asf.o  \
224 224
                                             rtpdec_h263.o \
225 225
                                             rtpdec_h264.o \
226
+                                            rtpdec_theora.o \
226 227
                                             rtpdec_vorbis.o
227 228
 OBJS-$(CONFIG_SEGAFILM_DEMUXER)          += segafilm.o
228 229
 OBJS-$(CONFIG_SHORTEN_DEMUXER)           += raw.o id3v2.o
... ...
@@ -22,7 +22,7 @@
22 22
 #define AVFORMAT_AVFORMAT_H
23 23
 
24 24
 #define LIBAVFORMAT_VERSION_MAJOR 52
25
-#define LIBAVFORMAT_VERSION_MINOR 56
25
+#define LIBAVFORMAT_VERSION_MINOR 57
26 26
 #define LIBAVFORMAT_VERSION_MICRO  1
27 27
 
28 28
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
... ...
@@ -35,6 +35,7 @@
35 35
 #include "rtpdec_h263.h"
36 36
 #include "rtpdec_h264.h"
37 37
 #include "rtpdec_vorbis.h"
38
+#include "rtpdec_theora.h"
38 39
 
39 40
 //#define DEBUG
40 41
 
... ...
@@ -69,6 +70,7 @@ void av_register_rtp_dynamic_payload_handlers(void)
69 69
     ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler);
70 70
     ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler);
71 71
     ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler);
72
+    ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler);
72 73
 
73 74
     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler);
74 75
     ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler);
75 76
new file mode 100644
... ...
@@ -0,0 +1,387 @@
0
+/*
1
+ * RTP Theora Protocol
2
+ * Copyright (c) 2010 Josh Allmann
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file libavformat/rtpdec_theora.c
23
+ * @brief Theora / RTP Code
24
+ * @author Josh Allmann <joshua.allmann@gmail.com>
25
+ */
26
+
27
+#include "libavutil/avstring.h"
28
+#include "libavutil/base64.h"
29
+#include "libavcodec/bytestream.h"
30
+
31
+#include <assert.h>
32
+
33
+#include "rtpdec.h"
34
+#include "rtpdec_theora.h"
35
+
36
+/**
37
+ * RTP/Theora specific private data.
38
+ */
39
+struct PayloadContext {
40
+    unsigned ident;             ///< 24-bit stream configuration identifier
41
+    uint32_t timestamp;
42
+    ByteIOContext* fragment;    ///< buffer for split payloads
43
+};
44
+
45
+static PayloadContext *theora_new_context(void)
46
+{
47
+    return av_mallocz(sizeof(PayloadContext));
48
+}
49
+
50
+static inline void free_fragment_if_needed(PayloadContext * data)
51
+{
52
+    if (data->fragment) {
53
+        uint8_t* p;
54
+        url_close_dyn_buf(data->fragment, &p);
55
+        av_free(p);
56
+        data->fragment = NULL;
57
+    }
58
+}
59
+
60
+static void theora_free_context(PayloadContext * data)
61
+{
62
+    free_fragment_if_needed(data);
63
+    av_free(data);
64
+}
65
+
66
+static int theora_handle_packet(AVFormatContext * ctx,
67
+                                PayloadContext * data,
68
+                                AVStream * st,
69
+                                AVPacket * pkt,
70
+                                uint32_t * timestamp,
71
+                                const uint8_t * buf, int len, int flags)
72
+{
73
+
74
+    int ident, fragmented, tdt, num_pkts, pkt_len;
75
+
76
+    if (len < 6) {
77
+        av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
78
+        return AVERROR_INVALIDDATA;
79
+    }
80
+
81
+    // read theora rtp headers
82
+    ident       = AV_RB24(buf);
83
+    fragmented  = buf[3] >> 6;
84
+    tdt         = (buf[3] >> 4) & 3;
85
+    num_pkts    = buf[3] & 7;
86
+    pkt_len     = AV_RB16(buf + 4);
87
+
88
+    if (pkt_len > len - 6) {
89
+        av_log(ctx, AV_LOG_ERROR,
90
+               "Invalid packet length %d in %d byte packet\n", pkt_len,
91
+               len);
92
+        return AVERROR_INVALIDDATA;
93
+    }
94
+
95
+    if (ident != data->ident) {
96
+        av_log(ctx, AV_LOG_ERROR,
97
+               "Unimplemented Theora SDP configuration change detected\n");
98
+        return AVERROR_PATCHWELCOME;
99
+    }
100
+
101
+    if (tdt) {
102
+        av_log(ctx, AV_LOG_ERROR,
103
+               "Unimplemented RTP Theora packet settings (%d,%d,%d)\n",
104
+               fragmented, tdt, num_pkts);
105
+        return AVERROR_PATCHWELCOME;
106
+    }
107
+
108
+    buf += 6; // move past header bits
109
+    len -= 6;
110
+
111
+    if (fragmented == 0) {
112
+        // whole frame(s)
113
+        int i, data_len, write_len;
114
+        buf -= 2;
115
+        len += 2;
116
+
117
+        // fast first pass to calculate total length
118
+        for (i = 0, data_len = 0;  (i < num_pkts) && (len >= 2);  i++) {
119
+            int off   = data_len + (i << 1);
120
+            pkt_len   = AV_RB16(buf + off);
121
+            data_len += pkt_len;
122
+            len      -= pkt_len + 2;
123
+        }
124
+
125
+        if (len < 0 || i < num_pkts) {
126
+            av_log(ctx, AV_LOG_ERROR,
127
+                   "Bad packet: %d bytes left at frame %d of %d\n",
128
+                   len, i, num_pkts);
129
+            return AVERROR_INVALIDDATA;
130
+        }
131
+
132
+        if (av_new_packet(pkt, data_len)) {
133
+            av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
134
+            return AVERROR_NOMEM;
135
+        }
136
+        pkt->stream_index = st->index;
137
+
138
+        // concatenate frames
139
+        for (i = 0, write_len = 0; write_len < data_len; i++) {
140
+            pkt_len = AV_RB16(buf);
141
+            buf += 2;
142
+            memcpy(pkt->data + write_len, buf, pkt_len);
143
+            write_len += pkt_len;
144
+            buf += pkt_len;
145
+        }
146
+        assert(write_len == data_len);
147
+
148
+        return 0;
149
+
150
+    } else if (fragmented == 1) {
151
+        // start of theora data fragment
152
+        int res;
153
+
154
+        // end packet has been lost somewhere, so drop buffered data
155
+        free_fragment_if_needed(data);
156
+
157
+        if((res = url_open_dyn_buf(&data->fragment)) < 0)
158
+            return res;
159
+
160
+        put_buffer(data->fragment, buf, pkt_len);
161
+        data->timestamp = *timestamp;
162
+
163
+    } else {
164
+        assert(fragmented < 4);
165
+        if (data->timestamp != *timestamp) {
166
+            // skip if fragmented timestamp is incorrect;
167
+            // a start packet has been lost somewhere
168
+            free_fragment_if_needed(data);
169
+            av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n");
170
+            return AVERROR_INVALIDDATA;
171
+        }
172
+
173
+        // copy data to fragment buffer
174
+        put_buffer(data->fragment, buf, pkt_len);
175
+
176
+        if (fragmented == 3) {
177
+            // end of theora data packet
178
+            uint8_t* theora_data;
179
+            int frame_size = url_close_dyn_buf(data->fragment, &theora_data);
180
+
181
+            if (frame_size < 0) {
182
+                av_log(ctx, AV_LOG_ERROR,
183
+                       "Error occurred when getting fragment buffer.");
184
+                return frame_size;
185
+            }
186
+
187
+            if (av_new_packet(pkt, frame_size)) {
188
+                av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
189
+                return AVERROR_NOMEM;
190
+            }
191
+
192
+            memcpy(pkt->data, theora_data, frame_size);
193
+            pkt->stream_index = st->index;
194
+
195
+            av_free(theora_data);
196
+            data->fragment = NULL;
197
+
198
+            return 0;
199
+        }
200
+    }
201
+
202
+   return AVERROR(EAGAIN);
203
+}
204
+
205
+/**
206
+ * Length encoding described in RFC5215 section 3.1.1.
207
+ */
208
+static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
209
+{
210
+    int n = 0;
211
+    for (; *buf < buf_end; ++*buf) {
212
+        n <<= 7;
213
+        n += **buf & 0x7f;
214
+        if (!(**buf & 0x80)) {
215
+            ++*buf;
216
+            return n;
217
+        }
218
+    }
219
+    return 0;
220
+}
221
+
222
+/**
223
+ * Based off parse_packed_headers in Vorbis RTP
224
+ */
225
+static unsigned int
226
+parse_packed_headers(const uint8_t * packed_headers,
227
+                     const uint8_t * packed_headers_end,
228
+                     AVCodecContext * codec, PayloadContext * theora_data)
229
+{
230
+
231
+    unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
232
+    uint8_t *ptr;
233
+
234
+    if (packed_headers_end - packed_headers < 9) {
235
+        av_log(codec, AV_LOG_ERROR,
236
+               "Invalid %d byte packed header.",
237
+               packed_headers_end - packed_headers);
238
+        return AVERROR_INVALIDDATA;
239
+    }
240
+
241
+    num_packed         = bytestream_get_be32(&packed_headers);
242
+    theora_data->ident = bytestream_get_be24(&packed_headers);
243
+    length             = bytestream_get_be16(&packed_headers);
244
+    num_headers        = get_base128(&packed_headers, packed_headers_end);
245
+    length1            = get_base128(&packed_headers, packed_headers_end);
246
+    length2            = get_base128(&packed_headers, packed_headers_end);
247
+
248
+    if (num_packed != 1 || num_headers > 3) {
249
+        av_log(codec, AV_LOG_ERROR,
250
+               "Unimplemented number of headers: %d packed headers, %d headers\n",
251
+               num_packed, num_headers);
252
+        return AVERROR_PATCHWELCOME;
253
+    }
254
+
255
+    if (packed_headers_end - packed_headers != length ||
256
+        length1 > length || length2 > length - length1) {
257
+        av_log(codec, AV_LOG_ERROR,
258
+               "Bad packed header lengths (%d,%d,%d,%d)\n", length1,
259
+               length2, packed_headers_end - packed_headers, length);
260
+        return AVERROR_INVALIDDATA;
261
+    }
262
+
263
+    /* allocate extra space:
264
+     * -- length/255 +2 for xiphlacing
265
+     * -- one for the '2' marker
266
+     * -- FF_INPUT_BUFFER_PADDING_SIZE required */
267
+    extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
268
+
269
+    ptr = codec->extradata = av_malloc(extradata_alloc);
270
+    if (!ptr) {
271
+        av_log(codec, AV_LOG_ERROR, "Out of memory\n");
272
+        return AVERROR_NOMEM;
273
+    }
274
+    *ptr++ = 2;
275
+    ptr += av_xiphlacing(ptr, length1);
276
+    ptr += av_xiphlacing(ptr, length2);
277
+    memcpy(ptr, packed_headers, length);
278
+    ptr += length;
279
+    codec->extradata_size = ptr - codec->extradata;
280
+    // clear out remaining parts of the buffer
281
+    memset(ptr, 0, extradata_alloc - codec->extradata_size);
282
+
283
+    return 0;
284
+}
285
+
286
+static int theora_parse_fmtp_pair(AVCodecContext * codec,
287
+                                  PayloadContext *theora_data,
288
+                                  char *attr, char *value)
289
+{
290
+    int result = 0;
291
+
292
+    if (!strcmp(attr, "sampling")) {
293
+        return AVERROR_PATCHWELCOME;
294
+    } else if (!strcmp(attr, "width")) {
295
+        /* This is an integer between 1 and 1048561
296
+         * and MUST be in multiples of 16. */
297
+        codec->width = atoi(value);
298
+        return 0;
299
+    } else if (!strcmp(attr, "height")) {
300
+        /* This is an integer between 1 and 1048561
301
+         * and MUST be in multiples of 16. */
302
+        codec->height = atoi(value);
303
+        return 0;
304
+    } else if (!strcmp(attr, "delivery-method")) {
305
+        /* Possible values are: inline, in_band, out_band/specific_name. */
306
+        return AVERROR_PATCHWELCOME;
307
+    } else if (!strcmp(attr, "configuration-uri")) {
308
+        /* NOTE: configuration-uri is supported only under 2 conditions:
309
+         *--after the delivery-method tag
310
+         * --with a delivery-method value of out_band */
311
+        return AVERROR_PATCHWELCOME;
312
+    } else if (!strcmp(attr, "configuration")) {
313
+        /* NOTE: configuration is supported only AFTER the delivery-method tag
314
+         * The configuration value is a base64 encoded packed header */
315
+        uint8_t *decoded_packet = NULL;
316
+        int packet_size;
317
+        size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
318
+
319
+        if (decoded_alloc <= INT_MAX) {
320
+            decoded_packet = av_malloc(decoded_alloc);
321
+            if (decoded_packet) {
322
+                packet_size =
323
+                    av_base64_decode(decoded_packet, value, decoded_alloc);
324
+
325
+                result = parse_packed_headers
326
+                    (decoded_packet, decoded_packet + packet_size, codec,
327
+                    theora_data);
328
+            } else {
329
+                av_log(codec, AV_LOG_ERROR,
330
+                       "Out of memory while decoding SDP configuration.\n");
331
+                result = AVERROR_NOMEM;
332
+            }
333
+        } else {
334
+            av_log(codec, AV_LOG_ERROR, "Packet too large\n");
335
+            result = AVERROR_INVALIDDATA;
336
+        }
337
+        av_free(decoded_packet);
338
+    }
339
+    return result;
340
+}
341
+
342
+static int theora_parse_sdp_line(AVFormatContext *s, int st_index,
343
+                                 PayloadContext *data, const char *line)
344
+{
345
+    const char *p;
346
+    char *value;
347
+    char attr[25];
348
+    int value_size = strlen(line), attr_size = sizeof(attr), res = 0;
349
+    AVCodecContext* codec = s->streams[st_index]->codec;
350
+
351
+    assert(codec->id == CODEC_ID_THEORA);
352
+    assert(data);
353
+
354
+    if (!(value = av_malloc(value_size))) {
355
+        av_log(codec, AV_LOG_ERROR, "Out of memory\n");
356
+        return AVERROR_NOMEM;
357
+    }
358
+
359
+    if (av_strstart(line, "fmtp:", &p)) {
360
+        // remove protocol identifier
361
+        while (*p && *p == ' ') p++; // strip spaces
362
+        while (*p && *p != ' ') p++; // eat protocol identifier
363
+        while (*p && *p == ' ') p++; // strip trailing spaces
364
+
365
+        while (ff_rtsp_next_attr_and_value(&p,
366
+                                           attr, attr_size,
367
+                                           value, value_size)) {
368
+            res = theora_parse_fmtp_pair(codec, data, attr, value);
369
+            if (res < 0 && res != AVERROR_PATCHWELCOME)
370
+                return res;
371
+        }
372
+    }
373
+
374
+    av_free(value);
375
+    return 0;
376
+}
377
+
378
+RTPDynamicProtocolHandler ff_theora_dynamic_handler = {
379
+    .enc_name         = "theora",
380
+    .codec_type       = CODEC_TYPE_VIDEO,
381
+    .codec_id         = CODEC_ID_THEORA,
382
+    .parse_sdp_a_line = theora_parse_sdp_line,
383
+    .open             = theora_new_context,
384
+    .close            = theora_free_context,
385
+    .parse_packet     = theora_handle_packet
386
+};
0 387
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+/*
1
+ * RTP Theora Protocol.
2
+ * Based off RFC 5215 (Vorbis RTP) and the Theora RTP draft.
3
+ * Copyright (c) 2010 Josh Allmann
4
+ *
5
+ * This file is part of FFmpeg.
6
+ *
7
+ * FFmpeg is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU Lesser General Public
9
+ * License as published by the Free Software Foundation; either
10
+ * version 2.1 of the License, or (at your option) any later version.
11
+ *
12
+ * FFmpeg is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * Lesser General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Lesser General Public
18
+ * License along with FFmpeg; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
+ */
21
+
22
+#ifndef AVFORMAT_RTPDEC_THEORA_H
23
+#define AVFORMAT_RTPDEC_THEORA_H
24
+
25
+#include "libavcodec/avcodec.h"
26
+#include "rtpdec.h"
27
+
28
+/**
29
+ * Theora RTP callbacks.
30
+ */
31
+extern RTPDynamicProtocolHandler ff_theora_dynamic_handler;
32
+
33
+#endif /* AVFORMAT_RTPDEC_THEORA_H */