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