Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> | ||
3 | * Copyright (c) 2010 Peter Ross <pross@xvid.org> | ||
4 | * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com> | ||
5 | * | ||
6 | * This file is part of FFmpeg. | ||
7 | * | ||
8 | * FFmpeg is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU Lesser General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2.1 of the License, or (at your option) any later version. | ||
12 | * | ||
13 | * FFmpeg is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with FFmpeg; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | */ | ||
22 | |||
23 | /** | ||
24 | * @file | ||
25 | * IFF file demuxer | ||
26 | * by Jaikrishnan Menon | ||
27 | * for more information on the .iff file format, visit: | ||
28 | * http://wiki.multimedia.cx/index.php?title=IFF | ||
29 | */ | ||
30 | |||
31 | #include <inttypes.h> | ||
32 | |||
33 | #include "libavutil/avassert.h" | ||
34 | #include "libavutil/channel_layout.h" | ||
35 | #include "libavutil/intreadwrite.h" | ||
36 | #include "libavutil/dict.h" | ||
37 | #include "libavutil/mem.h" | ||
38 | #include "libavcodec/bytestream.h" | ||
39 | #include "avformat.h" | ||
40 | #include "demux.h" | ||
41 | #include "id3v2.h" | ||
42 | #include "internal.h" | ||
43 | |||
44 | #define ID_8SVX MKTAG('8','S','V','X') | ||
45 | #define ID_16SV MKTAG('1','6','S','V') | ||
46 | #define ID_MAUD MKTAG('M','A','U','D') | ||
47 | #define ID_MHDR MKTAG('M','H','D','R') | ||
48 | #define ID_MDAT MKTAG('M','D','A','T') | ||
49 | #define ID_VHDR MKTAG('V','H','D','R') | ||
50 | #define ID_ATAK MKTAG('A','T','A','K') | ||
51 | #define ID_RLSE MKTAG('R','L','S','E') | ||
52 | #define ID_CHAN MKTAG('C','H','A','N') | ||
53 | #define ID_PBM MKTAG('P','B','M',' ') | ||
54 | #define ID_ILBM MKTAG('I','L','B','M') | ||
55 | #define ID_BMHD MKTAG('B','M','H','D') | ||
56 | #define ID_DGBL MKTAG('D','G','B','L') | ||
57 | #define ID_CAMG MKTAG('C','A','M','G') | ||
58 | #define ID_CMAP MKTAG('C','M','A','P') | ||
59 | #define ID_ACBM MKTAG('A','C','B','M') | ||
60 | #define ID_DEEP MKTAG('D','E','E','P') | ||
61 | #define ID_RGB8 MKTAG('R','G','B','8') | ||
62 | #define ID_RGBN MKTAG('R','G','B','N') | ||
63 | #define ID_DSD MKTAG('D','S','D',' ') | ||
64 | #define ID_DST MKTAG('D','S','T',' ') | ||
65 | #define ID_DSTC MKTAG('D','S','T','C') | ||
66 | #define ID_DSTF MKTAG('D','S','T','F') | ||
67 | #define ID_FRTE MKTAG('F','R','T','E') | ||
68 | #define ID_ANIM MKTAG('A','N','I','M') | ||
69 | #define ID_ANHD MKTAG('A','N','H','D') | ||
70 | #define ID_DLTA MKTAG('D','L','T','A') | ||
71 | #define ID_DPAN MKTAG('D','P','A','N') | ||
72 | |||
73 | #define ID_FORM MKTAG('F','O','R','M') | ||
74 | #define ID_FRM8 MKTAG('F','R','M','8') | ||
75 | #define ID_ANNO MKTAG('A','N','N','O') | ||
76 | #define ID_AUTH MKTAG('A','U','T','H') | ||
77 | #define ID_CHRS MKTAG('C','H','R','S') | ||
78 | #define ID_COPYRIGHT MKTAG('(','c',')',' ') | ||
79 | #define ID_CSET MKTAG('C','S','E','T') | ||
80 | #define ID_FVER MKTAG('F','V','E','R') | ||
81 | #define ID_NAME MKTAG('N','A','M','E') | ||
82 | #define ID_TEXT MKTAG('T','E','X','T') | ||
83 | #define ID_ABIT MKTAG('A','B','I','T') | ||
84 | #define ID_BODY MKTAG('B','O','D','Y') | ||
85 | #define ID_DBOD MKTAG('D','B','O','D') | ||
86 | #define ID_DPEL MKTAG('D','P','E','L') | ||
87 | #define ID_DLOC MKTAG('D','L','O','C') | ||
88 | #define ID_TVDC MKTAG('T','V','D','C') | ||
89 | |||
90 | #define LEFT 2 | ||
91 | #define RIGHT 4 | ||
92 | #define STEREO 6 | ||
93 | |||
94 | /** | ||
95 | * This number of bytes if added at the beginning of each AVPacket | ||
96 | * which contain additional information about video properties | ||
97 | * which has to be shared between demuxer and decoder. | ||
98 | * This number may change between frames, e.g. the demuxer might | ||
99 | * set it to smallest possible size of 2 to indicate that there's | ||
100 | * no extradata changing in this frame. | ||
101 | */ | ||
102 | #define IFF_EXTRA_VIDEO_SIZE 41 | ||
103 | |||
104 | typedef enum { | ||
105 | COMP_NONE, | ||
106 | COMP_FIB, | ||
107 | COMP_EXP | ||
108 | } svx8_compression_type; | ||
109 | |||
110 | typedef struct IffDemuxContext { | ||
111 | int is_64bit; ///< chunk size is 64-bit | ||
112 | int64_t body_pos; | ||
113 | int64_t body_end; | ||
114 | uint32_t body_size; | ||
115 | svx8_compression_type svx8_compression; | ||
116 | unsigned maud_bits; | ||
117 | unsigned maud_compression; | ||
118 | unsigned bitmap_compression; ///< delta compression method used | ||
119 | unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) | ||
120 | unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) | ||
121 | unsigned flags; ///< 1 for EHB, 0 is no extra half darkening | ||
122 | unsigned transparency; ///< transparency color index in palette | ||
123 | unsigned masking; ///< masking method used | ||
124 | uint8_t tvdc[32]; ///< TVDC lookup table | ||
125 | int64_t pts; | ||
126 | } IffDemuxContext; | ||
127 | |||
128 | /* Metadata string read */ | ||
129 | 2 | static int get_metadata(AVFormatContext *s, | |
130 | const char *const tag, | ||
131 | const unsigned data_size) | ||
132 | { | ||
133 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | uint8_t *buf = ((data_size + 1) == 0) ? NULL : av_malloc(data_size + 1); |
134 | |||
135 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!buf) |
136 | ✗ | return AVERROR(ENOMEM); | |
137 | |||
138 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (avio_read(s->pb, buf, data_size) != data_size) { |
139 | ✗ | av_free(buf); | |
140 | ✗ | return AVERROR(EIO); | |
141 | } | ||
142 | 2 | buf[data_size] = 0; | |
143 | 2 | av_dict_set(&s->metadata, tag, buf, AV_DICT_DONT_STRDUP_VAL); | |
144 | 2 | return 0; | |
145 | } | ||
146 | |||
147 | 7186 | static int iff_probe(const AVProbeData *p) | |
148 | { | ||
149 | 7186 | const uint8_t *d = p->buf; | |
150 | |||
151 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 7165 times.
|
7186 | if ( (AV_RL32(d) == ID_FORM && |
152 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1 times.
|
21 | (AV_RL32(d+8) == ID_8SVX || |
153 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | AV_RL32(d+8) == ID_16SV || |
154 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | AV_RL32(d+8) == ID_MAUD || |
155 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1 times.
|
20 | AV_RL32(d+8) == ID_PBM || |
156 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | AV_RL32(d+8) == ID_ACBM || |
157 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | AV_RL32(d+8) == ID_DEEP || |
158 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1 times.
|
19 | AV_RL32(d+8) == ID_ILBM || |
159 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_RGB8 || |
160 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_ANIM || |
161 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_RGBN)) || |
162 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7182 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
7183 | (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) |
163 | 4 | return AVPROBE_SCORE_MAX; | |
164 | 7182 | return 0; | |
165 | } | ||
166 | |||
167 | static const AVCodecTag dsd_codec_tags[] = { | ||
168 | { AV_CODEC_ID_DSD_MSBF, ID_DSD }, | ||
169 | { AV_CODEC_ID_DST, ID_DST }, | ||
170 | { AV_CODEC_ID_NONE, 0 }, | ||
171 | }; | ||
172 | |||
173 | |||
174 | #define DSD_SLFT MKTAG('S','L','F','T') | ||
175 | #define DSD_SRGT MKTAG('S','R','G','T') | ||
176 | #define DSD_MLFT MKTAG('M','L','F','T') | ||
177 | #define DSD_MRGT MKTAG('M','R','G','T') | ||
178 | #define DSD_C MKTAG('C',' ',' ',' ') | ||
179 | #define DSD_LS MKTAG('L','S',' ',' ') | ||
180 | #define DSD_RS MKTAG('R','S',' ',' ') | ||
181 | #define DSD_LFE MKTAG('L','F','E',' ') | ||
182 | |||
183 | static const uint32_t dsd_stereo[] = { DSD_SLFT, DSD_SRGT }; | ||
184 | static const uint32_t dsd_5point0[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LS, DSD_RS }; | ||
185 | static const uint32_t dsd_5point1[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LFE, DSD_LS, DSD_RS }; | ||
186 | |||
187 | typedef struct { | ||
188 | AVChannelLayout layout; | ||
189 | const uint32_t * dsd_layout; | ||
190 | } DSDLayoutDesc; | ||
191 | |||
192 | static const DSDLayoutDesc dsd_channel_layout[] = { | ||
193 | { AV_CHANNEL_LAYOUT_STEREO, dsd_stereo }, | ||
194 | { AV_CHANNEL_LAYOUT_5POINT0, dsd_5point0 }, | ||
195 | { AV_CHANNEL_LAYOUT_5POINT1, dsd_5point1 }, | ||
196 | }; | ||
197 | |||
198 | static const AVChannelLayout dsd_loudspeaker_config[] = { | ||
199 | AV_CHANNEL_LAYOUT_STEREO, | ||
200 | { 0 }, { 0 }, | ||
201 | AV_CHANNEL_LAYOUT_5POINT0, AV_CHANNEL_LAYOUT_5POINT1, | ||
202 | }; | ||
203 | |||
204 | static const char * dsd_source_comment[] = { | ||
205 | "dsd_source_comment", | ||
206 | "analogue_source_comment", | ||
207 | "pcm_source_comment", | ||
208 | }; | ||
209 | |||
210 | static const char * dsd_history_comment[] = { | ||
211 | "general_remark", | ||
212 | "operator_name", | ||
213 | "creating_machine", | ||
214 | "timezone", | ||
215 | "file_revision" | ||
216 | }; | ||
217 | |||
218 | ✗ | static int parse_dsd_diin(AVFormatContext *s, AVStream *st, uint64_t eof) | |
219 | { | ||
220 | ✗ | AVIOContext *pb = s->pb; | |
221 | |||
222 | ✗ | while (av_sat_add64(avio_tell(pb), 12) <= eof && !avio_feof(pb)) { | |
223 | ✗ | uint32_t tag = avio_rl32(pb); | |
224 | ✗ | uint64_t size = avio_rb64(pb); | |
225 | ✗ | uint64_t orig_pos = avio_tell(pb); | |
226 | ✗ | const char * metadata_tag = NULL; | |
227 | |||
228 | ✗ | if (size >= INT64_MAX) | |
229 | ✗ | return AVERROR_INVALIDDATA; | |
230 | |||
231 | ✗ | switch(tag) { | |
232 | ✗ | case MKTAG('D','I','A','R'): metadata_tag = "artist"; break; | |
233 | ✗ | case MKTAG('D','I','T','I'): metadata_tag = "title"; break; | |
234 | } | ||
235 | |||
236 | ✗ | if (metadata_tag && size > 4) { | |
237 | ✗ | unsigned int tag_size = avio_rb32(pb); | |
238 | ✗ | int ret = get_metadata(s, metadata_tag, FFMIN(tag_size, size - 4)); | |
239 | ✗ | if (ret < 0) { | |
240 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
241 | ✗ | return ret; | |
242 | } | ||
243 | } | ||
244 | |||
245 | ✗ | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
246 | } | ||
247 | |||
248 | ✗ | return 0; | |
249 | } | ||
250 | |||
251 | 1 | static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) | |
252 | { | ||
253 | 1 | AVIOContext *pb = s->pb; | |
254 | char abss[24]; | ||
255 | int hour, min, sec, i, ret, config; | ||
256 | int dsd_layout[6]; | ||
257 | ID3v2ExtraMeta *id3v2_extra_meta; | ||
258 | |||
259 |
3/4✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
|
4 | while (av_sat_add64(avio_tell(pb), 12) <= eof && !avio_feof(pb)) { |
260 | 3 | uint32_t tag = avio_rl32(pb); | |
261 | 3 | uint64_t size = avio_rb64(pb); | |
262 | 3 | uint64_t orig_pos = avio_tell(pb); | |
263 | |||
264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (size >= INT64_MAX) |
265 | ✗ | return AVERROR_INVALIDDATA; | |
266 | |||
267 |
3/7✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
3 | switch(tag) { |
268 | ✗ | case MKTAG('A','B','S','S'): | |
269 | ✗ | if (size < 8) | |
270 | ✗ | return AVERROR_INVALIDDATA; | |
271 | ✗ | hour = avio_rb16(pb); | |
272 | ✗ | min = avio_r8(pb); | |
273 | ✗ | sec = avio_r8(pb); | |
274 | ✗ | snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb)); | |
275 | ✗ | av_dict_set(&st->metadata, "absolute_start_time", abss, 0); | |
276 | ✗ | break; | |
277 | |||
278 | 1 | case MKTAG('C','H','N','L'): | |
279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 2) |
280 | ✗ | return AVERROR_INVALIDDATA; | |
281 | 1 | st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
282 | 1 | st->codecpar->ch_layout.nb_channels = avio_rb16(pb); | |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 2 + st->codecpar->ch_layout.nb_channels * 4) |
284 | ✗ | return AVERROR_INVALIDDATA; | |
285 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (st->codecpar->ch_layout.nb_channels > FF_ARRAY_ELEMS(dsd_layout)) { |
286 | ✗ | avpriv_request_sample(s, "channel layout"); | |
287 | ✗ | break; | |
288 | } | ||
289 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < st->codecpar->ch_layout.nb_channels; i++) |
290 | 2 | dsd_layout[i] = avio_rl32(pb); | |
291 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) { |
292 | 1 | const DSDLayoutDesc * d = &dsd_channel_layout[i]; | |
293 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (d->layout.nb_channels == st->codecpar->ch_layout.nb_channels && |
294 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | !memcmp(d->dsd_layout, dsd_layout, d->layout.nb_channels * sizeof(uint32_t))) { |
295 | 1 | st->codecpar->ch_layout = d->layout; | |
296 | 1 | break; | |
297 | } | ||
298 | } | ||
299 | 1 | break; | |
300 | |||
301 | 1 | case MKTAG('C','M','P','R'): | |
302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 4) |
303 | ✗ | return AVERROR_INVALIDDATA; | |
304 | 1 | st->codecpar->codec_tag = tag = avio_rl32(pb); | |
305 | 1 | st->codecpar->codec_id = ff_codec_get_id(dsd_codec_tags, tag); | |
306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!st->codecpar->codec_id) { |
307 | ✗ | av_log(s, AV_LOG_ERROR, "'%s' compression is not supported\n", | |
308 | ✗ | av_fourcc2str(tag)); | |
309 | ✗ | return AVERROR_PATCHWELCOME; | |
310 | } | ||
311 | 1 | break; | |
312 | |||
313 | 1 | case MKTAG('F','S',' ',' '): | |
314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 4) |
315 | ✗ | return AVERROR_INVALIDDATA; | |
316 | 1 | st->codecpar->sample_rate = avio_rb32(pb) / 8; | |
317 | 1 | break; | |
318 | |||
319 | ✗ | case MKTAG('I','D','3',' '): | |
320 | ✗ | ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); | |
321 | ✗ | if (id3v2_extra_meta) { | |
322 | ✗ | if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || | |
323 | ✗ | (ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) { | |
324 | ✗ | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
325 | ✗ | return ret; | |
326 | } | ||
327 | ✗ | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
328 | } | ||
329 | |||
330 | ✗ | if (size < avio_tell(pb) - orig_pos) { | |
331 | ✗ | av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n"); | |
332 | ✗ | return AVERROR_INVALIDDATA; | |
333 | } | ||
334 | ✗ | break; | |
335 | |||
336 | ✗ | case MKTAG('L','S','C','O'): | |
337 | ✗ | if (size < 2) | |
338 | ✗ | return AVERROR_INVALIDDATA; | |
339 | ✗ | config = avio_rb16(pb); | |
340 | ✗ | if (config != 0xFFFF) { | |
341 | ✗ | if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config)) | |
342 | ✗ | st->codecpar->ch_layout = dsd_loudspeaker_config[config]; | |
343 | ✗ | if (!st->codecpar->ch_layout.nb_channels) | |
344 | ✗ | avpriv_request_sample(s, "loudspeaker configuration %d", config); | |
345 | } | ||
346 | ✗ | break; | |
347 | } | ||
348 | |||
349 | 3 | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
350 | } | ||
351 | |||
352 | 1 | return 0; | |
353 | } | ||
354 | |||
355 | 11 | static int read_dst_frame(AVFormatContext *s, AVPacket *pkt) | |
356 | { | ||
357 | 11 | IffDemuxContext *iff = s->priv_data; | |
358 | 11 | AVIOContext *pb = s->pb; | |
359 | uint32_t chunk_id; | ||
360 | uint64_t chunk_pos, data_pos, data_size; | ||
361 | 11 | int ret = AVERROR_EOF; | |
362 | |||
363 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | while (!avio_feof(pb)) { |
364 | 12 | chunk_pos = avio_tell(pb); | |
365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (chunk_pos >= iff->body_end) |
366 | ✗ | return AVERROR_EOF; | |
367 | |||
368 | 12 | chunk_id = avio_rl32(pb); | |
369 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); |
370 | 12 | data_pos = avio_tell(pb); | |
371 | |||
372 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | if (data_size < 1 || data_size >= INT64_MAX) |
373 | ✗ | return AVERROR_INVALIDDATA; | |
374 | |||
375 |
2/3✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
12 | switch (chunk_id) { |
376 | 11 | case ID_DSTF: | |
377 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (!pkt) { |
378 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | iff->body_pos = avio_tell(pb) - (iff->is_64bit ? 12 : 8); |
379 | 1 | iff->body_size = iff->body_end - iff->body_pos; | |
380 | 1 | return 0; | |
381 | } | ||
382 | 10 | ret = av_get_packet(pb, pkt, data_size); | |
383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (ret < 0) |
384 | ✗ | return ret; | |
385 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | if (data_size & 1) |
386 | 4 | avio_skip(pb, 1); | |
387 | 10 | pkt->flags |= AV_PKT_FLAG_KEY; | |
388 | 10 | pkt->stream_index = 0; | |
389 | 10 | pkt->duration = s->streams[0]->codecpar->sample_rate / 75; | |
390 | 10 | pkt->pos = chunk_pos; | |
391 | |||
392 | 10 | chunk_pos = avio_tell(pb); | |
393 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (chunk_pos >= iff->body_end) |
394 | 1 | return 0; | |
395 | |||
396 | 9 | avio_seek(pb, chunk_pos, SEEK_SET); | |
397 | 9 | return 0; | |
398 | |||
399 | 1 | case ID_FRTE: | |
400 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
401 | ✗ | return AVERROR_INVALIDDATA; | |
402 | 1 | s->streams[0]->duration = avio_rb32(pb) * (uint64_t)s->streams[0]->codecpar->sample_rate / 75; | |
403 | |||
404 | 1 | break; | |
405 | } | ||
406 | |||
407 | 1 | avio_skip(pb, data_size - (avio_tell(pb) - data_pos) + (data_size & 1)); | |
408 | } | ||
409 | |||
410 | ✗ | return ret; | |
411 | } | ||
412 | |||
413 | static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | ||
414 | static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | ||
415 | static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8}; | ||
416 | static const uint8_t deep_argb[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 1, 0, 8, 0, 2, 0, 8}; | ||
417 | static const uint8_t deep_abgr[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 3, 0, 8, 0, 2, 0, 8}; | ||
418 | |||
419 | 4 | static int iff_read_header(AVFormatContext *s) | |
420 | { | ||
421 | 4 | IffDemuxContext *iff = s->priv_data; | |
422 | 4 | AVIOContext *pb = s->pb; | |
423 | AVStream *st; | ||
424 | uint8_t *buf; | ||
425 | uint32_t chunk_id; | ||
426 | uint64_t data_size; | ||
427 | 4 | uint32_t screenmode = 0, num, den; | |
428 | 4 | unsigned transparency = 0; | |
429 | 4 | unsigned masking = 0; // no mask | |
430 | uint8_t fmt[16]; | ||
431 | int fmt_size; | ||
432 | |||
433 | 4 | st = avformat_new_stream(s, NULL); | |
434 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!st) |
435 | ✗ | return AVERROR(ENOMEM); | |
436 | |||
437 | 4 | st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
438 | 4 | iff->is_64bit = avio_rl32(pb) == ID_FRM8; | |
439 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | avio_skip(pb, iff->is_64bit ? 8 : 4); |
440 | // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content | ||
441 | 4 | st->codecpar->codec_tag = avio_rl32(pb); | |
442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (st->codecpar->codec_tag == ID_ANIM) { |
443 | ✗ | avio_skip(pb, 12); | |
444 | } | ||
445 | 4 | iff->bitmap_compression = -1; | |
446 | 4 | iff->svx8_compression = -1; | |
447 | 4 | iff->maud_bits = -1; | |
448 | 4 | iff->maud_compression = -1; | |
449 | |||
450 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 4 times.
|
41 | while(!avio_feof(pb)) { |
451 | uint64_t orig_pos; | ||
452 | int res; | ||
453 | 37 | const char *metadata_tag = NULL; | |
454 | int version, nb_comments, i; | ||
455 | 37 | chunk_id = avio_rl32(pb); | |
456 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
|
37 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); |
457 | 37 | orig_pos = avio_tell(pb); | |
458 | |||
459 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (data_size >= INT64_MAX) |
460 | ✗ | return AVERROR_INVALIDDATA; | |
461 | |||
462 |
10/22✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 23 times.
|
37 | switch(chunk_id) { |
463 | 1 | case ID_VHDR: | |
464 | 1 | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
465 | |||
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 14) |
467 | ✗ | return AVERROR_INVALIDDATA; | |
468 | 1 | avio_skip(pb, 12); | |
469 | 1 | st->codecpar->sample_rate = avio_rb16(pb); | |
470 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (data_size >= 16) { |
471 | 1 | avio_skip(pb, 1); | |
472 | 1 | iff->svx8_compression = avio_r8(pb); | |
473 | } | ||
474 | 1 | break; | |
475 | |||
476 | ✗ | case ID_MHDR: | |
477 | ✗ | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
478 | |||
479 | ✗ | if (data_size < 32) | |
480 | ✗ | return AVERROR_INVALIDDATA; | |
481 | ✗ | avio_skip(pb, 4); | |
482 | ✗ | iff->maud_bits = avio_rb16(pb); | |
483 | ✗ | avio_skip(pb, 2); | |
484 | ✗ | num = avio_rb32(pb); | |
485 | ✗ | den = avio_rb16(pb); | |
486 | ✗ | if (!den) | |
487 | ✗ | return AVERROR_INVALIDDATA; | |
488 | ✗ | avio_skip(pb, 2); | |
489 | ✗ | st->codecpar->sample_rate = num / den; | |
490 | ✗ | st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
491 | ✗ | st->codecpar->ch_layout.nb_channels = avio_rb16(pb); | |
492 | ✗ | iff->maud_compression = avio_rb16(pb); | |
493 | ✗ | if (st->codecpar->ch_layout.nb_channels == 1) | |
494 | ✗ | st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
495 | ✗ | else if (st->codecpar->ch_layout.nb_channels == 2) | |
496 | ✗ | st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
497 | ✗ | break; | |
498 | |||
499 | 4 | case ID_ABIT: | |
500 | case ID_BODY: | ||
501 | case ID_DBOD: | ||
502 | case ID_DSD: | ||
503 | case ID_DST: | ||
504 | case ID_MDAT: | ||
505 | 4 | iff->body_pos = avio_tell(pb); | |
506 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (iff->body_pos < 0 || iff->body_pos + data_size > INT64_MAX) |
507 | ✗ | return AVERROR_INVALIDDATA; | |
508 | |||
509 | 4 | iff->body_end = iff->body_pos + data_size; | |
510 | 4 | iff->body_size = data_size; | |
511 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (chunk_id == ID_DST) { |
512 | 1 | int ret = read_dst_frame(s, NULL); | |
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
514 | ✗ | return ret; | |
515 | } | ||
516 | 4 | break; | |
517 | |||
518 | ✗ | case ID_CHAN: | |
519 | ✗ | if (data_size < 4) | |
520 | ✗ | return AVERROR_INVALIDDATA; | |
521 | ✗ | if (avio_rb32(pb) < 6) { | |
522 | ✗ | st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
523 | } else { | ||
524 | ✗ | st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
525 | } | ||
526 | ✗ | break; | |
527 | |||
528 | 1 | case ID_CAMG: | |
529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
530 | ✗ | return AVERROR_INVALIDDATA; | |
531 | 1 | screenmode = avio_rb32(pb); | |
532 | 1 | break; | |
533 | |||
534 | 2 | case ID_CMAP: | |
535 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (data_size < 3 || data_size > 768 || data_size % 3) { |
536 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n", | |
537 | data_size); | ||
538 | ✗ | return AVERROR_INVALIDDATA; | |
539 | } | ||
540 | 2 | res = ff_alloc_extradata(st->codecpar, | |
541 | 2 | data_size + IFF_EXTRA_VIDEO_SIZE); | |
542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (res < 0) |
543 | ✗ | return res; | |
544 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (avio_read(pb, st->codecpar->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) { |
545 | ✗ | av_freep(&st->codecpar->extradata); | |
546 | ✗ | st->codecpar->extradata_size = 0; | |
547 | ✗ | return AVERROR(EIO); | |
548 | } | ||
549 | 2 | break; | |
550 | |||
551 | 2 | case ID_BMHD: | |
552 | 2 | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; | |
553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (data_size <= 8) |
554 | ✗ | return AVERROR_INVALIDDATA; | |
555 | 2 | st->codecpar->width = avio_rb16(pb); | |
556 | 2 | st->codecpar->height = avio_rb16(pb); | |
557 | 2 | avio_skip(pb, 4); // x, y offset | |
558 | 2 | st->codecpar->bits_per_coded_sample = avio_r8(pb); | |
559 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 10) |
560 | 2 | masking = avio_r8(pb); | |
561 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 11) |
562 | 2 | iff->bitmap_compression = avio_r8(pb); | |
563 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 14) { |
564 | 2 | avio_skip(pb, 1); // padding | |
565 | 2 | transparency = avio_rb16(pb); | |
566 | } | ||
567 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 16) { |
568 | 2 | st->sample_aspect_ratio.num = avio_r8(pb); | |
569 | 2 | st->sample_aspect_ratio.den = avio_r8(pb); | |
570 | } | ||
571 | 2 | break; | |
572 | |||
573 | ✗ | case ID_ANHD: | |
574 | ✗ | break; | |
575 | |||
576 | ✗ | case ID_DPAN: | |
577 | ✗ | avio_skip(pb, 2); | |
578 | ✗ | st->duration = avio_rb16(pb); | |
579 | ✗ | break; | |
580 | |||
581 | ✗ | case ID_DPEL: | |
582 | ✗ | if (data_size < 4 || (data_size & 3)) | |
583 | ✗ | return AVERROR_INVALIDDATA; | |
584 | ✗ | if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0) | |
585 | ✗ | return fmt_size; | |
586 | ✗ | if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24))) | |
587 | ✗ | st->codecpar->format = AV_PIX_FMT_RGB24; | |
588 | ✗ | else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba))) | |
589 | ✗ | st->codecpar->format = AV_PIX_FMT_RGBA; | |
590 | ✗ | else if (fmt_size == sizeof(deep_bgra) && !memcmp(fmt, deep_bgra, sizeof(deep_bgra))) | |
591 | ✗ | st->codecpar->format = AV_PIX_FMT_BGRA; | |
592 | ✗ | else if (fmt_size == sizeof(deep_argb) && !memcmp(fmt, deep_argb, sizeof(deep_argb))) | |
593 | ✗ | st->codecpar->format = AV_PIX_FMT_ARGB; | |
594 | ✗ | else if (fmt_size == sizeof(deep_abgr) && !memcmp(fmt, deep_abgr, sizeof(deep_abgr))) | |
595 | ✗ | st->codecpar->format = AV_PIX_FMT_ABGR; | |
596 | else { | ||
597 | ✗ | avpriv_request_sample(s, "color format %.16s", fmt); | |
598 | ✗ | return AVERROR_PATCHWELCOME; | |
599 | } | ||
600 | ✗ | break; | |
601 | |||
602 | ✗ | case ID_DGBL: | |
603 | ✗ | st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; | |
604 | ✗ | if (data_size < 8) | |
605 | ✗ | return AVERROR_INVALIDDATA; | |
606 | ✗ | st->codecpar->width = avio_rb16(pb); | |
607 | ✗ | st->codecpar->height = avio_rb16(pb); | |
608 | ✗ | iff->bitmap_compression = avio_rb16(pb); | |
609 | ✗ | st->sample_aspect_ratio.num = avio_r8(pb); | |
610 | ✗ | st->sample_aspect_ratio.den = avio_r8(pb); | |
611 | ✗ | st->codecpar->bits_per_coded_sample = 24; | |
612 | ✗ | break; | |
613 | |||
614 | ✗ | case ID_DLOC: | |
615 | ✗ | if (data_size < 4) | |
616 | ✗ | return AVERROR_INVALIDDATA; | |
617 | ✗ | st->codecpar->width = avio_rb16(pb); | |
618 | ✗ | st->codecpar->height = avio_rb16(pb); | |
619 | ✗ | break; | |
620 | |||
621 | ✗ | case ID_TVDC: | |
622 | ✗ | if (data_size < sizeof(iff->tvdc)) | |
623 | ✗ | return AVERROR_INVALIDDATA; | |
624 | ✗ | res = avio_read(pb, iff->tvdc, sizeof(iff->tvdc)); | |
625 | ✗ | if (res < 0) | |
626 | ✗ | return res; | |
627 | ✗ | break; | |
628 | |||
629 | 1 | case ID_ANNO: | |
630 | 1 | case ID_TEXT: metadata_tag = "comment"; break; | |
631 | ✗ | case ID_AUTH: metadata_tag = "artist"; break; | |
632 | ✗ | case ID_COPYRIGHT: metadata_tag = "copyright"; break; | |
633 | 1 | case ID_NAME: metadata_tag = "title"; break; | |
634 | |||
635 | /* DSD tags */ | ||
636 | |||
637 | 1 | case MKTAG('F','V','E','R'): | |
638 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
639 | ✗ | return AVERROR_INVALIDDATA; | |
640 | 1 | version = avio_rb32(pb); | |
641 | 1 | av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF); | |
642 | 1 | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
643 | 1 | break; | |
644 | |||
645 | ✗ | case MKTAG('D','I','I','N'): | |
646 | ✗ | res = parse_dsd_diin(s, st, orig_pos + data_size); | |
647 | ✗ | if (res < 0) | |
648 | ✗ | return res; | |
649 | ✗ | break; | |
650 | |||
651 | 1 | case MKTAG('P','R','O','P'): | |
652 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
653 | ✗ | return AVERROR_INVALIDDATA; | |
654 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (avio_rl32(pb) != MKTAG('S','N','D',' ')) { |
655 | ✗ | avpriv_request_sample(s, "unknown property type"); | |
656 | ✗ | break; | |
657 | } | ||
658 | 1 | res = parse_dsd_prop(s, st, orig_pos + data_size); | |
659 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (res < 0) |
660 | ✗ | return res; | |
661 | 1 | break; | |
662 | |||
663 | ✗ | case MKTAG('C','O','M','T'): | |
664 | ✗ | if (data_size < 2) | |
665 | ✗ | return AVERROR_INVALIDDATA; | |
666 | ✗ | nb_comments = avio_rb16(pb); | |
667 | ✗ | for (i = 0; i < nb_comments; i++) { | |
668 | int year, mon, day, hour, min, type, ref; | ||
669 | char tmp[24]; | ||
670 | const char *tag; | ||
671 | int metadata_size; | ||
672 | |||
673 | ✗ | year = avio_rb16(pb); | |
674 | ✗ | mon = avio_r8(pb); | |
675 | ✗ | day = avio_r8(pb); | |
676 | ✗ | hour = avio_r8(pb); | |
677 | ✗ | min = avio_r8(pb); | |
678 | ✗ | snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min); | |
679 | ✗ | av_dict_set(&st->metadata, "comment_time", tmp, 0); | |
680 | |||
681 | ✗ | type = avio_rb16(pb); | |
682 | ✗ | ref = avio_rb16(pb); | |
683 | ✗ | switch (type) { | |
684 | ✗ | case 1: | |
685 | ✗ | if (!i) | |
686 | ✗ | tag = "channel_comment"; | |
687 | else { | ||
688 | ✗ | snprintf(tmp, sizeof(tmp), "channel%d_comment", ref); | |
689 | ✗ | tag = tmp; | |
690 | } | ||
691 | ✗ | break; | |
692 | ✗ | case 2: | |
693 | ✗ | tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_source_comment[ref] : "source_comment"; | |
694 | ✗ | break; | |
695 | ✗ | case 3: | |
696 | ✗ | tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history"; | |
697 | ✗ | break; | |
698 | ✗ | default: | |
699 | ✗ | tag = "comment"; | |
700 | } | ||
701 | |||
702 | ✗ | metadata_size = avio_rb32(pb); | |
703 | ✗ | if ((res = get_metadata(s, tag, metadata_size)) < 0) { | |
704 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag); | |
705 | ✗ | return res; | |
706 | } | ||
707 | |||
708 | ✗ | if (metadata_size & 1) | |
709 | ✗ | avio_skip(pb, 1); | |
710 | } | ||
711 | ✗ | break; | |
712 | } | ||
713 | |||
714 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35 times.
|
37 | if (metadata_tag) { |
715 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if ((res = get_metadata(s, metadata_tag, data_size)) < 0) { |
716 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
717 | ✗ | return res; | |
718 | } | ||
719 | } | ||
720 | 37 | avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); | |
721 | } | ||
722 | |||
723 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (st->codecpar->codec_tag == ID_ANIM) |
724 | ✗ | avio_seek(pb, 12, SEEK_SET); | |
725 | else | ||
726 | 4 | avio_seek(pb, iff->body_pos, SEEK_SET); | |
727 | |||
728 |
2/3✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | switch(st->codecpar->codec_type) { |
729 | 2 | case AVMEDIA_TYPE_AUDIO: | |
730 | 2 | avpriv_set_pts_info(st, 32, 1, st->codecpar->sample_rate); | |
731 | |||
732 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (st->codecpar->codec_tag == ID_16SV) |
733 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR; | |
734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | else if (st->codecpar->codec_tag == ID_MAUD) { |
735 | ✗ | if (iff->maud_bits == 8 && !iff->maud_compression) { | |
736 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_U8; | |
737 | ✗ | } else if (iff->maud_bits == 16 && !iff->maud_compression) { | |
738 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE; | |
739 | ✗ | } else if (iff->maud_bits == 8 && iff->maud_compression == 2) { | |
740 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; | |
741 | ✗ | } else if (iff->maud_bits == 8 && iff->maud_compression == 3) { | |
742 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; | |
743 | } else { | ||
744 | ✗ | avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits); | |
745 | ✗ | return AVERROR_PATCHWELCOME; | |
746 | } | ||
747 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | } else if (st->codecpar->codec_tag != ID_DSD && |
748 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | st->codecpar->codec_tag != ID_DST) { |
749 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | switch (iff->svx8_compression) { |
750 | ✗ | case COMP_NONE: | |
751 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; | |
752 | ✗ | break; | |
753 | 1 | case COMP_FIB: | |
754 | 1 | st->codecpar->codec_id = AV_CODEC_ID_8SVX_FIB; | |
755 | 1 | break; | |
756 | ✗ | case COMP_EXP: | |
757 | ✗ | st->codecpar->codec_id = AV_CODEC_ID_8SVX_EXP; | |
758 | ✗ | break; | |
759 | ✗ | default: | |
760 | ✗ | av_log(s, AV_LOG_ERROR, | |
761 | ✗ | "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); | |
762 | ✗ | return -1; | |
763 | } | ||
764 | } | ||
765 | |||
766 | 2 | st->codecpar->bits_per_coded_sample = av_get_bits_per_sample(st->codecpar->codec_id); | |
767 | 2 | st->codecpar->bit_rate = (int64_t)st->codecpar->ch_layout.nb_channels * | |
768 | 2 | st->codecpar->sample_rate * | |
769 | 2 | st->codecpar->bits_per_coded_sample; | |
770 | 2 | st->codecpar->block_align = st->codecpar->ch_layout.nb_channels * | |
771 | 2 | st->codecpar->bits_per_coded_sample; | |
772 |
2/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2 | if ((st->codecpar->codec_tag == ID_DSD || st->codecpar->codec_tag == ID_MAUD) && st->codecpar->block_align <= 0) |
773 | ✗ | return AVERROR_INVALIDDATA; | |
774 | 2 | break; | |
775 | |||
776 | 2 | case AVMEDIA_TYPE_VIDEO: | |
777 | 2 | iff->bpp = st->codecpar->bits_per_coded_sample; | |
778 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (st->codecpar->codec_tag == ID_ANIM) |
779 | ✗ | avpriv_set_pts_info(st, 32, 1, 60); | |
780 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { |
781 | ✗ | iff->ham = iff->bpp > 6 ? 6 : 4; | |
782 | ✗ | st->codecpar->bits_per_coded_sample = 24; | |
783 | } | ||
784 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8; |
785 | 2 | iff->masking = masking; | |
786 | 2 | iff->transparency = transparency; | |
787 | |||
788 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!st->codecpar->extradata) { |
789 | ✗ | int ret = ff_alloc_extradata(st->codecpar, IFF_EXTRA_VIDEO_SIZE); | |
790 | ✗ | if (ret < 0) | |
791 | ✗ | return ret; | |
792 | } | ||
793 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | av_assert0(st->codecpar->extradata_size >= IFF_EXTRA_VIDEO_SIZE); |
794 | 2 | buf = st->codecpar->extradata; | |
795 | 2 | bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE); | |
796 | 2 | bytestream_put_byte(&buf, iff->bitmap_compression); | |
797 | 2 | bytestream_put_byte(&buf, iff->bpp); | |
798 | 2 | bytestream_put_byte(&buf, iff->ham); | |
799 | 2 | bytestream_put_byte(&buf, iff->flags); | |
800 | 2 | bytestream_put_be16(&buf, iff->transparency); | |
801 | 2 | bytestream_put_byte(&buf, iff->masking); | |
802 | 2 | bytestream_put_buffer(&buf, iff->tvdc, sizeof(iff->tvdc)); | |
803 | 2 | st->codecpar->codec_id = AV_CODEC_ID_IFF_ILBM; | |
804 | 2 | break; | |
805 | ✗ | default: | |
806 | ✗ | return -1; | |
807 | } | ||
808 | |||
809 | 4 | return 0; | |
810 | } | ||
811 | |||
812 | ✗ | static unsigned get_anim_duration(uint8_t *buf, int size) | |
813 | { | ||
814 | GetByteContext gb; | ||
815 | |||
816 | ✗ | bytestream2_init(&gb, buf, size); | |
817 | ✗ | bytestream2_skip(&gb, 4); | |
818 | ✗ | while (bytestream2_get_bytes_left(&gb) > 8) { | |
819 | ✗ | unsigned chunk = bytestream2_get_le32(&gb); | |
820 | ✗ | unsigned size = bytestream2_get_be32(&gb); | |
821 | |||
822 | ✗ | if (chunk == ID_ANHD) { | |
823 | ✗ | if (size < 40) | |
824 | ✗ | break; | |
825 | ✗ | bytestream2_skip(&gb, 14); | |
826 | ✗ | return bytestream2_get_be32(&gb); | |
827 | } else { | ||
828 | ✗ | bytestream2_skip(&gb, size + size & 1); | |
829 | } | ||
830 | } | ||
831 | ✗ | return 10; | |
832 | } | ||
833 | |||
834 | 21 | static int iff_read_packet(AVFormatContext *s, | |
835 | AVPacket *pkt) | ||
836 | { | ||
837 | 21 | IffDemuxContext *iff = s->priv_data; | |
838 | 21 | AVIOContext *pb = s->pb; | |
839 | 21 | AVStream *st = s->streams[0]; | |
840 | int ret; | ||
841 | 21 | int64_t pos = avio_tell(pb); | |
842 | |||
843 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | if (avio_feof(pb)) |
844 | ✗ | return AVERROR_EOF; | |
845 |
3/4✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 13 times.
|
21 | if (st->codecpar->codec_tag != ID_ANIM && pos >= iff->body_end) |
846 | 8 | return AVERROR_EOF; | |
847 | |||
848 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
|
13 | if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { |
849 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (st->codecpar->codec_tag == ID_DSD || st->codecpar->codec_tag == ID_MAUD) { |
850 | ✗ | ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * st->codecpar->block_align)); | |
851 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
|
11 | } else if (st->codecpar->codec_tag == ID_DST) { |
852 | 10 | return read_dst_frame(s, pkt); | |
853 | } else { | ||
854 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (iff->body_size > INT_MAX || !iff->body_size) |
855 | ✗ | return AVERROR_INVALIDDATA; | |
856 | 1 | ret = av_get_packet(pb, pkt, iff->body_size); | |
857 | } | ||
858 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && |
859 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | st->codecpar->codec_tag == ID_ANIM) { |
860 | uint64_t data_size, orig_pos; | ||
861 | uint32_t chunk_id, chunk_id2; | ||
862 | |||
863 | ✗ | while (!avio_feof(pb)) { | |
864 | ✗ | if (avio_feof(pb)) | |
865 | ✗ | return AVERROR_EOF; | |
866 | |||
867 | ✗ | orig_pos = avio_tell(pb); | |
868 | ✗ | chunk_id = avio_rl32(pb); | |
869 | ✗ | data_size = avio_rb32(pb); | |
870 | ✗ | chunk_id2 = avio_rl32(pb); | |
871 | |||
872 | ✗ | if (chunk_id == ID_FORM && | |
873 | chunk_id2 == ID_ILBM) { | ||
874 | ✗ | avio_skip(pb, -4); | |
875 | ✗ | break; | |
876 | ✗ | } else if (chunk_id == ID_FORM && | |
877 | chunk_id2 == ID_ANIM) { | ||
878 | ✗ | continue; | |
879 | } else { | ||
880 | ✗ | avio_skip(pb, data_size); | |
881 | } | ||
882 | } | ||
883 | ✗ | ret = av_get_packet(pb, pkt, data_size); | |
884 | ✗ | pkt->pos = orig_pos; | |
885 | ✗ | pkt->duration = get_anim_duration(pkt->data, pkt->size); | |
886 | ✗ | if (pos == 12) | |
887 | ✗ | pkt->flags |= AV_PKT_FLAG_KEY; | |
888 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && |
889 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | st->codecpar->codec_tag != ID_ANIM) { |
890 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (iff->body_size > INT_MAX || !iff->body_size) |
891 | ✗ | return AVERROR_INVALIDDATA; | |
892 | 2 | ret = av_get_packet(pb, pkt, iff->body_size); | |
893 | 2 | pkt->pos = pos; | |
894 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (pos == iff->body_pos) |
895 | 2 | pkt->flags |= AV_PKT_FLAG_KEY; | |
896 | } else { | ||
897 | ✗ | av_assert0(0); | |
898 | } | ||
899 | |||
900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ret < 0) |
901 | ✗ | return ret; | |
902 | 3 | pkt->stream_index = 0; | |
903 | 3 | return ret; | |
904 | } | ||
905 | |||
906 | const FFInputFormat ff_iff_demuxer = { | ||
907 | .p.name = "iff", | ||
908 | .p.long_name = NULL_IF_CONFIG_SMALL("IFF (Interchange File Format)"), | ||
909 | .p.flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, | ||
910 | .priv_data_size = sizeof(IffDemuxContext), | ||
911 | .read_probe = iff_probe, | ||
912 | .read_header = iff_read_header, | ||
913 | .read_packet = iff_read_packet, | ||
914 | }; | ||
915 |