Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
r3d.c
Go to the documentation of this file.
1
/*
2
* R3D REDCODE demuxer
3
* Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
4
*
5
* This file is part of Libav.
6
*
7
* Libav 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
* Libav 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 Libav; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
//#define DEBUG
23
24
#include "
libavutil/intreadwrite.h
"
25
#include "
libavutil/dict.h
"
26
#include "
libavutil/mathematics.h
"
27
#include "
avformat.h
"
28
#include "
internal.h
"
29
30
typedef
struct
{
31
unsigned
video_offsets_count
;
32
unsigned
*
video_offsets
;
33
unsigned
rdvo_offset
;
34
}
R3DContext
;
35
36
typedef
struct
{
37
unsigned
size
;
38
uint32_t
tag
;
39
uint64_t
offset
;
40
}
Atom
;
41
42
static
int
read_atom
(
AVFormatContext
*s,
Atom
*atom)
43
{
44
atom->
offset
=
avio_tell
(s->
pb
);
45
atom->
size
=
avio_rb32
(s->
pb
);
46
if
(atom->
size
< 8)
47
return
-1;
48
atom->
tag
=
avio_rl32
(s->
pb
);
49
av_dlog
(s,
"atom %u %.4s offset %#"
PRIx64
"\n"
,
50
atom->
size
, (
char
*)&atom->
tag
, atom->
offset
);
51
return
atom->
size
;
52
}
53
54
static
int
r3d_read_red1
(
AVFormatContext
*s)
55
{
56
AVStream
*st =
avformat_new_stream
(s,
NULL
);
57
char
filename[258];
58
int
tmp;
59
int
av_unused
tmp2;
60
AVRational
framerate;
61
62
if
(!st)
63
return
AVERROR
(ENOMEM);
64
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
65
st->
codec
->
codec_id
=
AV_CODEC_ID_JPEG2000
;
66
67
tmp =
avio_r8
(s->
pb
);
// major version
68
tmp2 =
avio_r8
(s->
pb
);
// minor version
69
av_dlog
(s,
"version %d.%d\n"
, tmp, tmp2);
70
71
tmp =
avio_rb16
(s->
pb
);
// unknown
72
av_dlog
(s,
"unknown1 %d\n"
, tmp);
73
74
tmp =
avio_rb32
(s->
pb
);
75
avpriv_set_pts_info
(st, 32, 1, tmp);
76
77
tmp =
avio_rb32
(s->
pb
);
// filenum
78
av_dlog
(s,
"filenum %d\n"
, tmp);
79
80
avio_skip
(s->
pb
, 32);
// unknown
81
82
st->
codec
->
width
=
avio_rb32
(s->
pb
);
83
st->
codec
->
height
=
avio_rb32
(s->
pb
);
84
85
tmp =
avio_rb16
(s->
pb
);
// unknown
86
av_dlog
(s,
"unknown2 %d\n"
, tmp);
87
88
framerate.
num
=
avio_rb16
(s->
pb
);
89
framerate.
den
=
avio_rb16
(s->
pb
);
90
if
(framerate.
num
> 0 && framerate.
den
> 0) {
91
#if FF_API_R_FRAME_RATE
92
st->r_frame_rate =
93
#endif
94
st->
avg_frame_rate
= framerate;
95
}
96
97
tmp =
avio_r8
(s->
pb
);
// audio channels
98
av_dlog
(s,
"audio channels %d\n"
, tmp);
99
if
(tmp > 0) {
100
AVStream
*ast =
avformat_new_stream
(s,
NULL
);
101
if
(!ast)
102
return
AVERROR
(ENOMEM);
103
ast->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
104
ast->
codec
->
codec_id
=
AV_CODEC_ID_PCM_S32BE
;
105
ast->
codec
->
channels
= tmp;
106
avpriv_set_pts_info
(ast, 32, 1, st->
time_base
.
den
);
107
}
108
109
avio_read
(s->
pb
, filename, 257);
110
filename[
sizeof
(filename)-1] = 0;
111
av_dict_set
(&st->
metadata
,
"filename"
, filename, 0);
112
113
av_dlog
(s,
"filename %s\n"
, filename);
114
av_dlog
(s,
"resolution %dx%d\n"
, st->
codec
->
width
, st->
codec
->
height
);
115
av_dlog
(s,
"timescale %d\n"
, st->
time_base
.
den
);
116
av_dlog
(s,
"frame rate %d/%d\n"
,
117
framerate.
num
, framerate.
den
);
118
119
return
0;
120
}
121
122
static
int
r3d_read_rdvo
(
AVFormatContext
*s,
Atom
*atom)
123
{
124
R3DContext
*r3d = s->
priv_data
;
125
AVStream
*st = s->
streams
[0];
126
int
i;
127
128
r3d->
video_offsets_count
= (atom->
size
- 8) / 4;
129
r3d->
video_offsets
=
av_malloc
(atom->
size
);
130
if
(!r3d->
video_offsets
)
131
return
AVERROR
(ENOMEM);
132
133
for
(i = 0; i < r3d->
video_offsets_count
; i++) {
134
r3d->
video_offsets
[i] =
avio_rb32
(s->
pb
);
135
if
(!r3d->
video_offsets
[i]) {
136
r3d->
video_offsets_count
= i;
137
break
;
138
}
139
av_dlog
(s,
"video offset %d: %#x\n"
, i, r3d->
video_offsets
[i]);
140
}
141
142
if
(st->
avg_frame_rate
.
num
)
143
st->
duration
=
av_rescale_q
(r3d->
video_offsets_count
,
144
(
AVRational
){st->
avg_frame_rate
.
den
,
145
st->
avg_frame_rate
.
num
},
146
st->time_base);
147
av_dlog
(s,
"duration %"
PRId64
"\n"
, st->duration);
148
149
return
0;
150
}
151
152
static
void
r3d_read_reos
(
AVFormatContext
*s)
153
{
154
R3DContext
*r3d = s->
priv_data
;
155
int
av_unused
tmp;
156
157
r3d->
rdvo_offset
=
avio_rb32
(s->
pb
);
158
avio_rb32
(s->
pb
);
// rdvs offset
159
avio_rb32
(s->
pb
);
// rdao offset
160
avio_rb32
(s->
pb
);
// rdas offset
161
162
tmp =
avio_rb32
(s->
pb
);
163
av_dlog
(s,
"num video chunks %d\n"
, tmp);
164
165
tmp =
avio_rb32
(s->
pb
);
166
av_dlog
(s,
"num audio chunks %d\n"
, tmp);
167
168
avio_skip
(s->
pb
, 6*4);
169
}
170
171
static
int
r3d_read_header
(
AVFormatContext
*s)
172
{
173
R3DContext
*r3d = s->
priv_data
;
174
Atom
atom;
175
int
ret;
176
177
if
(
read_atom
(s, &atom) < 0) {
178
av_log
(s,
AV_LOG_ERROR
,
"error reading atom\n"
);
179
return
-1;
180
}
181
if
(atom.
tag
==
MKTAG
(
'R'
,
'E'
,
'D'
,
'1'
)) {
182
if
((ret =
r3d_read_red1
(s)) < 0) {
183
av_log
(s,
AV_LOG_ERROR
,
"error parsing 'red1' atom\n"
);
184
return
ret;
185
}
186
}
else
{
187
av_log
(s,
AV_LOG_ERROR
,
"could not find 'red1' atom\n"
);
188
return
-1;
189
}
190
191
s->
data_offset
=
avio_tell
(s->
pb
);
192
av_dlog
(s,
"data offset %#"
PRIx64
"\n"
, s->
data_offset
);
193
if
(!s->
pb
->
seekable
)
194
return
0;
195
// find REOB/REOF/REOS to load index
196
avio_seek
(s->
pb
,
avio_size
(s->
pb
)-48-8, SEEK_SET);
197
if
(
read_atom
(s, &atom) < 0)
198
av_log
(s,
AV_LOG_ERROR
,
"error reading end atom\n"
);
199
200
if
(atom.
tag
!=
MKTAG
(
'R'
,
'E'
,
'O'
,
'B'
) &&
201
atom.
tag
!=
MKTAG
(
'R'
,
'E'
,
'O'
,
'F'
) &&
202
atom.
tag
!=
MKTAG
(
'R'
,
'E'
,
'O'
,
'S'
))
203
goto
out;
204
205
r3d_read_reos
(s);
206
207
if
(r3d->
rdvo_offset
) {
208
avio_seek
(s->
pb
, r3d->
rdvo_offset
, SEEK_SET);
209
if
(
read_atom
(s, &atom) < 0)
210
av_log
(s,
AV_LOG_ERROR
,
"error reading 'rdvo' atom\n"
);
211
if
(atom.
tag
==
MKTAG
(
'R'
,
'D'
,
'V'
,
'O'
)) {
212
if
(
r3d_read_rdvo
(s, &atom) < 0)
213
av_log
(s,
AV_LOG_ERROR
,
"error parsing 'rdvo' atom\n"
);
214
}
215
}
216
217
out:
218
avio_seek
(s->
pb
, s->
data_offset
, SEEK_SET);
219
return
0;
220
}
221
222
static
int
r3d_read_redv
(
AVFormatContext
*s,
AVPacket
*pkt,
Atom
*atom)
223
{
224
AVStream
*st = s->
streams
[0];
225
int
tmp;
226
int
av_unused
tmp2;
227
uint64_t pos =
avio_tell
(s->
pb
);
228
unsigned
dts;
229
int
ret;
230
231
dts =
avio_rb32
(s->
pb
);
232
233
tmp =
avio_rb32
(s->
pb
);
234
av_dlog
(s,
"frame num %d\n"
, tmp);
235
236
tmp =
avio_r8
(s->
pb
);
// major version
237
tmp2 =
avio_r8
(s->
pb
);
// minor version
238
av_dlog
(s,
"version %d.%d\n"
, tmp, tmp2);
239
240
tmp =
avio_rb16
(s->
pb
);
// unknown
241
av_dlog
(s,
"unknown %d\n"
, tmp);
242
243
if
(tmp > 4) {
244
tmp =
avio_rb16
(s->
pb
);
// unknown
245
av_dlog
(s,
"unknown %d\n"
, tmp);
246
247
tmp =
avio_rb16
(s->
pb
);
// unknown
248
av_dlog
(s,
"unknown %d\n"
, tmp);
249
250
tmp =
avio_rb32
(s->
pb
);
251
av_dlog
(s,
"width %d\n"
, tmp);
252
tmp =
avio_rb32
(s->
pb
);
253
av_dlog
(s,
"height %d\n"
, tmp);
254
255
tmp =
avio_rb32
(s->
pb
);
256
av_dlog
(s,
"metadata len %d\n"
, tmp);
257
}
258
tmp = atom->
size
- 8 - (
avio_tell
(s->
pb
) - pos);
259
if
(tmp < 0)
260
return
-1;
261
ret =
av_get_packet
(s->
pb
, pkt, tmp);
262
if
(ret < 0) {
263
av_log
(s,
AV_LOG_ERROR
,
"error reading video packet\n"
);
264
return
-1;
265
}
266
267
pkt->
stream_index
= 0;
268
pkt->
dts
= dts;
269
if
(st->
avg_frame_rate
.
num
)
270
pkt->
duration
= (uint64_t)st->
time_base
.
den
*
271
st->
avg_frame_rate
.
den
/st->
avg_frame_rate
.
num
;
272
av_dlog
(s,
"pkt dts %"
PRId64
" duration %d\n"
, pkt->
dts
, pkt->
duration
);
273
274
return
0;
275
}
276
277
static
int
r3d_read_reda
(
AVFormatContext
*s,
AVPacket
*pkt,
Atom
*atom)
278
{
279
AVStream
*st = s->
streams
[1];
280
int
av_unused
tmp, tmp2;
281
int
samples
,
size
;
282
uint64_t pos =
avio_tell
(s->
pb
);
283
unsigned
dts;
284
int
ret;
285
286
dts =
avio_rb32
(s->
pb
);
287
288
st->
codec
->
sample_rate
=
avio_rb32
(s->
pb
);
289
if
(st->
codec
->
sample_rate
<= 0) {
290
av_log
(s,
AV_LOG_ERROR
,
"Bad sample rate\n"
);
291
return
AVERROR_INVALIDDATA
;
292
}
293
294
samples =
avio_rb32
(s->
pb
);
295
296
tmp =
avio_rb32
(s->
pb
);
297
av_dlog
(s,
"packet num %d\n"
, tmp);
298
299
tmp =
avio_rb16
(s->
pb
);
// unknown
300
av_dlog
(s,
"unknown %d\n"
, tmp);
301
302
tmp =
avio_r8
(s->
pb
);
// major version
303
tmp2 =
avio_r8
(s->
pb
);
// minor version
304
av_dlog
(s,
"version %d.%d\n"
, tmp, tmp2);
305
306
tmp =
avio_rb32
(s->
pb
);
// unknown
307
av_dlog
(s,
"unknown %d\n"
, tmp);
308
309
size = atom->
size
- 8 - (
avio_tell
(s->
pb
) - pos);
310
if
(size < 0)
311
return
-1;
312
ret =
av_get_packet
(s->
pb
, pkt, size);
313
if
(ret < 0) {
314
av_log
(s,
AV_LOG_ERROR
,
"error reading audio packet\n"
);
315
return
ret;
316
}
317
318
pkt->
stream_index
= 1;
319
pkt->
dts
= dts;
320
pkt->
duration
=
av_rescale
(samples, st->
time_base
.
den
, st->
codec
->
sample_rate
);
321
av_dlog
(s,
"pkt dts %"
PRId64
" duration %d samples %d sample rate %d\n"
,
322
pkt->
dts
, pkt->
duration
, samples, st->
codec
->
sample_rate
);
323
324
return
0;
325
}
326
327
static
int
r3d_read_packet
(
AVFormatContext
*s,
AVPacket
*pkt)
328
{
329
Atom
atom;
330
int
err = 0;
331
332
while
(!err) {
333
if
(
read_atom
(s, &atom) < 0) {
334
err = -1;
335
break
;
336
}
337
switch
(atom.
tag
) {
338
case
MKTAG
(
'R'
,
'E'
,
'D'
,
'V'
):
339
if
(s->
streams
[0]->
discard
==
AVDISCARD_ALL
)
340
goto
skip;
341
if
(!(err =
r3d_read_redv
(s, pkt, &atom)))
342
return
0;
343
break
;
344
case
MKTAG
(
'R'
,
'E'
,
'D'
,
'A'
):
345
if
(s->
nb_streams
< 2)
346
return
-1;
347
if
(s->
streams
[1]->
discard
==
AVDISCARD_ALL
)
348
goto
skip;
349
if
(!(err =
r3d_read_reda
(s, pkt, &atom)))
350
return
0;
351
break
;
352
default
:
353
skip:
354
avio_skip
(s->
pb
, atom.
size
-8);
355
}
356
}
357
return
err;
358
}
359
360
static
int
r3d_probe
(
AVProbeData
*p)
361
{
362
if
(
AV_RL32
(p->
buf
+ 4) ==
MKTAG
(
'R'
,
'E'
,
'D'
,
'1'
))
363
return
AVPROBE_SCORE_MAX
;
364
return
0;
365
}
366
367
static
int
r3d_seek
(
AVFormatContext
*s,
int
stream_index, int64_t sample_time,
int
flags
)
368
{
369
AVStream
*st = s->
streams
[0];
// video stream
370
R3DContext
*r3d = s->
priv_data
;
371
int
frame_num;
372
373
if
(!st->
avg_frame_rate
.
num
)
374
return
-1;
375
376
frame_num =
av_rescale_q
(sample_time, st->
time_base
,
377
(
AVRational
){st->
avg_frame_rate
.
den
, st->
avg_frame_rate
.
num
});
378
av_dlog
(s,
"seek frame num %d timestamp %"
PRId64
"\n"
,
379
frame_num, sample_time);
380
381
if
(frame_num < r3d->video_offsets_count) {
382
if
(
avio_seek
(s->pb, r3d->video_offsets_count, SEEK_SET) < 0)
383
return
-1;
384
}
else
{
385
av_log
(s, AV_LOG_ERROR,
"could not seek to frame %d\n"
, frame_num);
386
return
-1;
387
}
388
389
return
0;
390
}
391
392
static
int
r3d_close
(
AVFormatContext
*s)
393
{
394
R3DContext
*r3d = s->
priv_data
;
395
396
av_freep
(&r3d->
video_offsets
);
397
398
return
0;
399
}
400
401
AVInputFormat
ff_r3d_demuxer
= {
402
.
name
=
"r3d"
,
403
.long_name =
NULL_IF_CONFIG_SMALL
(
"REDCODE R3D"
),
404
.priv_data_size =
sizeof
(
R3DContext
),
405
.
read_probe
=
r3d_probe
,
406
.
read_header
=
r3d_read_header
,
407
.
read_packet
=
r3d_read_packet
,
408
.
read_close
=
r3d_close
,
409
.
read_seek
=
r3d_seek
,
410
};