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