Main Page
Related Pages
Modules
Data Structures
Files
Examples
File List
Globals
libavformat
iff.c
Go to the documentation of this file.
1
/*
2
* IFF (.iff) file demuxer
3
* Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
4
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
5
* Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
6
*
7
* This file is part of Libav.
8
*
9
* Libav is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU Lesser General Public
11
* License as published by the Free Software Foundation; either
12
* version 2.1 of the License, or (at your option) any later version.
13
*
14
* Libav is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17
* Lesser General Public License for more details.
18
*
19
* You should have received a copy of the GNU Lesser General Public
20
* License along with Libav; if not, write to the Free Software
21
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
*/
23
32
#include "
libavutil/intreadwrite.h
"
33
#include "
libavutil/dict.h
"
34
#include "
avformat.h
"
35
#include "
internal.h
"
36
37
#define ID_8SVX MKTAG('8','S','V','X')
38
#define ID_VHDR MKTAG('V','H','D','R')
39
#define ID_ATAK MKTAG('A','T','A','K')
40
#define ID_RLSE MKTAG('R','L','S','E')
41
#define ID_CHAN MKTAG('C','H','A','N')
42
#define ID_PBM MKTAG('P','B','M',' ')
43
#define ID_ILBM MKTAG('I','L','B','M')
44
#define ID_BMHD MKTAG('B','M','H','D')
45
#define ID_CMAP MKTAG('C','M','A','P')
46
47
#define ID_FORM MKTAG('F','O','R','M')
48
#define ID_ANNO MKTAG('A','N','N','O')
49
#define ID_AUTH MKTAG('A','U','T','H')
50
#define ID_CHRS MKTAG('C','H','R','S')
51
#define ID_COPYRIGHT MKTAG('(','c',')',' ')
52
#define ID_CSET MKTAG('C','S','E','T')
53
#define ID_FVER MKTAG('F','V','E','R')
54
#define ID_NAME MKTAG('N','A','M','E')
55
#define ID_TEXT MKTAG('T','E','X','T')
56
#define ID_BODY MKTAG('B','O','D','Y')
57
#define ID_ANNO MKTAG('A','N','N','O')
58
59
#define LEFT 2
60
#define RIGHT 4
61
#define STEREO 6
62
63
typedef
enum
{
64
COMP_NONE
,
65
COMP_FIB
,
66
COMP_EXP
67
}
svx8_compression_type
;
68
69
typedef
enum
{
70
BITMAP_RAW
,
71
BITMAP_BYTERUN1
72
}
bitmap_compression_type
;
73
74
typedef
struct
{
75
uint64_t
body_pos
;
76
uint32_t
body_size
;
77
uint32_t
sent_bytes
;
78
}
IffDemuxContext
;
79
80
81
/* Metadata string read */
82
static
int
get_metadata
(
AVFormatContext
*s,
83
const
char
*
const
tag
,
84
const
unsigned
data_size)
85
{
86
uint8_t *buf = ((data_size + 1) == 0) ?
NULL
:
av_malloc
(data_size + 1);
87
88
if
(!buf)
89
return
AVERROR
(ENOMEM);
90
91
if
(
avio_read
(s->
pb
, buf, data_size) < 0) {
92
av_free
(buf);
93
return
AVERROR
(EIO);
94
}
95
buf[data_size] = 0;
96
av_dict_set
(&s->
metadata
, tag, buf,
AV_DICT_DONT_STRDUP_VAL
);
97
return
0;
98
}
99
100
static
int
iff_probe
(
AVProbeData
*p)
101
{
102
const
uint8_t *d = p->
buf
;
103
104
if
(
AV_RL32
(d) ==
ID_FORM
&&
105
(
AV_RL32
(d+8) ==
ID_8SVX
||
AV_RL32
(d+8) ==
ID_PBM
||
AV_RL32
(d+8) ==
ID_ILBM
) )
106
return
AVPROBE_SCORE_MAX
;
107
return
0;
108
}
109
110
static
int
iff_read_header
(
AVFormatContext
*s,
111
AVFormatParameters
*ap)
112
{
113
IffDemuxContext
*iff = s->
priv_data
;
114
AVIOContext
*pb = s->
pb
;
115
AVStream
*st;
116
uint32_t chunk_id, data_size;
117
int
compression = -1;
118
119
st =
avformat_new_stream
(s,
NULL
);
120
if
(!st)
121
return
AVERROR
(ENOMEM);
122
123
st->
codec
->
channels
= 1;
124
avio_skip
(pb, 8);
125
// codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
126
st->
codec
->
codec_tag
=
avio_rl32
(pb);
127
128
while
(!pb->
eof_reached
) {
129
uint64_t orig_pos;
130
int
res;
131
const
char
*metadata_tag =
NULL
;
132
chunk_id =
avio_rl32
(pb);
133
data_size =
avio_rb32
(pb);
134
orig_pos =
avio_tell
(pb);
135
136
switch
(chunk_id) {
137
case
ID_VHDR
:
138
st->
codec
->
codec_type
=
AVMEDIA_TYPE_AUDIO
;
139
140
if
(data_size < 14)
141
return
AVERROR_INVALIDDATA
;
142
avio_skip
(pb, 12);
143
st->
codec
->
sample_rate
=
avio_rb16
(pb);
144
if
(data_size >= 16) {
145
avio_skip
(pb, 1);
146
compression =
avio_r8
(pb);
147
}
148
break
;
149
150
case
ID_BODY
:
151
iff->
body_pos
=
avio_tell
(pb);
152
iff->
body_size
= data_size;
153
break
;
154
155
case
ID_CHAN
:
156
if
(data_size < 4)
157
return
AVERROR_INVALIDDATA
;
158
st->
codec
->
channels
= (
avio_rb32
(pb) < 6) ? 1 : 2;
159
break
;
160
161
case
ID_CMAP
:
162
st->
codec
->
extradata_size
= data_size;
163
st->
codec
->
extradata
=
av_malloc
(data_size);
164
if
(!st->
codec
->
extradata
)
165
return
AVERROR
(ENOMEM);
166
if
(
avio_read
(pb, st->
codec
->
extradata
, data_size) < 0)
167
return
AVERROR
(EIO);
168
break
;
169
170
case
ID_BMHD
:
171
st->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
172
if
(data_size <= 8)
173
return
AVERROR_INVALIDDATA
;
174
st->
codec
->
width
=
avio_rb16
(pb);
175
st->
codec
->
height
=
avio_rb16
(pb);
176
avio_skip
(pb, 4);
// x, y offset
177
st->
codec
->
bits_per_coded_sample
=
avio_r8
(pb);
178
if
(data_size >= 11) {
179
avio_skip
(pb, 1);
// masking
180
compression =
avio_r8
(pb);
181
}
182
if
(data_size >= 16) {
183
avio_skip
(pb, 3);
// paddding, transparent
184
st->
sample_aspect_ratio
.
num
=
avio_r8
(pb);
185
st->
sample_aspect_ratio
.
den
=
avio_r8
(pb);
186
}
187
break
;
188
189
case
ID_ANNO
:
190
case
ID_TEXT
:
191
metadata_tag =
"comment"
;
192
break
;
193
194
case
ID_AUTH
:
195
metadata_tag =
"artist"
;
196
break
;
197
198
case
ID_COPYRIGHT
:
199
metadata_tag =
"copyright"
;
200
break
;
201
202
case
ID_NAME
:
203
metadata_tag =
"title"
;
204
break
;
205
}
206
207
if
(metadata_tag) {
208
if
((res =
get_metadata
(s, metadata_tag, data_size)) < 0) {
209
av_log
(s,
AV_LOG_ERROR
,
"cannot allocate metadata tag %s!"
, metadata_tag);
210
return
res;
211
}
212
}
213
avio_skip
(pb, data_size - (
avio_tell
(pb) - orig_pos) + (data_size & 1));
214
}
215
216
avio_seek
(pb, iff->
body_pos
, SEEK_SET);
217
218
switch
(st->
codec
->
codec_type
) {
219
case
AVMEDIA_TYPE_AUDIO
:
220
avpriv_set_pts_info
(st, 32, 1, st->
codec
->
sample_rate
);
221
222
switch
(compression) {
223
case
COMP_NONE
:
224
st->
codec
->
codec_id
=
CODEC_ID_PCM_S8_PLANAR
;
225
break
;
226
case
COMP_FIB
:
227
st->
codec
->
codec_id
= CODEC_ID_8SVX_FIB;
228
break
;
229
case
COMP_EXP
:
230
st->
codec
->
codec_id
= CODEC_ID_8SVX_EXP;
231
break
;
232
default
:
233
av_log
(s,
AV_LOG_ERROR
,
"unknown compression method\n"
);
234
return
-1;
235
}
236
237
st->
codec
->
bits_per_coded_sample
= 8;
238
st->
codec
->
bit_rate
= st->
codec
->
channels
* st->
codec
->
sample_rate
* st->
codec
->
bits_per_coded_sample
;
239
st->
codec
->
block_align
= st->
codec
->
channels
* st->
codec
->
bits_per_coded_sample
;
240
break
;
241
242
case
AVMEDIA_TYPE_VIDEO
:
243
switch
(compression) {
244
case
BITMAP_RAW
:
245
st->
codec
->
codec_id
=
CODEC_ID_IFF_ILBM
;
246
break
;
247
case
BITMAP_BYTERUN1
:
248
st->
codec
->
codec_id
=
CODEC_ID_IFF_BYTERUN1
;
249
break
;
250
default
:
251
av_log
(s,
AV_LOG_ERROR
,
"unknown compression method\n"
);
252
return
AVERROR_INVALIDDATA
;
253
}
254
break
;
255
default
:
256
return
-1;
257
}
258
259
return
0;
260
}
261
262
static
int
iff_read_packet
(
AVFormatContext
*s,
263
AVPacket
*pkt)
264
{
265
IffDemuxContext
*iff = s->
priv_data
;
266
AVIOContext
*pb = s->
pb
;
267
int
ret;
268
269
if
(iff->
sent_bytes
>= iff->
body_size
)
270
return
AVERROR_EOF
;
271
272
ret =
av_get_packet
(pb, pkt, iff->
body_size
);
273
if
(ret < 0)
274
return
ret;
275
276
if
(iff->
sent_bytes
== 0)
277
pkt->
flags
|=
AV_PKT_FLAG_KEY
;
278
iff->
sent_bytes
= iff->
body_size
;
279
280
pkt->
stream_index
= 0;
281
return
ret;
282
}
283
284
AVInputFormat
ff_iff_demuxer
= {
285
.
name
=
"IFF"
,
286
.long_name =
NULL_IF_CONFIG_SMALL
(
"IFF format"
),
287
.priv_data_size =
sizeof
(
IffDemuxContext
),
288
.
read_probe
=
iff_probe
,
289
.
read_header
=
iff_read_header
,
290
.
read_packet
=
iff_read_packet
,
291
};