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 | int64_t sbdy_pos; | ||
115 | int64_t resume_pos; | ||
116 | uint32_t body_size; | ||
117 | svx8_compression_type svx8_compression; | ||
118 | unsigned maud_bits; | ||
119 | unsigned maud_compression; | ||
120 | unsigned bitmap_compression; ///< delta compression method used | ||
121 | unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) | ||
122 | unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) | ||
123 | unsigned flags; ///< 1 for EHB, 0 is no extra half darkening | ||
124 | unsigned transparency; ///< transparency color index in palette | ||
125 | unsigned masking; ///< masking method used | ||
126 | uint8_t tvdc[32]; ///< TVDC lookup table | ||
127 | uint32_t form_tag; | ||
128 | int audio_stream_index; | ||
129 | int video_stream_index; | ||
130 | } IffDemuxContext; | ||
131 | |||
132 | /* Metadata string read */ | ||
133 | 2 | static int get_metadata(AVFormatContext *s, | |
134 | const char *const tag, | ||
135 | const unsigned data_size) | ||
136 | { | ||
137 |
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); |
138 | |||
139 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!buf) |
140 | ✗ | return AVERROR(ENOMEM); | |
141 | |||
142 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (avio_read(s->pb, buf, data_size) != data_size) { |
143 | ✗ | av_free(buf); | |
144 | ✗ | return AVERROR(EIO); | |
145 | } | ||
146 | 2 | buf[data_size] = 0; | |
147 | 2 | av_dict_set(&s->metadata, tag, buf, AV_DICT_DONT_STRDUP_VAL); | |
148 | 2 | return 0; | |
149 | } | ||
150 | |||
151 | 7203 | static int iff_probe(const AVProbeData *p) | |
152 | { | ||
153 | 7203 | const uint8_t *d = p->buf; | |
154 | |||
155 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 7182 times.
|
7203 | if ( (AV_RL32(d) == ID_FORM && |
156 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1 times.
|
21 | (AV_RL32(d+8) == ID_8SVX || |
157 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | AV_RL32(d+8) == ID_16SV || |
158 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | AV_RL32(d+8) == ID_MAUD || |
159 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1 times.
|
20 | AV_RL32(d+8) == ID_PBM || |
160 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | AV_RL32(d+8) == ID_ACBM || |
161 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | AV_RL32(d+8) == ID_DEEP || |
162 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 1 times.
|
19 | AV_RL32(d+8) == ID_ILBM || |
163 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_RGB8 || |
164 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_ANIM || |
165 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | AV_RL32(d+8) == ID_RGBN)) || |
166 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7199 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
7200 | (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) |
167 | 4 | return AVPROBE_SCORE_MAX; | |
168 | 7199 | return 0; | |
169 | } | ||
170 | |||
171 | static const AVCodecTag dsd_codec_tags[] = { | ||
172 | { AV_CODEC_ID_DSD_MSBF, ID_DSD }, | ||
173 | { AV_CODEC_ID_DST, ID_DST }, | ||
174 | { AV_CODEC_ID_NONE, 0 }, | ||
175 | }; | ||
176 | |||
177 | |||
178 | #define DSD_SLFT MKTAG('S','L','F','T') | ||
179 | #define DSD_SRGT MKTAG('S','R','G','T') | ||
180 | #define DSD_MLFT MKTAG('M','L','F','T') | ||
181 | #define DSD_MRGT MKTAG('M','R','G','T') | ||
182 | #define DSD_C MKTAG('C',' ',' ',' ') | ||
183 | #define DSD_LS MKTAG('L','S',' ',' ') | ||
184 | #define DSD_RS MKTAG('R','S',' ',' ') | ||
185 | #define DSD_LFE MKTAG('L','F','E',' ') | ||
186 | |||
187 | static const uint32_t dsd_stereo[] = { DSD_SLFT, DSD_SRGT }; | ||
188 | static const uint32_t dsd_5point0[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LS, DSD_RS }; | ||
189 | static const uint32_t dsd_5point1[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LFE, DSD_LS, DSD_RS }; | ||
190 | |||
191 | typedef struct { | ||
192 | AVChannelLayout layout; | ||
193 | const uint32_t * dsd_layout; | ||
194 | } DSDLayoutDesc; | ||
195 | |||
196 | static const DSDLayoutDesc dsd_channel_layout[] = { | ||
197 | { AV_CHANNEL_LAYOUT_STEREO, dsd_stereo }, | ||
198 | { AV_CHANNEL_LAYOUT_5POINT0, dsd_5point0 }, | ||
199 | { AV_CHANNEL_LAYOUT_5POINT1, dsd_5point1 }, | ||
200 | }; | ||
201 | |||
202 | static const AVChannelLayout dsd_loudspeaker_config[] = { | ||
203 | AV_CHANNEL_LAYOUT_STEREO, | ||
204 | { 0 }, { 0 }, | ||
205 | AV_CHANNEL_LAYOUT_5POINT0, AV_CHANNEL_LAYOUT_5POINT1, | ||
206 | }; | ||
207 | |||
208 | static const char * dsd_source_comment[] = { | ||
209 | "dsd_source_comment", | ||
210 | "analogue_source_comment", | ||
211 | "pcm_source_comment", | ||
212 | }; | ||
213 | |||
214 | static const char * dsd_history_comment[] = { | ||
215 | "general_remark", | ||
216 | "operator_name", | ||
217 | "creating_machine", | ||
218 | "timezone", | ||
219 | "file_revision" | ||
220 | }; | ||
221 | |||
222 | ✗ | static int parse_dsd_diin(AVFormatContext *s, AVStream *st, uint64_t eof) | |
223 | { | ||
224 | ✗ | AVIOContext *pb = s->pb; | |
225 | |||
226 | ✗ | while (av_sat_add64(avio_tell(pb), 12) <= eof && !avio_feof(pb)) { | |
227 | ✗ | uint32_t tag = avio_rl32(pb); | |
228 | ✗ | uint64_t size = avio_rb64(pb); | |
229 | ✗ | uint64_t orig_pos = avio_tell(pb); | |
230 | ✗ | const char * metadata_tag = NULL; | |
231 | |||
232 | ✗ | if (size >= INT64_MAX) | |
233 | ✗ | return AVERROR_INVALIDDATA; | |
234 | |||
235 | ✗ | switch(tag) { | |
236 | ✗ | case MKTAG('D','I','A','R'): metadata_tag = "artist"; break; | |
237 | ✗ | case MKTAG('D','I','T','I'): metadata_tag = "title"; break; | |
238 | } | ||
239 | |||
240 | ✗ | if (metadata_tag && size > 4) { | |
241 | ✗ | unsigned int tag_size = avio_rb32(pb); | |
242 | ✗ | int ret = get_metadata(s, metadata_tag, FFMIN(tag_size, size - 4)); | |
243 | ✗ | if (ret < 0) { | |
244 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
245 | ✗ | return ret; | |
246 | } | ||
247 | } | ||
248 | |||
249 | ✗ | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
250 | } | ||
251 | |||
252 | ✗ | return 0; | |
253 | } | ||
254 | |||
255 | 1 | static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) | |
256 | { | ||
257 | 1 | AVIOContext *pb = s->pb; | |
258 | char abss[24]; | ||
259 | int hour, min, sec, i, ret, config; | ||
260 | int dsd_layout[6]; | ||
261 | ID3v2ExtraMeta *id3v2_extra_meta; | ||
262 | |||
263 |
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)) { |
264 | 3 | uint32_t tag = avio_rl32(pb); | |
265 | 3 | uint64_t size = avio_rb64(pb); | |
266 | 3 | uint64_t orig_pos = avio_tell(pb); | |
267 | |||
268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (size >= INT64_MAX) |
269 | ✗ | return AVERROR_INVALIDDATA; | |
270 | |||
271 |
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) { |
272 | ✗ | case MKTAG('A','B','S','S'): | |
273 | ✗ | if (size < 8) | |
274 | ✗ | return AVERROR_INVALIDDATA; | |
275 | ✗ | hour = avio_rb16(pb); | |
276 | ✗ | min = avio_r8(pb); | |
277 | ✗ | sec = avio_r8(pb); | |
278 | ✗ | snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb)); | |
279 | ✗ | av_dict_set(&st->metadata, "absolute_start_time", abss, 0); | |
280 | ✗ | break; | |
281 | |||
282 | 1 | case MKTAG('C','H','N','L'): | |
283 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 2) |
284 | ✗ | return AVERROR_INVALIDDATA; | |
285 | 1 | st->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
286 | 1 | st->codecpar->ch_layout.nb_channels = avio_rb16(pb); | |
287 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 2 + st->codecpar->ch_layout.nb_channels * 4) |
288 | ✗ | return AVERROR_INVALIDDATA; | |
289 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (st->codecpar->ch_layout.nb_channels > FF_ARRAY_ELEMS(dsd_layout)) { |
290 | ✗ | avpriv_request_sample(s, "channel layout"); | |
291 | ✗ | break; | |
292 | } | ||
293 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < st->codecpar->ch_layout.nb_channels; i++) |
294 | 2 | dsd_layout[i] = avio_rl32(pb); | |
295 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) { |
296 | 1 | const DSDLayoutDesc * d = &dsd_channel_layout[i]; | |
297 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (d->layout.nb_channels == st->codecpar->ch_layout.nb_channels && |
298 |
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))) { |
299 | 1 | st->codecpar->ch_layout = d->layout; | |
300 | 1 | break; | |
301 | } | ||
302 | } | ||
303 | 1 | break; | |
304 | |||
305 | 1 | case MKTAG('C','M','P','R'): | |
306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 4) |
307 | ✗ | return AVERROR_INVALIDDATA; | |
308 | 1 | st->codecpar->codec_tag = tag = avio_rl32(pb); | |
309 | 1 | st->codecpar->codec_id = ff_codec_get_id(dsd_codec_tags, tag); | |
310 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!st->codecpar->codec_id) { |
311 | ✗ | av_log(s, AV_LOG_ERROR, "'%s' compression is not supported\n", | |
312 | ✗ | av_fourcc2str(tag)); | |
313 | ✗ | return AVERROR_PATCHWELCOME; | |
314 | } | ||
315 | 1 | break; | |
316 | |||
317 | 1 | case MKTAG('F','S',' ',' '): | |
318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (size < 4) |
319 | ✗ | return AVERROR_INVALIDDATA; | |
320 | 1 | st->codecpar->sample_rate = avio_rb32(pb) / 8; | |
321 | 1 | break; | |
322 | |||
323 | ✗ | case MKTAG('I','D','3',' '): | |
324 | ✗ | ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); | |
325 | ✗ | if (id3v2_extra_meta) { | |
326 | ✗ | if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || | |
327 | ✗ | (ret = ff_id3v2_parse_chapters(s, id3v2_extra_meta)) < 0) { | |
328 | ✗ | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
329 | ✗ | return ret; | |
330 | } | ||
331 | ✗ | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
332 | } | ||
333 | |||
334 | ✗ | if (size < avio_tell(pb) - orig_pos) { | |
335 | ✗ | av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n"); | |
336 | ✗ | return AVERROR_INVALIDDATA; | |
337 | } | ||
338 | ✗ | break; | |
339 | |||
340 | ✗ | case MKTAG('L','S','C','O'): | |
341 | ✗ | if (size < 2) | |
342 | ✗ | return AVERROR_INVALIDDATA; | |
343 | ✗ | config = avio_rb16(pb); | |
344 | ✗ | if (config != 0xFFFF) { | |
345 | ✗ | if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config)) | |
346 | ✗ | st->codecpar->ch_layout = dsd_loudspeaker_config[config]; | |
347 | ✗ | if (!st->codecpar->ch_layout.nb_channels) | |
348 | ✗ | avpriv_request_sample(s, "loudspeaker configuration %d", config); | |
349 | } | ||
350 | ✗ | break; | |
351 | } | ||
352 | |||
353 | 3 | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
354 | } | ||
355 | |||
356 | 1 | return 0; | |
357 | } | ||
358 | |||
359 | 11 | static int read_dst_frame(AVFormatContext *s, AVPacket *pkt) | |
360 | { | ||
361 | 11 | IffDemuxContext *iff = s->priv_data; | |
362 | 11 | AVIOContext *pb = s->pb; | |
363 | uint32_t chunk_id; | ||
364 | uint64_t chunk_pos, data_pos, data_size; | ||
365 | 11 | int ret = AVERROR_EOF; | |
366 | |||
367 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | while (!avio_feof(pb)) { |
368 | 12 | chunk_pos = avio_tell(pb); | |
369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (chunk_pos >= iff->body_end) |
370 | ✗ | return AVERROR_EOF; | |
371 | |||
372 | 12 | chunk_id = avio_rl32(pb); | |
373 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); |
374 | 12 | data_pos = avio_tell(pb); | |
375 | |||
376 |
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) |
377 | ✗ | return AVERROR_INVALIDDATA; | |
378 | |||
379 |
2/3✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
12 | switch (chunk_id) { |
380 | 11 | case ID_DSTF: | |
381 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (!pkt) { |
382 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | iff->body_pos = avio_tell(pb) - (iff->is_64bit ? 12 : 8); |
383 | 1 | iff->body_size = iff->body_end - iff->body_pos; | |
384 | 1 | return 0; | |
385 | } | ||
386 | 10 | ret = av_get_packet(pb, pkt, data_size); | |
387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (ret < 0) |
388 | ✗ | return ret; | |
389 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | if (data_size & 1) |
390 | 4 | avio_skip(pb, 1); | |
391 | 10 | pkt->flags |= AV_PKT_FLAG_KEY; | |
392 | 10 | pkt->stream_index = iff->audio_stream_index; | |
393 | 10 | pkt->duration = s->streams[0]->codecpar->sample_rate / 75; | |
394 | 10 | pkt->pos = chunk_pos; | |
395 | |||
396 | 10 | chunk_pos = avio_tell(pb); | |
397 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (chunk_pos >= iff->body_end) |
398 | 1 | return 0; | |
399 | |||
400 | 9 | avio_seek(pb, chunk_pos, SEEK_SET); | |
401 | 9 | return 0; | |
402 | |||
403 | 1 | case ID_FRTE: | |
404 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
405 | ✗ | return AVERROR_INVALIDDATA; | |
406 | 1 | s->streams[0]->duration = avio_rb32(pb) * (uint64_t)s->streams[0]->codecpar->sample_rate / 75; | |
407 | |||
408 | 1 | break; | |
409 | } | ||
410 | |||
411 | 1 | avio_skip(pb, data_size - (avio_tell(pb) - data_pos) + (data_size & 1)); | |
412 | } | ||
413 | |||
414 | ✗ | return ret; | |
415 | } | ||
416 | |||
417 | static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | ||
418 | static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | ||
419 | static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8}; | ||
420 | static const uint8_t deep_argb[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 1, 0, 8, 0, 2, 0, 8}; | ||
421 | static const uint8_t deep_abgr[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 3, 0, 8, 0, 2, 0, 8}; | ||
422 | |||
423 | 4 | static AVStream * new_stream(AVFormatContext *s, AVStream **st_ptr, int *index_ptr, enum AVMediaType codec_type) | |
424 | { | ||
425 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (!*st_ptr) { |
426 | 4 | *st_ptr = avformat_new_stream(s, NULL); | |
427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!*st_ptr) |
428 | ✗ | return NULL; | |
429 | 4 | (*st_ptr)->codecpar->codec_type = codec_type; | |
430 | 4 | (*index_ptr) = (*st_ptr)->index; | |
431 | } | ||
432 | 4 | return *st_ptr; | |
433 | } | ||
434 | |||
435 | 4 | static int iff_read_header(AVFormatContext *s) | |
436 | { | ||
437 | 4 | IffDemuxContext *iff = s->priv_data; | |
438 | 4 | AVIOContext *pb = s->pb; | |
439 | 4 | AVStream *sta = NULL, *stv = NULL; | |
440 | uint8_t *buf; | ||
441 | uint32_t chunk_id; | ||
442 | uint64_t data_size; | ||
443 | 4 | uint32_t screenmode = 0, num, den; | |
444 | 4 | unsigned transparency = 0; | |
445 | 4 | unsigned masking = 0; // no mask | |
446 | uint8_t fmt[16]; | ||
447 | int fmt_size; | ||
448 | |||
449 | 4 | iff->audio_stream_index = -1; | |
450 | 4 | iff->video_stream_index = -1; | |
451 | 4 | iff->is_64bit = avio_rl32(pb) == ID_FRM8; | |
452 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | avio_skip(pb, iff->is_64bit ? 8 : 4); |
453 | 4 | iff->form_tag = avio_rl32(pb); | |
454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (iff->form_tag == ID_ANIM) { |
455 | ✗ | avio_skip(pb, 12); | |
456 | } | ||
457 | 4 | iff->bitmap_compression = -1; | |
458 | 4 | iff->svx8_compression = -1; | |
459 | 4 | iff->maud_bits = -1; | |
460 | 4 | iff->maud_compression = -1; | |
461 | |||
462 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 4 times.
|
41 | while(!avio_feof(pb)) { |
463 | uint64_t orig_pos; | ||
464 | int res; | ||
465 | 37 | const char *metadata_tag = NULL; | |
466 | int version, nb_comments, i; | ||
467 | 37 | chunk_id = avio_rl32(pb); | |
468 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
|
37 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); |
469 | 37 | orig_pos = avio_tell(pb); | |
470 | |||
471 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (data_size >= INT64_MAX) |
472 | ✗ | return AVERROR_INVALIDDATA; | |
473 | |||
474 |
10/23✓ 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 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 23 times.
|
37 | switch(chunk_id) { |
475 | 1 | case ID_VHDR: | |
476 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 14) |
477 | ✗ | return AVERROR_INVALIDDATA; | |
478 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!new_stream(s, &sta, &iff->audio_stream_index, AVMEDIA_TYPE_AUDIO)) |
479 | ✗ | return AVERROR(ENOMEM); | |
480 | 1 | avio_skip(pb, 12); | |
481 | 1 | sta->codecpar->sample_rate = avio_rb16(pb); | |
482 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (data_size >= 16) { |
483 | 1 | avio_skip(pb, 1); | |
484 | 1 | iff->svx8_compression = avio_r8(pb); | |
485 | } | ||
486 | 1 | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
487 | 14 | break; | |
488 | |||
489 | ✗ | case ID_MHDR: | |
490 | ✗ | if (data_size < 32) | |
491 | ✗ | return AVERROR_INVALIDDATA; | |
492 | ✗ | if (!new_stream(s, &sta, &iff->audio_stream_index, AVMEDIA_TYPE_AUDIO)) | |
493 | ✗ | return AVERROR(ENOMEM); | |
494 | ✗ | avio_skip(pb, 4); | |
495 | ✗ | iff->maud_bits = avio_rb16(pb); | |
496 | ✗ | avio_skip(pb, 2); | |
497 | ✗ | num = avio_rb32(pb); | |
498 | ✗ | den = avio_rb16(pb); | |
499 | ✗ | if (!den) | |
500 | ✗ | return AVERROR_INVALIDDATA; | |
501 | ✗ | avio_skip(pb, 2); | |
502 | ✗ | sta->codecpar->sample_rate = num / den; | |
503 | ✗ | sta->codecpar->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
504 | ✗ | sta->codecpar->ch_layout.nb_channels = avio_rb16(pb); | |
505 | ✗ | iff->maud_compression = avio_rb16(pb); | |
506 | ✗ | if (sta->codecpar->ch_layout.nb_channels == 1) | |
507 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
508 | ✗ | else if (sta->codecpar->ch_layout.nb_channels == 2) | |
509 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
510 | ✗ | break; | |
511 | |||
512 | 4 | case ID_ABIT: | |
513 | case ID_BODY: | ||
514 | case ID_DBOD: | ||
515 | case ID_DSD: | ||
516 | case ID_DST: | ||
517 | case ID_MDAT: | ||
518 | 4 | iff->body_pos = avio_tell(pb); | |
519 |
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) |
520 | ✗ | return AVERROR_INVALIDDATA; | |
521 | |||
522 | 4 | iff->body_end = iff->body_pos + data_size; | |
523 | 4 | iff->body_size = data_size; | |
524 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (chunk_id == ID_DST) { |
525 | 1 | int ret = read_dst_frame(s, NULL); | |
526 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
527 | ✗ | return ret; | |
528 | } | ||
529 | 4 | break; | |
530 | |||
531 | ✗ | case ID_CHAN: | |
532 | ✗ | if (data_size < 4) | |
533 | ✗ | return AVERROR_INVALIDDATA; | |
534 | ✗ | if (!sta) | |
535 | ✗ | return AVERROR_INVALIDDATA; | |
536 | ✗ | if (avio_rb32(pb) < 6) { | |
537 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
538 | } else { | ||
539 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
540 | } | ||
541 | ✗ | break; | |
542 | |||
543 | 1 | case ID_CAMG: | |
544 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
545 | ✗ | return AVERROR_INVALIDDATA; | |
546 | 1 | screenmode = avio_rb32(pb); | |
547 | 1 | break; | |
548 | |||
549 | 2 | case ID_CMAP: | |
550 |
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) { |
551 | ✗ | av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n", | |
552 | data_size); | ||
553 | ✗ | return AVERROR_INVALIDDATA; | |
554 | } | ||
555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!stv) |
556 | ✗ | return AVERROR_INVALIDDATA; | |
557 | 2 | res = ff_alloc_extradata(stv->codecpar, | |
558 | 2 | data_size + IFF_EXTRA_VIDEO_SIZE); | |
559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (res < 0) |
560 | ✗ | return res; | |
561 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (avio_read(pb, stv->codecpar->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) { |
562 | ✗ | av_freep(&stv->codecpar->extradata); | |
563 | ✗ | stv->codecpar->extradata_size = 0; | |
564 | ✗ | return AVERROR(EIO); | |
565 | } | ||
566 | 2 | break; | |
567 | |||
568 | 2 | case ID_BMHD: | |
569 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (data_size <= 8) |
570 | ✗ | return AVERROR_INVALIDDATA; | |
571 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (!new_stream(s, &stv, &iff->video_stream_index, AVMEDIA_TYPE_VIDEO)) |
572 | ✗ | return AVERROR(ENOMEM); | |
573 | 2 | stv->codecpar->width = avio_rb16(pb); | |
574 | 2 | stv->codecpar->height = avio_rb16(pb); | |
575 | 2 | avio_skip(pb, 4); // x, y offset | |
576 | 2 | stv->codecpar->bits_per_coded_sample = avio_r8(pb); | |
577 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 10) |
578 | 2 | masking = avio_r8(pb); | |
579 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 11) |
580 | 2 | iff->bitmap_compression = avio_r8(pb); | |
581 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 14) { |
582 | 2 | avio_skip(pb, 1); // padding | |
583 | 2 | transparency = avio_rb16(pb); | |
584 | } | ||
585 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (data_size >= 16) { |
586 | 2 | stv->sample_aspect_ratio.num = avio_r8(pb); | |
587 | 2 | stv->sample_aspect_ratio.den = avio_r8(pb); | |
588 | } | ||
589 | 2 | break; | |
590 | |||
591 | ✗ | case ID_ANHD: | |
592 | ✗ | break; | |
593 | |||
594 | ✗ | case ID_DPAN: | |
595 | ✗ | if (!stv) | |
596 | ✗ | return AVERROR_INVALIDDATA; | |
597 | ✗ | avio_skip(pb, 2); | |
598 | ✗ | stv->duration = avio_rb16(pb); | |
599 | ✗ | break; | |
600 | |||
601 | ✗ | case ID_DPEL: | |
602 | ✗ | if (data_size < 4 || (data_size & 3)) | |
603 | ✗ | return AVERROR_INVALIDDATA; | |
604 | ✗ | if (!stv) | |
605 | ✗ | return AVERROR_INVALIDDATA; | |
606 | ✗ | if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0) | |
607 | ✗ | return fmt_size; | |
608 | ✗ | if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24))) | |
609 | ✗ | stv->codecpar->format = AV_PIX_FMT_RGB24; | |
610 | ✗ | else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba))) | |
611 | ✗ | stv->codecpar->format = AV_PIX_FMT_RGBA; | |
612 | ✗ | else if (fmt_size == sizeof(deep_bgra) && !memcmp(fmt, deep_bgra, sizeof(deep_bgra))) | |
613 | ✗ | stv->codecpar->format = AV_PIX_FMT_BGRA; | |
614 | ✗ | else if (fmt_size == sizeof(deep_argb) && !memcmp(fmt, deep_argb, sizeof(deep_argb))) | |
615 | ✗ | stv->codecpar->format = AV_PIX_FMT_ARGB; | |
616 | ✗ | else if (fmt_size == sizeof(deep_abgr) && !memcmp(fmt, deep_abgr, sizeof(deep_abgr))) | |
617 | ✗ | stv->codecpar->format = AV_PIX_FMT_ABGR; | |
618 | else { | ||
619 | ✗ | avpriv_request_sample(s, "color format %.16s", fmt); | |
620 | ✗ | return AVERROR_PATCHWELCOME; | |
621 | } | ||
622 | ✗ | break; | |
623 | |||
624 | ✗ | case ID_DGBL: | |
625 | ✗ | if (data_size < 8) | |
626 | ✗ | return AVERROR_INVALIDDATA; | |
627 | ✗ | if (!new_stream(s, &stv, &iff->video_stream_index, AVMEDIA_TYPE_VIDEO)) | |
628 | ✗ | return AVERROR(ENOMEM); | |
629 | ✗ | stv->codecpar->width = avio_rb16(pb); | |
630 | ✗ | stv->codecpar->height = avio_rb16(pb); | |
631 | ✗ | iff->bitmap_compression = avio_rb16(pb); | |
632 | ✗ | stv->sample_aspect_ratio.num = avio_r8(pb); | |
633 | ✗ | stv->sample_aspect_ratio.den = avio_r8(pb); | |
634 | ✗ | stv->codecpar->bits_per_coded_sample = 24; | |
635 | ✗ | break; | |
636 | |||
637 | ✗ | case ID_DLOC: | |
638 | ✗ | if (data_size < 4) | |
639 | ✗ | return AVERROR_INVALIDDATA; | |
640 | ✗ | if (!new_stream(s, &stv, &iff->video_stream_index, AVMEDIA_TYPE_VIDEO)) | |
641 | ✗ | return AVERROR(ENOMEM); | |
642 | ✗ | stv->codecpar->width = avio_rb16(pb); | |
643 | ✗ | stv->codecpar->height = avio_rb16(pb); | |
644 | ✗ | break; | |
645 | |||
646 | ✗ | case ID_TVDC: | |
647 | ✗ | if (data_size < sizeof(iff->tvdc)) | |
648 | ✗ | return AVERROR_INVALIDDATA; | |
649 | ✗ | res = avio_read(pb, iff->tvdc, sizeof(iff->tvdc)); | |
650 | ✗ | if (res < 0) | |
651 | ✗ | return res; | |
652 | ✗ | break; | |
653 | |||
654 | ✗ | case MKTAG('S','X','H','D'): | |
655 | ✗ | if (data_size < 22) | |
656 | ✗ | return AVERROR_INVALIDDATA; | |
657 | ✗ | if (!new_stream(s, &sta, &iff->audio_stream_index, AVMEDIA_TYPE_AUDIO)) | |
658 | ✗ | return AVERROR(ENOMEM); | |
659 | ✗ | sta->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
660 | ✗ | switch(avio_r8(pb)) { | |
661 | ✗ | case 8: | |
662 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; | |
663 | ✗ | break; | |
664 | ✗ | default: | |
665 | ✗ | avpriv_request_sample(s, "sound bitdepth"); | |
666 | ✗ | return AVERROR_INVALIDDATA; | |
667 | } | ||
668 | ✗ | avio_skip(pb, 9); | |
669 | ✗ | if (avio_rb32(pb)) { | |
670 | ✗ | avpriv_request_sample(s, "sound compression"); | |
671 | ✗ | return AVERROR_INVALIDDATA; | |
672 | } | ||
673 | ✗ | avio_skip(pb, 1); | |
674 | ✗ | sta->codecpar->ch_layout.nb_channels = avio_r8(pb); | |
675 | ✗ | if (!sta->codecpar->ch_layout.nb_channels) | |
676 | ✗ | return AVERROR_INVALIDDATA; | |
677 | ✗ | if (sta->codecpar->ch_layout.nb_channels == 1) | |
678 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; | |
679 | ✗ | else if (sta->codecpar->ch_layout.nb_channels == 2) | |
680 | ✗ | sta->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; | |
681 | ✗ | sta->codecpar->sample_rate = avio_rb32(pb); | |
682 | ✗ | avpriv_set_pts_info(sta, 64, 1, sta->codecpar->sample_rate); | |
683 | ✗ | avio_skip(pb, 2); | |
684 | ✗ | break; | |
685 | |||
686 | 1 | case ID_ANNO: | |
687 | 1 | case ID_TEXT: metadata_tag = "comment"; break; | |
688 | ✗ | case ID_AUTH: metadata_tag = "artist"; break; | |
689 | ✗ | case ID_COPYRIGHT: metadata_tag = "copyright"; break; | |
690 | 1 | case ID_NAME: metadata_tag = "title"; break; | |
691 | |||
692 | /* DSD tags */ | ||
693 | |||
694 | 1 | case MKTAG('F','V','E','R'): | |
695 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if (iff->form_tag == ID_DSD || iff->form_tag == ID_DST) { |
696 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
697 | ✗ | return AVERROR_INVALIDDATA; | |
698 | 1 | version = avio_rb32(pb); | |
699 | 1 | av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF); | |
700 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (!new_stream(s, &sta, &iff->audio_stream_index, AVMEDIA_TYPE_AUDIO)) |
701 | ✗ | return AVERROR(ENOMEM); | |
702 | 1 | sta->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; | |
703 | } | ||
704 | 1 | break; | |
705 | |||
706 | ✗ | case MKTAG('D','I','I','N'): | |
707 | ✗ | if (!sta) | |
708 | ✗ | return AVERROR_INVALIDDATA; | |
709 | ✗ | res = parse_dsd_diin(s, sta, orig_pos + data_size); | |
710 | ✗ | if (res < 0) | |
711 | ✗ | return res; | |
712 | ✗ | break; | |
713 | |||
714 | 1 | case MKTAG('P','R','O','P'): | |
715 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (data_size < 4) |
716 | ✗ | return AVERROR_INVALIDDATA; | |
717 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if (avio_rl32(pb) != MKTAG('S','N','D',' ')) { |
718 | ✗ | avpriv_request_sample(s, "unknown property type"); | |
719 | ✗ | break; | |
720 | } | ||
721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!sta) |
722 | ✗ | return AVERROR_INVALIDDATA; | |
723 | 1 | res = parse_dsd_prop(s, sta, orig_pos + data_size); | |
724 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (res < 0) |
725 | ✗ | return res; | |
726 | 1 | break; | |
727 | |||
728 | ✗ | case MKTAG('C','O','M','T'): | |
729 | ✗ | if (data_size < 2) | |
730 | ✗ | return AVERROR_INVALIDDATA; | |
731 | ✗ | if (!sta) | |
732 | ✗ | return AVERROR_INVALIDDATA; | |
733 | ✗ | nb_comments = avio_rb16(pb); | |
734 | ✗ | for (i = 0; i < nb_comments; i++) { | |
735 | int year, mon, day, hour, min, type, ref; | ||
736 | char tmp[24]; | ||
737 | const char *tag; | ||
738 | int metadata_size; | ||
739 | |||
740 | ✗ | year = avio_rb16(pb); | |
741 | ✗ | mon = avio_r8(pb); | |
742 | ✗ | day = avio_r8(pb); | |
743 | ✗ | hour = avio_r8(pb); | |
744 | ✗ | min = avio_r8(pb); | |
745 | ✗ | snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min); | |
746 | ✗ | av_dict_set(&sta->metadata, "comment_time", tmp, 0); | |
747 | |||
748 | ✗ | type = avio_rb16(pb); | |
749 | ✗ | ref = avio_rb16(pb); | |
750 | ✗ | switch (type) { | |
751 | ✗ | case 1: | |
752 | ✗ | if (!i) | |
753 | ✗ | tag = "channel_comment"; | |
754 | else { | ||
755 | ✗ | snprintf(tmp, sizeof(tmp), "channel%d_comment", ref); | |
756 | ✗ | tag = tmp; | |
757 | } | ||
758 | ✗ | break; | |
759 | ✗ | case 2: | |
760 | ✗ | tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_source_comment[ref] : "source_comment"; | |
761 | ✗ | break; | |
762 | ✗ | case 3: | |
763 | ✗ | tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history"; | |
764 | ✗ | break; | |
765 | ✗ | default: | |
766 | ✗ | tag = "comment"; | |
767 | } | ||
768 | |||
769 | ✗ | metadata_size = avio_rb32(pb); | |
770 | ✗ | if ((res = get_metadata(s, tag, metadata_size)) < 0) { | |
771 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag); | |
772 | ✗ | return res; | |
773 | } | ||
774 | |||
775 | ✗ | if (metadata_size & 1) | |
776 | ✗ | avio_skip(pb, 1); | |
777 | } | ||
778 | ✗ | break; | |
779 | } | ||
780 | |||
781 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 35 times.
|
37 | if (metadata_tag) { |
782 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if ((res = get_metadata(s, metadata_tag, data_size)) < 0) { |
783 | ✗ | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
784 | ✗ | return res; | |
785 | } | ||
786 | } | ||
787 | 37 | avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); | |
788 | } | ||
789 | |||
790 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | if ((!sta && !stv) || |
791 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
4 | (iff->form_tag == ID_ANIM && !stv) || |
792 |
4/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
4 | (iff->form_tag != ID_ANIM && sta && stv)) |
793 | ✗ | return AVERROR_INVALIDDATA; | |
794 | |||
795 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (iff->form_tag == ID_ANIM) |
796 | ✗ | avio_seek(pb, 12, SEEK_SET); | |
797 | else | ||
798 | 4 | avio_seek(pb, iff->body_pos, SEEK_SET); | |
799 | |||
800 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (sta) { |
801 | 2 | avpriv_set_pts_info(sta, 32, 1, sta->codecpar->sample_rate); | |
802 | |||
803 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (sta->codecpar->codec_id != AV_CODEC_ID_NONE) { |
804 | /* codec_id already set by PROP or SXHD chunk */ | ||
805 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (iff->form_tag == ID_16SV) |
806 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR; | |
807 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | else if (iff->form_tag == ID_MAUD) { |
808 | ✗ | if (iff->maud_bits == 8 && !iff->maud_compression) { | |
809 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_U8; | |
810 | ✗ | } else if (iff->maud_bits == 16 && !iff->maud_compression) { | |
811 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE; | |
812 | ✗ | } else if (iff->maud_bits == 8 && iff->maud_compression == 2) { | |
813 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; | |
814 | ✗ | } else if (iff->maud_bits == 8 && iff->maud_compression == 3) { | |
815 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; | |
816 | } else { | ||
817 | ✗ | avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits); | |
818 | ✗ | return AVERROR_PATCHWELCOME; | |
819 | } | ||
820 | } else { | ||
821 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | switch (iff->svx8_compression) { |
822 | ✗ | case COMP_NONE: | |
823 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; | |
824 | ✗ | break; | |
825 | 1 | case COMP_FIB: | |
826 | 1 | sta->codecpar->codec_id = AV_CODEC_ID_8SVX_FIB; | |
827 | 1 | break; | |
828 | ✗ | case COMP_EXP: | |
829 | ✗ | sta->codecpar->codec_id = AV_CODEC_ID_8SVX_EXP; | |
830 | ✗ | break; | |
831 | ✗ | default: | |
832 | ✗ | av_log(s, AV_LOG_ERROR, | |
833 | ✗ | "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); | |
834 | ✗ | return -1; | |
835 | } | ||
836 | } | ||
837 | |||
838 | 2 | sta->codecpar->bits_per_coded_sample = av_get_bits_per_sample(sta->codecpar->codec_id); | |
839 | 2 | sta->codecpar->bit_rate = (int64_t)sta->codecpar->ch_layout.nb_channels * | |
840 | 2 | sta->codecpar->sample_rate * | |
841 | 2 | sta->codecpar->bits_per_coded_sample; | |
842 | 2 | sta->codecpar->block_align = sta->codecpar->ch_layout.nb_channels * | |
843 | 2 | sta->codecpar->bits_per_coded_sample; | |
844 |
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 ((sta->codecpar->codec_tag == ID_DSD || iff->form_tag == ID_MAUD) && sta->codecpar->block_align <= 0) |
845 | ✗ | return AVERROR_INVALIDDATA; | |
846 | } | ||
847 | |||
848 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (stv) { |
849 | 2 | iff->bpp = stv->codecpar->bits_per_coded_sample; | |
850 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (iff->form_tag == ID_ANIM) |
851 | ✗ | avpriv_set_pts_info(stv, 32, 1, 60); | |
852 |
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) { |
853 | ✗ | iff->ham = iff->bpp > 6 ? 6 : 4; | |
854 | ✗ | stv->codecpar->bits_per_coded_sample = 24; | |
855 | } | ||
856 |
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; |
857 | 2 | iff->masking = masking; | |
858 | 2 | iff->transparency = transparency; | |
859 | |||
860 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!stv->codecpar->extradata) { |
861 | ✗ | int ret = ff_alloc_extradata(stv->codecpar, IFF_EXTRA_VIDEO_SIZE); | |
862 | ✗ | if (ret < 0) | |
863 | ✗ | return ret; | |
864 | } | ||
865 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | av_assert0(stv->codecpar->extradata_size >= IFF_EXTRA_VIDEO_SIZE); |
866 | 2 | buf = stv->codecpar->extradata; | |
867 | 2 | bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE); | |
868 | 2 | bytestream_put_byte(&buf, iff->bitmap_compression); | |
869 | 2 | bytestream_put_byte(&buf, iff->bpp); | |
870 | 2 | bytestream_put_byte(&buf, iff->ham); | |
871 | 2 | bytestream_put_byte(&buf, iff->flags); | |
872 | 2 | bytestream_put_be16(&buf, iff->transparency); | |
873 | 2 | bytestream_put_byte(&buf, iff->masking); | |
874 | 2 | bytestream_put_buffer(&buf, iff->tvdc, sizeof(iff->tvdc)); | |
875 | 2 | stv->codecpar->codec_id = AV_CODEC_ID_IFF_ILBM; | |
876 | 2 | stv->codecpar->codec_tag = iff->form_tag; // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content | |
877 | } | ||
878 | |||
879 | 4 | return 0; | |
880 | } | ||
881 | |||
882 | ✗ | static unsigned get_anim_duration(uint8_t *buf, int size) | |
883 | { | ||
884 | GetByteContext gb; | ||
885 | |||
886 | ✗ | bytestream2_init(&gb, buf, size); | |
887 | ✗ | bytestream2_skip(&gb, 4); | |
888 | ✗ | while (bytestream2_get_bytes_left(&gb) > 8) { | |
889 | ✗ | unsigned chunk = bytestream2_get_le32(&gb); | |
890 | ✗ | unsigned size = bytestream2_get_be32(&gb); | |
891 | |||
892 | ✗ | if (chunk == ID_ANHD) { | |
893 | ✗ | if (size < 40) | |
894 | ✗ | break; | |
895 | ✗ | bytestream2_skip(&gb, 14); | |
896 | ✗ | return bytestream2_get_be32(&gb); | |
897 | } else { | ||
898 | ✗ | bytestream2_skip(&gb, size + size & 1); | |
899 | } | ||
900 | } | ||
901 | ✗ | return 10; | |
902 | } | ||
903 | |||
904 | ✗ | static int64_t get_sbdy_offset(uint8_t *buf, int size) | |
905 | { | ||
906 | GetByteContext gb; | ||
907 | |||
908 | ✗ | bytestream2_init(&gb, buf, size); | |
909 | ✗ | bytestream2_skip(&gb, 4); | |
910 | ✗ | while (bytestream2_get_bytes_left(&gb) > 8) { | |
911 | ✗ | unsigned chunk = bytestream2_get_le32(&gb); | |
912 | ✗ | unsigned size = bytestream2_get_be32(&gb); | |
913 | |||
914 | ✗ | if (chunk == MKTAG('S','B','D','Y')) | |
915 | ✗ | return bytestream2_tell(&gb); | |
916 | |||
917 | ✗ | bytestream2_skip(&gb, size + size & 1); | |
918 | } | ||
919 | |||
920 | ✗ | return 0; | |
921 | } | ||
922 | |||
923 | 21 | static int iff_read_packet(AVFormatContext *s, | |
924 | AVPacket *pkt) | ||
925 | { | ||
926 | 21 | IffDemuxContext *iff = s->priv_data; | |
927 | 21 | AVIOContext *pb = s->pb; | |
928 | int ret; | ||
929 | 21 | int64_t pos = avio_tell(pb); | |
930 | |||
931 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | if (avio_feof(pb)) |
932 | ✗ | return AVERROR_EOF; | |
933 |
3/4✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 13 times.
|
21 | if (iff->form_tag != ID_ANIM && pos >= iff->body_end) |
934 | 8 | return AVERROR_EOF; | |
935 | |||
936 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (iff->sbdy_pos) { |
937 | int64_t data_size; | ||
938 | ✗ | avio_seek(pb, iff->sbdy_pos, SEEK_SET); | |
939 | ✗ | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); | |
940 | ✗ | ret = av_get_packet(pb, pkt, data_size); | |
941 | ✗ | pkt->stream_index = iff->audio_stream_index; | |
942 | ✗ | pkt->duration = data_size / s->streams[iff->audio_stream_index]->codecpar->ch_layout.nb_channels; | |
943 | ✗ | pkt->pos = INT_MAX; /* not seekable */ | |
944 | |||
945 | ✗ | iff->sbdy_pos = 0; | |
946 | ✗ | avio_seek(pb, iff->resume_pos, SEEK_SET); | |
947 | ✗ | return ret; | |
948 | } | ||
949 | |||
950 |
3/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
13 | if (iff->audio_stream_index >= 0 && iff->video_stream_index < 0) { /* audio only */ |
951 | 11 | AVStream *sta = s->streams[iff->audio_stream_index]; | |
952 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (sta->codecpar->codec_tag == ID_DSD || iff->form_tag == ID_MAUD) { |
953 | ✗ | ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * sta->codecpar->block_align)); | |
954 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
|
11 | } else if (sta->codecpar->codec_tag == ID_DST) { |
955 | 10 | return read_dst_frame(s, pkt); | |
956 | } else { | ||
957 |
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) |
958 | ✗ | return AVERROR_INVALIDDATA; | |
959 | 1 | ret = av_get_packet(pb, pkt, iff->body_size); | |
960 | } | ||
961 | 1 | pkt->stream_index = iff->audio_stream_index; | |
962 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | } else if (iff->form_tag == ID_ANIM) { |
963 | uint64_t data_size, orig_pos; | ||
964 | uint32_t chunk_id, chunk_id2; | ||
965 | |||
966 | ✗ | while (!avio_feof(pb)) { | |
967 | ✗ | if (avio_feof(pb)) | |
968 | ✗ | return AVERROR_EOF; | |
969 | |||
970 | ✗ | orig_pos = avio_tell(pb); | |
971 | ✗ | chunk_id = avio_rl32(pb); | |
972 | ✗ | data_size = avio_rb32(pb); | |
973 | ✗ | chunk_id2 = avio_rl32(pb); | |
974 | |||
975 | ✗ | if (chunk_id == ID_FORM && | |
976 | chunk_id2 == ID_ILBM) { | ||
977 | ✗ | avio_skip(pb, -4); | |
978 | ✗ | break; | |
979 | ✗ | } else if (chunk_id == ID_FORM && | |
980 | chunk_id2 == ID_ANIM) { | ||
981 | ✗ | continue; | |
982 | } else { | ||
983 | ✗ | avio_skip(pb, data_size); | |
984 | } | ||
985 | } | ||
986 | ✗ | ret = av_get_packet(pb, pkt, data_size); | |
987 | ✗ | pkt->stream_index = iff->video_stream_index; | |
988 | ✗ | pkt->pos = orig_pos; | |
989 | ✗ | pkt->duration = get_anim_duration(pkt->data, pkt->size); | |
990 | ✗ | if (pos == 12) | |
991 | ✗ | pkt->flags |= AV_PKT_FLAG_KEY; | |
992 | |||
993 | ✗ | if (iff->audio_stream_index >= 0) { | |
994 | ✗ | iff->sbdy_pos = get_sbdy_offset(pkt->data, pkt->size); | |
995 | ✗ | if (iff->sbdy_pos) { | |
996 | ✗ | iff->sbdy_pos += orig_pos + 4; | |
997 | ✗ | iff->resume_pos = avio_tell(pb); | |
998 | } | ||
999 | } | ||
1000 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | } else if (iff->video_stream_index >= 0 && iff->audio_stream_index < 0) { /* video only */ |
1001 |
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) |
1002 | ✗ | return AVERROR_INVALIDDATA; | |
1003 | 2 | ret = av_get_packet(pb, pkt, iff->body_size); | |
1004 | 2 | pkt->stream_index = iff->video_stream_index; | |
1005 | 2 | pkt->pos = pos; | |
1006 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (pos == iff->body_pos) |
1007 | 2 | pkt->flags |= AV_PKT_FLAG_KEY; | |
1008 | } else { | ||
1009 | ✗ | av_assert0(0); | |
1010 | } | ||
1011 | |||
1012 | 3 | return ret; | |
1013 | } | ||
1014 | |||
1015 | const FFInputFormat ff_iff_demuxer = { | ||
1016 | .p.name = "iff", | ||
1017 | .p.long_name = NULL_IF_CONFIG_SMALL("IFF (Interchange File Format)"), | ||
1018 | .p.flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, | ||
1019 | .priv_data_size = sizeof(IffDemuxContext), | ||
1020 | .read_probe = iff_probe, | ||
1021 | .read_header = iff_read_header, | ||
1022 | .read_packet = iff_read_packet, | ||
1023 | }; | ||
1024 |