Browse code

R3D REDCODE demuxer

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

Baptiste Coudurier authored on 2009/01/20 16:42:14
Showing 6 changed files
... ...
@@ -144,6 +144,7 @@ version <next>
144 144
 - RV30 and RV40 decoder
145 145
 - QCELP / PureVoice decoder
146 146
 - hybrid WavPack support
147
+- R3D REDCODE demuxer
147 148
 
148 149
 version 0.4.9-pre1:
149 150
 
... ...
@@ -272,6 +272,7 @@ Muxers/Demuxers:
272 272
   oggparseogm.c                         Mans Rullgard
273 273
   psxstr.c                              Mike Melanson
274 274
   pva.c                                 Ivo van Poorten
275
+  r3d.c                                 Baptiste Coudurier
275 276
   raw.c                                 Michael Niedermayer
276 277
   rl2.c                                 Sascha Sommer
277 278
   rm.c                                  Roberto Togni
... ...
@@ -123,6 +123,8 @@ library:
123 123
 @item raw MPEG-4 video          @tab X @tab X
124 124
 @item raw PCM 8/16/32 bits, 32/64-bit floating point, mu-law/A-law @tab X  @tab  X
125 125
 @item raw Shorten audio         @tab    @tab  X
126
+@item R3D REDCODE               @tab   @tab X
127
+    @tab File format used by RED Digital cameras, contains JPEG 2000 frames and PCM audio.
126 128
 @item RealMedia                 @tab X @tab X
127 129
 @item RL2                       @tab   @tab X
128 130
     @tab Audio and video format used in some games by Entertainment Software Partners.
... ...
@@ -160,6 +160,7 @@ void av_register_all(void)
160 160
     REGISTER_MUXDEMUX (PCM_U8,    pcm_u8);
161 161
     REGISTER_MUXER    (PSP, psp);
162 162
     REGISTER_DEMUXER  (PVA, pva);
163
+    REGISTER_DEMUXER  (R3D, r3d);
163 164
     REGISTER_MUXDEMUX (RAWVIDEO, rawvideo);
164 165
     REGISTER_DEMUXER  (REDIR, redir);
165 166
     REGISTER_DEMUXER  (RL2, rl2);
... ...
@@ -22,8 +22,8 @@
22 22
 #define AVFORMAT_AVFORMAT_H
23 23
 
24 24
 #define LIBAVFORMAT_VERSION_MAJOR 52
25
-#define LIBAVFORMAT_VERSION_MINOR 24
26
-#define LIBAVFORMAT_VERSION_MICRO  1
25
+#define LIBAVFORMAT_VERSION_MINOR 25
26
+#define LIBAVFORMAT_VERSION_MICRO  0
27 27
 
28 28
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
29 29
                                                LIBAVFORMAT_VERSION_MINOR, \
30 30
new file mode 100644
... ...
@@ -0,0 +1,384 @@
0
+/*
1
+ * R3D REDCODE demuxer
2
+ * Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
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
+//#define DEBUG
22
+
23
+#include "libavutil/intreadwrite.h"
24
+#include "avformat.h"
25
+
26
+typedef struct {
27
+    unsigned video_offsets_count;
28
+    unsigned *video_offsets;
29
+    unsigned rdvo_offset;
30
+} R3DContext;
31
+
32
+typedef struct {
33
+    unsigned size;
34
+    uint32_t tag;
35
+    uint64_t offset;
36
+} Atom;
37
+
38
+static int read_atom(AVFormatContext *s, Atom *atom)
39
+{
40
+    atom->offset = url_ftell(s->pb);
41
+    atom->size = get_be32(s->pb);
42
+    if (atom->size < 8)
43
+        return -1;
44
+    atom->tag = get_le32(s->pb);
45
+    dprintf(s, "atom %d %.4s offset %#llx\n",
46
+            atom->size, (char*)&atom->tag, atom->offset);
47
+    return atom->size;
48
+}
49
+
50
+static int r3d_read_red1(AVFormatContext *s)
51
+{
52
+    AVStream *st = av_new_stream(s, 0);
53
+    int tmp, tmp2;
54
+
55
+    if (!st)
56
+        return -1;
57
+    st->codec->codec_type = CODEC_TYPE_VIDEO;
58
+    st->codec->codec_id = CODEC_ID_JPEG2000;
59
+
60
+    tmp  = get_byte(s->pb); // major version
61
+    tmp2 = get_byte(s->pb); // minor version
62
+    dprintf(s, "version %d.%d\n", tmp, tmp2);
63
+
64
+    tmp = get_be16(s->pb); // unknown
65
+    dprintf(s, "unknown1 %d\n", tmp);
66
+
67
+    tmp = get_be32(s->pb);
68
+    av_set_pts_info(st, 32, 1, tmp);
69
+
70
+    tmp = get_be32(s->pb); // filenum
71
+    dprintf(s, "filenum %d\n", tmp);
72
+
73
+    url_fskip(s->pb, 32); // unknown
74
+
75
+    st->codec->width  = get_be32(s->pb);
76
+    st->codec->height = get_be32(s->pb);
77
+
78
+    tmp = get_be16(s->pb); // unknown
79
+    dprintf(s, "unknown2 %d\n", tmp);
80
+
81
+    st->codec->time_base.den = get_be16(s->pb);
82
+    st->codec->time_base.num = get_be16(s->pb);
83
+
84
+    tmp = get_byte(s->pb); // audio channels
85
+    dprintf(s, "audio channels %d\n", tmp);
86
+    if (tmp > 0) {
87
+        AVStream *ast = av_new_stream(s, 1);
88
+        ast->codec->codec_type = CODEC_TYPE_AUDIO;
89
+        ast->codec->codec_id = CODEC_ID_PCM_S32BE;
90
+        ast->codec->channels = tmp;
91
+        av_set_pts_info(ast, 32, 1, st->time_base.den);
92
+    }
93
+
94
+    st->filename = av_mallocz(258);
95
+    if (!st->filename)
96
+        return AVERROR(ENOMEM);
97
+    get_buffer(s->pb, st->filename, 257);
98
+
99
+    dprintf(s, "filename %s\n", st->filename);
100
+    dprintf(s, "resolution %dx%d\n", st->codec->width, st->codec->height);
101
+    dprintf(s, "timescale %d\n", st->time_base.den);
102
+    dprintf(s, "frame rate %d/%d\n",
103
+            st->codec->time_base.num, st->codec->time_base.den);
104
+
105
+    return 0;
106
+}
107
+
108
+static int r3d_read_rdvo(AVFormatContext *s, Atom *atom)
109
+{
110
+    R3DContext *r3d = s->priv_data;
111
+    AVStream *st = s->streams[0];
112
+    int i;
113
+
114
+    r3d->video_offsets_count = (atom->size - 8) / 4;
115
+    r3d->video_offsets = av_malloc(atom->size);
116
+    if (!r3d->video_offsets)
117
+        return AVERROR(ENOMEM);
118
+
119
+    for (i = 0; i < r3d->video_offsets_count; i++) {
120
+        r3d->video_offsets[i] = get_be32(s->pb);
121
+        if (!r3d->video_offsets[i]) {
122
+            r3d->video_offsets_count = i;
123
+            break;
124
+        }
125
+        dprintf(s, "video offset %d: %#x\n", i, r3d->video_offsets[i]);
126
+    }
127
+
128
+    if (st->codec->time_base.den)
129
+        st->duration = (uint64_t)r3d->video_offsets_count*
130
+            st->time_base.den*st->codec->time_base.num/st->codec->time_base.den;
131
+    dprintf(s, "duration %lld\n", st->duration);
132
+
133
+    return 0;
134
+}
135
+
136
+static void r3d_read_reos(AVFormatContext *s)
137
+{
138
+    R3DContext *r3d = s->priv_data;
139
+    int tmp;
140
+
141
+    r3d->rdvo_offset = get_be32(s->pb);
142
+    get_be32(s->pb); // rdvs offset
143
+    get_be32(s->pb); // rdao offset
144
+    get_be32(s->pb); // rdas offset
145
+
146
+    tmp = get_be32(s->pb);
147
+    dprintf(s, "num video chunks %d\n", tmp);
148
+
149
+    tmp = get_be32(s->pb);
150
+    dprintf(s, "num audio chunks %d\n", tmp);
151
+
152
+    url_fskip(s->pb, 6*4);
153
+}
154
+
155
+static int r3d_read_header(AVFormatContext *s, AVFormatParameters *ap)
156
+{
157
+    R3DContext *r3d = s->priv_data;
158
+    Atom atom;
159
+    int ret;
160
+
161
+    if (read_atom(s, &atom) < 0) {
162
+        av_log(s, AV_LOG_ERROR, "error reading atom\n");
163
+        return -1;
164
+    }
165
+    if (atom.tag == MKTAG('R','E','D','1')) {
166
+        if ((ret = r3d_read_red1(s)) < 0) {
167
+            av_log(s, AV_LOG_ERROR, "error parsing 'red1' atom\n");
168
+            return ret;
169
+        }
170
+    } else {
171
+        av_log(s, AV_LOG_ERROR, "could not find 'red1' atom\n");
172
+        return -1;
173
+    }
174
+
175
+    s->data_offset = url_ftell(s->pb);
176
+    dprintf(s, "data offset %#llx\n", s->data_offset);
177
+    if (url_is_streamed(s->pb))
178
+        return 0;
179
+    // find REOB/REOF/REOS to load index
180
+    url_fseek(s->pb, url_fsize(s->pb)-48-8, SEEK_SET);
181
+    if (read_atom(s, &atom) < 0)
182
+        av_log(s, AV_LOG_ERROR, "error reading end atom\n");
183
+
184
+    if (atom.tag != MKTAG('R','E','O','B') &&
185
+        atom.tag != MKTAG('R','E','O','F') &&
186
+        atom.tag != MKTAG('R','E','O','S'))
187
+        goto out;
188
+
189
+    r3d_read_reos(s);
190
+
191
+    if (r3d->rdvo_offset) {
192
+        url_fseek(s->pb, r3d->rdvo_offset, SEEK_SET);
193
+        if (read_atom(s, &atom) < 0)
194
+            av_log(s, AV_LOG_ERROR, "error reading 'rdvo' atom\n");
195
+        if (atom.tag == MKTAG('R','D','V','O')) {
196
+            if (r3d_read_rdvo(s, &atom) < 0)
197
+                av_log(s, AV_LOG_ERROR, "error parsing 'rdvo' atom\n");
198
+        }
199
+    }
200
+
201
+ out:
202
+    url_fseek(s->pb, s->data_offset, SEEK_SET);
203
+    return 0;
204
+}
205
+
206
+static int r3d_read_redv(AVFormatContext *s, AVPacket *pkt, Atom *atom)
207
+{
208
+    AVStream *st = s->streams[0];
209
+    int tmp, tmp2;
210
+    uint64_t pos = url_ftell(s->pb);
211
+    unsigned dts;
212
+
213
+    dts = get_be32(s->pb);
214
+
215
+    tmp = get_be32(s->pb);
216
+    dprintf(s, "frame num %d\n", tmp);
217
+
218
+    tmp  = get_byte(s->pb); // major version
219
+    tmp2 = get_byte(s->pb); // minor version
220
+    dprintf(s, "version %d.%d\n", tmp, tmp2);
221
+
222
+    tmp = get_be16(s->pb); // unknown
223
+    dprintf(s, "unknown %d\n", tmp);
224
+
225
+    if (tmp > 4) {
226
+        tmp = get_be16(s->pb); // unknown
227
+        dprintf(s, "unknown %d\n", tmp);
228
+
229
+        tmp = get_be16(s->pb); // unknown
230
+        dprintf(s, "unknown %d\n", tmp);
231
+
232
+        tmp = get_be32(s->pb);
233
+        dprintf(s, "width %d\n", tmp);
234
+        tmp = get_be32(s->pb);
235
+        dprintf(s, "height %d\n", tmp);
236
+
237
+        tmp = get_be32(s->pb);
238
+        dprintf(s, "metadata len %d\n", tmp);
239
+    }
240
+    tmp = atom->size - 8 - (url_ftell(s->pb) - pos);
241
+    if (tmp < 0)
242
+        return -1;
243
+
244
+    if (av_get_packet(s->pb, pkt, tmp) != tmp) {
245
+        av_log(s, AV_LOG_ERROR, "error reading video packet\n");
246
+        return -1;
247
+    }
248
+
249
+    pkt->stream_index = 0;
250
+    pkt->dts = dts;
251
+    if (st->codec->time_base.den)
252
+        pkt->duration = (uint64_t)st->time_base.den*
253
+            st->codec->time_base.num/st->codec->time_base.den;
254
+    dprintf(s, "pkt dts %lld duration %d\n", pkt->dts, pkt->duration);
255
+
256
+    return 0;
257
+}
258
+
259
+static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom)
260
+{
261
+    AVStream *st = s->streams[1];
262
+    int tmp, tmp2, samples, size;
263
+    uint64_t pos = url_ftell(s->pb);
264
+    unsigned dts;
265
+
266
+    dts = get_be32(s->pb);
267
+
268
+    st->codec->sample_rate = get_be32(s->pb);
269
+
270
+    samples = get_be32(s->pb);
271
+
272
+    tmp = get_be32(s->pb);
273
+    dprintf(s, "packet num %d\n", tmp);
274
+
275
+    tmp = get_be16(s->pb); // unkown
276
+    dprintf(s, "unknown %d\n", tmp);
277
+
278
+    tmp  = get_byte(s->pb); // major version
279
+    tmp2 = get_byte(s->pb); // minor version
280
+    dprintf(s, "version %d.%d\n", tmp, tmp2);
281
+
282
+    tmp = get_be32(s->pb); // unknown
283
+    dprintf(s, "unknown %d\n", tmp);
284
+
285
+    size = atom->size - 8 - (url_ftell(s->pb) - pos);
286
+    if (size < 0)
287
+        return -1;
288
+    if (av_get_packet(s->pb, pkt, size) != size) {
289
+        av_log(s, AV_LOG_ERROR, "error reading video packet\n");
290
+        return -1;
291
+    }
292
+
293
+    pkt->stream_index = 1;
294
+    pkt->dts = dts;
295
+    pkt->duration = av_rescale(samples, st->time_base.den, st->codec->sample_rate);
296
+    dprintf(s, "pkt dts %lld duration %d samples %d sample rate %d\n",
297
+            pkt->dts, pkt->duration, samples, st->codec->sample_rate);
298
+
299
+    return 0;
300
+}
301
+
302
+static int r3d_read_packet(AVFormatContext *s, AVPacket *pkt)
303
+{
304
+    Atom atom;
305
+    int err = 0;
306
+
307
+    while (!err) {
308
+        if (read_atom(s, &atom) < 0) {
309
+            err = -1;
310
+            break;
311
+        }
312
+        switch (atom.tag) {
313
+        case MKTAG('R','E','D','V'):
314
+            if (s->streams[0]->discard == AVDISCARD_ALL)
315
+                goto skip;
316
+            if (!(err = r3d_read_redv(s, pkt, &atom)))
317
+                return 0;
318
+            break;
319
+        case MKTAG('R','E','D','A'):
320
+            if (s->nb_streams < 2)
321
+                return -1;
322
+            if (s->streams[1]->discard == AVDISCARD_ALL)
323
+                goto skip;
324
+            if (!(err = r3d_read_reda(s, pkt, &atom)))
325
+                return 0;
326
+            break;
327
+        default:
328
+        skip:
329
+            url_fskip(s->pb, atom.size-8);
330
+        }
331
+    }
332
+    return err;
333
+}
334
+
335
+static int r3d_probe(AVProbeData *p)
336
+{
337
+    if (AV_RL32(p->buf + 4) == MKTAG('R','E','D','1'))
338
+        return AVPROBE_SCORE_MAX;
339
+    return 0;
340
+}
341
+
342
+static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
343
+{
344
+    AVStream *st = s->streams[0]; // video stream
345
+    R3DContext *r3d = s->priv_data;
346
+    int frame_num;
347
+
348
+    if (!st->codec->time_base.num || !st->time_base.den)
349
+        return -1;
350
+
351
+    frame_num = sample_time*st->codec->time_base.den/
352
+        ((int64_t)st->codec->time_base.num*st->time_base.den);
353
+    dprintf(s, "seek frame num %d timestamp %lld\n", frame_num, sample_time);
354
+
355
+    if (frame_num < r3d->video_offsets_count) {
356
+        url_fseek(s->pb, r3d->video_offsets_count, SEEK_SET);
357
+    } else {
358
+        av_log(s, AV_LOG_ERROR, "could not seek to frame %d\n", frame_num);
359
+        return -1;
360
+    }
361
+
362
+    return 0;
363
+}
364
+
365
+static int r3d_close(AVFormatContext *s)
366
+{
367
+    R3DContext *r3d = s->priv_data;
368
+
369
+    av_freep(&r3d->video_offsets);
370
+
371
+    return 0;
372
+}
373
+
374
+AVInputFormat r3d_demuxer = {
375
+    "r3d",
376
+    NULL_IF_CONFIG_SMALL("REDCODE R3D format"),
377
+    sizeof(R3DContext),
378
+    r3d_probe,
379
+    r3d_read_header,
380
+    r3d_read_packet,
381
+    r3d_close,
382
+    r3d_seek,
383
+};