Browse code

rtp: Depacketization of JPEG (RFC 2435)

Signed-off-by: Martin Storsjö <martin@martin.st>

Samuel Pitoiset authored on 2012/09/08 02:30:23
Showing 7 changed files
... ...
@@ -46,6 +46,7 @@ version <next>:
46 46
   -pass and -passlogfile are now per-output stream
47 47
 - Ut Video encoder
48 48
 - Microsoft Screen 2 decoder
49
+- RTP depacketization of JPEG
49 50
 
50 51
 
51 52
 version 0.8:
... ...
@@ -558,6 +558,7 @@ OBJS-$(CONFIG_OGG_DEMUXER)             += xiph.o flac.o flacdata.o     \
558 558
                                           dirac.o
559 559
 OBJS-$(CONFIG_OGG_MUXER)               += xiph.o flac.o flacdata.o
560 560
 OBJS-$(CONFIG_RTP_MUXER)               += mpeg4audio.o xiph.o
561
+OBJS-$(CONFIG_RTPDEC)                  += mjpeg.o
561 562
 OBJS-$(CONFIG_SPDIF_DEMUXER)           += aacadtsdec.o mpeg4audio.o
562 563
 OBJS-$(CONFIG_SPDIF_MUXER)             += dca.o
563 564
 OBJS-$(CONFIG_WEBM_MUXER)              += mpeg4audio.o mpegaudiodata.o  \
... ...
@@ -269,6 +269,7 @@ OBJS-$(CONFIG_RTPDEC)                    += rdt.o         \
269 269
                                             rtpdec_h263_rfc2190.o \
270 270
                                             rtpdec_h264.o \
271 271
                                             rtpdec_ilbc.o \
272
+                                            rtpdec_jpeg.o \
272 273
                                             rtpdec_latm.o \
273 274
                                             rtpdec_mpeg4.o \
274 275
                                             rtpdec_qcelp.o \
... ...
@@ -69,6 +69,7 @@ void av_register_rtp_dynamic_payload_handlers(void)
69 69
     ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler);
70 70
     ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler);
71 71
     ff_register_dynamic_payload_handler(&ff_ilbc_dynamic_handler);
72
+    ff_register_dynamic_payload_handler(&ff_jpeg_dynamic_handler);
72 73
     ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler);
73 74
     ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler);
74 75
     ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler);
... ...
@@ -46,6 +46,7 @@ extern RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler;
46 46
 extern RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler;
47 47
 extern RTPDynamicProtocolHandler ff_h264_dynamic_handler;
48 48
 extern RTPDynamicProtocolHandler ff_ilbc_dynamic_handler;
49
+extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler;
49 50
 extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler;
50 51
 extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler;
51 52
 extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler;
52 53
new file mode 100644
... ...
@@ -0,0 +1,331 @@
0
+/*
1
+ * RTP JPEG-compressed Video Depacketizer, RFC 2435
2
+ * Copyright (c) 2012 Samuel Pitoiset
3
+ *
4
+ * This file is part of Libav.
5
+ *
6
+ * Libav 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
+ * Libav 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 Libav; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "avformat.h"
22
+#include "rtpdec_formats.h"
23
+#include "libavutil/intreadwrite.h"
24
+#include "libavcodec/mjpeg.h"
25
+
26
+/**
27
+ * RTP/JPEG specific private data.
28
+ */
29
+struct PayloadContext {
30
+    AVIOContext *frame;         ///< current frame buffer
31
+    uint32_t    timestamp;      ///< current frame timestamp
32
+    int         hdr_size;       ///< size of the current frame header
33
+};
34
+
35
+static PayloadContext *jpeg_new_context(void)
36
+{
37
+    return av_mallocz(sizeof(PayloadContext));
38
+}
39
+
40
+static inline void free_frame_if_needed(PayloadContext *jpeg)
41
+{
42
+    if (jpeg->frame) {
43
+        uint8_t *p;
44
+        avio_close_dyn_buf(jpeg->frame, &p);
45
+        av_free(p);
46
+        jpeg->frame = NULL;
47
+    }
48
+}
49
+
50
+static void jpeg_free_context(PayloadContext *jpeg)
51
+{
52
+    free_frame_if_needed(jpeg);
53
+    av_free(jpeg);
54
+}
55
+
56
+static void jpeg_create_huffman_table(PutBitContext *p, int table_class,
57
+                                      int table_id, const uint8_t *bits_table,
58
+                                      const uint8_t *value_table)
59
+{
60
+    int i, n = 0;
61
+
62
+    put_bits(p, 8, 0);
63
+    put_bits(p, 4, table_class);
64
+    put_bits(p, 4, table_id);
65
+
66
+    for (i = 1; i <= 16; i++) {
67
+        n += bits_table[i];
68
+        put_bits(p, 8, bits_table[i]);
69
+    }
70
+
71
+    for (i = 0; i < n; i++) {
72
+        put_bits(p, 8, value_table[i]);
73
+    }
74
+}
75
+
76
+static int jpeg_create_header(uint8_t *buf, int size, uint32_t type, uint32_t w,
77
+                              uint32_t h, const uint8_t *qtable, int nb_qtable)
78
+{
79
+    PutBitContext pbc;
80
+
81
+    init_put_bits(&pbc, buf, size);
82
+
83
+    /* Convert from blocks to pixels. */
84
+    w <<= 3;
85
+    h <<= 3;
86
+
87
+    /* SOI */
88
+    put_marker(&pbc, SOI);
89
+
90
+    /* JFIF header */
91
+    put_marker(&pbc, APP0);
92
+    put_bits(&pbc, 16, 16);
93
+    avpriv_put_string(&pbc, "JFIF", 1);
94
+    put_bits(&pbc, 16, 0x0201);
95
+    put_bits(&pbc, 8, 0);
96
+    put_bits(&pbc, 16, 1);
97
+    put_bits(&pbc, 16, 1);
98
+    put_bits(&pbc, 8, 0);
99
+    put_bits(&pbc, 8, 0);
100
+
101
+    /* DQT */
102
+    put_marker(&pbc, DQT);
103
+    if (nb_qtable == 2) {
104
+        put_bits(&pbc, 16, 2 + 2 * (1 + 64));
105
+    } else {
106
+        put_bits(&pbc, 16, 2 + 1 * (1 + 64));
107
+    }
108
+    put_bits(&pbc, 8, 0);
109
+
110
+    /* Each table is an array of 64 values given in zig-zag
111
+     * order, identical to the format used in a JFIF DQT
112
+     * marker segment. */
113
+    avpriv_copy_bits(&pbc, qtable, 64 * 8);
114
+
115
+    if (nb_qtable == 2) {
116
+        put_bits(&pbc, 8, 1);
117
+        avpriv_copy_bits(&pbc, qtable + 64, 64 * 8);
118
+    }
119
+
120
+    /* DHT */
121
+    put_marker(&pbc, DHT);
122
+
123
+    jpeg_create_huffman_table(&pbc, 0, 0, avpriv_mjpeg_bits_dc_luminance,
124
+                              avpriv_mjpeg_val_dc);
125
+    jpeg_create_huffman_table(&pbc, 0, 1, avpriv_mjpeg_bits_dc_chrominance,
126
+                              avpriv_mjpeg_val_dc);
127
+    jpeg_create_huffman_table(&pbc, 1, 0, avpriv_mjpeg_bits_ac_luminance,
128
+                              avpriv_mjpeg_val_ac_luminance);
129
+    jpeg_create_huffman_table(&pbc, 1, 1, avpriv_mjpeg_bits_ac_chrominance,
130
+                              avpriv_mjpeg_val_ac_chrominance);
131
+
132
+    /* SOF0 */
133
+    put_marker(&pbc, SOF0);
134
+    put_bits(&pbc, 16, 17);
135
+    put_bits(&pbc, 8, 8);
136
+    put_bits(&pbc, 8, h >> 8);
137
+    put_bits(&pbc, 8, h);
138
+    put_bits(&pbc, 8, w >> 8);
139
+    put_bits(&pbc, 8, w);
140
+    put_bits(&pbc, 8, 3);
141
+    put_bits(&pbc, 8, 1);
142
+    put_bits(&pbc, 8, type ? 34 : 33);
143
+    put_bits(&pbc, 8, 0);
144
+    put_bits(&pbc, 8, 2);
145
+    put_bits(&pbc, 8, 17);
146
+    put_bits(&pbc, 8, nb_qtable == 2 ? 1 : 0);
147
+    put_bits(&pbc, 8, 3);
148
+    put_bits(&pbc, 8, 17);
149
+    put_bits(&pbc, 8, nb_qtable == 2 ? 1 : 0);
150
+
151
+    /* SOS */
152
+    put_marker(&pbc, SOS);
153
+    put_bits(&pbc, 16, 12);
154
+    put_bits(&pbc, 8, 3);
155
+    put_bits(&pbc, 8, 1);
156
+    put_bits(&pbc, 8, 0);
157
+    put_bits(&pbc, 8, 2);
158
+    put_bits(&pbc, 8, 17);
159
+    put_bits(&pbc, 8, 3);
160
+    put_bits(&pbc, 8, 17);
161
+    put_bits(&pbc, 8, 0);
162
+    put_bits(&pbc, 8, 63);
163
+    put_bits(&pbc, 8, 0);
164
+
165
+    /* Fill the buffer. */
166
+    flush_put_bits(&pbc);
167
+
168
+    /* Return the length in bytes of the JPEG header. */
169
+    return put_bits_count(&pbc) / 8;
170
+}
171
+
172
+static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg,
173
+                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
174
+                             const uint8_t *buf, int len, int flags)
175
+{
176
+    uint8_t type, q, width, height;
177
+    const uint8_t *qtables = NULL;
178
+    uint16_t qtable_len;
179
+    uint32_t off;
180
+    int ret;
181
+
182
+    if (len < 8) {
183
+        av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
184
+        return AVERROR_INVALIDDATA;
185
+    }
186
+
187
+    /* Parse the main JPEG header. */
188
+    off    = AV_RB24(buf + 1);  /* fragment byte offset */
189
+    type   = AV_RB8(buf + 4);   /* id of jpeg decoder params */
190
+    q      = AV_RB8(buf + 5);   /* quantization factor (or table id) */
191
+    width  = AV_RB8(buf + 6);   /* frame width in 8 pixel blocks */
192
+    height = AV_RB8(buf + 7);   /* frame height in 8 pixel blocks */
193
+    buf += 8;
194
+    len -= 8;
195
+
196
+    /* Parse the restart marker header. */
197
+    if (type > 63) {
198
+        av_log(ctx, AV_LOG_ERROR,
199
+               "Unimplemented RTP/JPEG restart marker header.\n");
200
+        return AVERROR_PATCHWELCOME;
201
+    }
202
+
203
+    /* Parse the quantization table header. */
204
+    if (q > 127 && off == 0) {
205
+        uint8_t precision;
206
+
207
+        if (len < 4) {
208
+            av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
209
+            return AVERROR_INVALIDDATA;
210
+        }
211
+
212
+        /* The first byte is reserved for future use. */
213
+        precision  = AV_RB8(buf + 1);    /* size of coefficients */
214
+        qtable_len = AV_RB16(buf + 2);   /* length in bytes */
215
+        buf += 4;
216
+        len -= 4;
217
+
218
+        if (precision)
219
+            av_log(ctx, AV_LOG_WARNING, "Only 8-bit precision is supported.\n");
220
+
221
+        if (q == 255 && qtable_len == 0) {
222
+            av_log(ctx, AV_LOG_ERROR,
223
+                   "Invalid RTP/JPEG packet. Quantization tables not found.\n");
224
+            return AVERROR_INVALIDDATA;
225
+        }
226
+
227
+        if (qtable_len > 0) {
228
+            if (len < qtable_len) {
229
+                av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
230
+                return AVERROR_INVALIDDATA;
231
+            }
232
+            qtables = buf;
233
+            buf += qtable_len;
234
+            len -= qtable_len;
235
+        }
236
+    }
237
+
238
+    if (off == 0) {
239
+        /* Start of JPEG data packet. */
240
+        uint8_t hdr[1024];
241
+
242
+        /* Skip the current frame in case of the end packet
243
+         * has been lost somewhere. */
244
+        free_frame_if_needed(jpeg);
245
+
246
+        if ((ret = avio_open_dyn_buf(&jpeg->frame)) < 0)
247
+            return ret;
248
+        jpeg->timestamp = *timestamp;
249
+
250
+        if (!qtables) {
251
+            av_log(ctx, AV_LOG_ERROR,
252
+                   "Unimplemented default quantization tables.\n");
253
+            return AVERROR_PATCHWELCOME;
254
+        }
255
+
256
+        /* Generate a frame and scan headers that can be prepended to the
257
+         * RTP/JPEG data payload to produce a JPEG compressed image in
258
+         * interchange format. */
259
+        jpeg->hdr_size = jpeg_create_header(hdr, sizeof(hdr), type, width,
260
+                                            height, qtables,
261
+                                            qtable_len > 64 ? 2 : 1);
262
+
263
+        /* Copy JPEG header to frame buffer. */
264
+        avio_write(jpeg->frame, hdr, jpeg->hdr_size);
265
+    }
266
+
267
+    if (!jpeg->frame) {
268
+        av_log(ctx, AV_LOG_ERROR,
269
+               "Received packet without a start chunk; dropping frame.\n");
270
+        return AVERROR(EAGAIN);
271
+    }
272
+
273
+    if (jpeg->timestamp != *timestamp) {
274
+        /* Skip the current frame if timestamp is incorrect.
275
+         * A start packet has been lost somewhere. */
276
+        free_frame_if_needed(jpeg);
277
+        av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match.\n");
278
+        return AVERROR_INVALIDDATA;
279
+    }
280
+
281
+    if (off != avio_tell(jpeg->frame) - jpeg->hdr_size) {
282
+        av_log(ctx, AV_LOG_ERROR,
283
+               "Missing packets; dropping frame.\n");
284
+        return AVERROR(EAGAIN);
285
+    }
286
+
287
+    /* Copy data to frame buffer. */
288
+    avio_write(jpeg->frame, buf, len);
289
+
290
+    if (flags & RTP_FLAG_MARKER) {
291
+        /* End of JPEG data packet. */
292
+        PutBitContext pbc;
293
+        uint8_t buf[2];
294
+
295
+        /* Put EOI marker. */
296
+        init_put_bits(&pbc, buf, sizeof(buf));
297
+        put_marker(&pbc, EOI);
298
+        flush_put_bits(&pbc);
299
+        avio_write(jpeg->frame, buf, sizeof(buf));
300
+
301
+        /* Prepare the JPEG packet. */
302
+        av_init_packet(pkt);
303
+        pkt->size = avio_close_dyn_buf(jpeg->frame, &pkt->data);
304
+        if (pkt->size < 0) {
305
+            av_log(ctx, AV_LOG_ERROR,
306
+                   "Error occured when getting frame buffer.\n");
307
+            jpeg->frame = NULL;
308
+            return pkt->size;
309
+        }
310
+        pkt->stream_index = st->index;
311
+        pkt->destruct     = av_destruct_packet;
312
+
313
+        /* Re-init the frame buffer. */
314
+        jpeg->frame = NULL;
315
+
316
+        return 0;
317
+    }
318
+
319
+    return AVERROR(EAGAIN);
320
+}
321
+
322
+RTPDynamicProtocolHandler ff_jpeg_dynamic_handler = {
323
+    .enc_name          = "JPEG",
324
+    .codec_type        = AVMEDIA_TYPE_VIDEO,
325
+    .codec_id          = AV_CODEC_ID_MJPEG,
326
+    .alloc             = jpeg_new_context,
327
+    .free              = jpeg_free_context,
328
+    .parse_packet      = jpeg_parse_packet,
329
+    .static_payload_id = 26,
330
+};
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/avutil.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 54
33
-#define LIBAVFORMAT_VERSION_MINOR 14
33
+#define LIBAVFORMAT_VERSION_MINOR 15
34 34
 #define LIBAVFORMAT_VERSION_MICRO  0
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \