Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 "libavcodec/bytestream.h" | |
38 | #include "avformat.h" | |
39 | #include "id3v2.h" | |
40 | #include "internal.h" | |
41 | ||
42 | #define ID_8SVX MKTAG('8','S','V','X') | |
43 | #define ID_16SV MKTAG('1','6','S','V') | |
44 | #define ID_MAUD MKTAG('M','A','U','D') | |
45 | #define ID_MHDR MKTAG('M','H','D','R') | |
46 | #define ID_MDAT MKTAG('M','D','A','T') | |
47 | #define ID_VHDR MKTAG('V','H','D','R') | |
48 | #define ID_ATAK MKTAG('A','T','A','K') | |
49 | #define ID_RLSE MKTAG('R','L','S','E') | |
50 | #define ID_CHAN MKTAG('C','H','A','N') | |
51 | #define ID_PBM MKTAG('P','B','M',' ') | |
52 | #define ID_ILBM MKTAG('I','L','B','M') | |
53 | #define ID_BMHD MKTAG('B','M','H','D') | |
54 | #define ID_DGBL MKTAG('D','G','B','L') | |
55 | #define ID_CAMG MKTAG('C','A','M','G') | |
56 | #define ID_CMAP MKTAG('C','M','A','P') | |
57 | #define ID_ACBM MKTAG('A','C','B','M') | |
58 | #define ID_DEEP MKTAG('D','E','E','P') | |
59 | #define ID_RGB8 MKTAG('R','G','B','8') | |
60 | #define ID_RGBN MKTAG('R','G','B','N') | |
61 | #define ID_DSD MKTAG('D','S','D',' ') | |
62 | #define ID_ANIM MKTAG('A','N','I','M') | |
63 | ||
64 | #define ID_FORM MKTAG('F','O','R','M') | |
65 | #define ID_FRM8 MKTAG('F','R','M','8') | |
66 | #define ID_ANNO MKTAG('A','N','N','O') | |
67 | #define ID_AUTH MKTAG('A','U','T','H') | |
68 | #define ID_CHRS MKTAG('C','H','R','S') | |
69 | #define ID_COPYRIGHT MKTAG('(','c',')',' ') | |
70 | #define ID_CSET MKTAG('C','S','E','T') | |
71 | #define ID_FVER MKTAG('F','V','E','R') | |
72 | #define ID_NAME MKTAG('N','A','M','E') | |
73 | #define ID_TEXT MKTAG('T','E','X','T') | |
74 | #define ID_ABIT MKTAG('A','B','I','T') | |
75 | #define ID_BODY MKTAG('B','O','D','Y') | |
76 | #define ID_DBOD MKTAG('D','B','O','D') | |
77 | #define ID_DPEL MKTAG('D','P','E','L') | |
78 | #define ID_DLOC MKTAG('D','L','O','C') | |
79 | #define ID_TVDC MKTAG('T','V','D','C') | |
80 | ||
81 | #define LEFT 2 | |
82 | #define RIGHT 4 | |
83 | #define STEREO 6 | |
84 | ||
85 | /** | |
86 | * This number of bytes if added at the beginning of each AVPacket | |
87 | * which contain additional information about video properties | |
88 | * which has to be shared between demuxer and decoder. | |
89 | * This number may change between frames, e.g. the demuxer might | |
90 | * set it to smallest possible size of 2 to indicate that there's | |
91 | * no extradata changing in this frame. | |
92 | */ | |
93 | #define IFF_EXTRA_VIDEO_SIZE 41 | |
94 | ||
95 | typedef enum { | |
96 | COMP_NONE, | |
97 | COMP_FIB, | |
98 | COMP_EXP | |
99 | } svx8_compression_type; | |
100 | ||
101 | typedef struct { | |
102 | int is_64bit; ///< chunk size is 64-bit | |
103 | int64_t body_pos; | |
104 | int64_t body_end; | |
105 | uint32_t body_size; | |
106 | svx8_compression_type svx8_compression; | |
107 | unsigned maud_bits; | |
108 | unsigned maud_compression; | |
109 | unsigned bitmap_compression; ///< delta compression method used | |
110 | unsigned bpp; ///< bits per plane to decode (differs from bits_per_coded_sample if HAM) | |
111 | unsigned ham; ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise) | |
112 | unsigned flags; ///< 1 for EHB, 0 is no extra half darkening | |
113 | unsigned transparency; ///< transparency color index in palette | |
114 | unsigned masking; ///< masking method used | |
115 | uint8_t tvdc[32]; ///< TVDC lookup table | |
116 | } IffDemuxContext; | |
117 | ||
118 | /* Metadata string read */ | |
119 | static int get_metadata(AVFormatContext *s, | |
120 | const char *const tag, | |
121 | const unsigned data_size) | |
122 | { | |
123 | uint8_t *buf = ((data_size + 1) == 0) ? NULL : av_malloc(data_size + 1); | |
124 | ||
125 | if (!buf) | |
126 | return AVERROR(ENOMEM); | |
127 | ||
128 | if (avio_read(s->pb, buf, data_size) != data_size) { | |
129 | av_free(buf); | |
130 | return AVERROR(EIO); | |
131 | } | |
132 | buf[data_size] = 0; | |
133 | av_dict_set(&s->metadata, tag, buf, AV_DICT_DONT_STRDUP_VAL); | |
134 | return 0; | |
135 | } | |
136 | ||
137 | static int iff_probe(AVProbeData *p) | |
138 | { | |
139 | const uint8_t *d = p->buf; | |
140 | ||
141 | if ( (AV_RL32(d) == ID_FORM && | |
142 | (AV_RL32(d+8) == ID_8SVX || | |
143 | AV_RL32(d+8) == ID_16SV || | |
144 | AV_RL32(d+8) == ID_MAUD || | |
145 | AV_RL32(d+8) == ID_PBM || | |
146 | AV_RL32(d+8) == ID_ACBM || | |
147 | AV_RL32(d+8) == ID_DEEP || | |
148 | AV_RL32(d+8) == ID_ILBM || | |
149 | AV_RL32(d+8) == ID_RGB8 || | |
150 | AV_RL32(d+8) == ID_RGB8 || | |
151 | AV_RL32(d+8) == ID_ANIM || | |
152 | AV_RL32(d+8) == ID_RGBN)) || | |
153 | (AV_RL32(d) == ID_FRM8 && AV_RL32(d+12) == ID_DSD)) | |
154 | return AVPROBE_SCORE_MAX; | |
155 | return 0; | |
156 | } | |
157 | ||
158 | static const AVCodecTag dsd_codec_tags[] = { | |
159 | { AV_CODEC_ID_DSD_MSBF, ID_DSD }, | |
160 | { AV_CODEC_ID_NONE, 0 }, | |
161 | }; | |
162 | ||
163 | ||
164 | #define DSD_SLFT MKTAG('S','L','F','T') | |
165 | #define DSD_SRGT MKTAG('S','R','G','T') | |
166 | #define DSD_MLFT MKTAG('M','L','F','T') | |
167 | #define DSD_MRGT MKTAG('M','R','G','T') | |
168 | #define DSD_C MKTAG('C',' ',' ',' ') | |
169 | #define DSD_LS MKTAG('L','S',' ',' ') | |
170 | #define DSD_RS MKTAG('R','S',' ',' ') | |
171 | #define DSD_LFE MKTAG('L','F','E',' ') | |
172 | ||
173 | static const uint32_t dsd_stereo[] = { DSD_SLFT, DSD_SRGT }; | |
174 | static const uint32_t dsd_5point0[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LS, DSD_RS }; | |
175 | static const uint32_t dsd_5point1[] = { DSD_MLFT, DSD_MRGT, DSD_C, DSD_LFE, DSD_LS, DSD_RS }; | |
176 | ||
177 | typedef struct { | |
178 | uint64_t layout; | |
179 | const uint32_t * dsd_layout; | |
180 | } DSDLayoutDesc; | |
181 | ||
182 | static const DSDLayoutDesc dsd_channel_layout[] = { | |
183 | { AV_CH_LAYOUT_STEREO, dsd_stereo }, | |
184 | { AV_CH_LAYOUT_5POINT0, dsd_5point0 }, | |
185 | { AV_CH_LAYOUT_5POINT1, dsd_5point1 }, | |
186 | }; | |
187 | ||
188 | static const uint64_t dsd_loudspeaker_config[] = { | |
189 | AV_CH_LAYOUT_STEREO, | |
190 | 0, 0, | |
191 | AV_CH_LAYOUT_5POINT0, AV_CH_LAYOUT_5POINT1, | |
192 | }; | |
193 | ||
194 | static const char * dsd_source_comment[] = { | |
195 | "dsd_source_comment", | |
196 | "analogue_source_comment", | |
197 | "pcm_source_comment", | |
198 | }; | |
199 | ||
200 | static const char * dsd_history_comment[] = { | |
201 | "general_remark", | |
202 | "operator_name", | |
203 | "creating_machine", | |
204 | "timezone", | |
205 | "file_revision" | |
206 | }; | |
207 | ||
208 | static int parse_dsd_diin(AVFormatContext *s, AVStream *st, uint64_t eof) | |
209 | { | |
210 | AVIOContext *pb = s->pb; | |
211 | ||
212 | while (avio_tell(pb) + 12 <= eof) { | |
213 | uint32_t tag = avio_rl32(pb); | |
214 | uint64_t size = avio_rb64(pb); | |
215 | uint64_t orig_pos = avio_tell(pb); | |
216 | const char * metadata_tag = NULL; | |
217 | ||
218 | switch(tag) { | |
219 | case MKTAG('D','I','A','R'): metadata_tag = "artist"; break; | |
220 | case MKTAG('D','I','T','I'): metadata_tag = "title"; break; | |
221 | } | |
222 | ||
223 | if (metadata_tag && size > 4) { | |
224 | unsigned int tag_size = avio_rb32(pb); | |
225 | int ret = get_metadata(s, metadata_tag, FFMIN(tag_size, size - 4)); | |
226 | if (ret < 0) { | |
227 | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
228 | return ret; | |
229 | } | |
230 | } | |
231 | ||
232 | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
233 | } | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) | |
239 | { | |
240 | AVIOContext *pb = s->pb; | |
241 | char abss[24]; | |
242 | int hour, min, sec, i, ret, config; | |
243 | int dsd_layout[6]; | |
244 | ID3v2ExtraMeta *id3v2_extra_meta; | |
245 | ||
246 | while (avio_tell(pb) + 12 <= eof) { | |
247 | uint32_t tag = avio_rl32(pb); | |
248 | uint64_t size = avio_rb64(pb); | |
249 | uint64_t orig_pos = avio_tell(pb); | |
250 | ||
251 | switch(tag) { | |
252 | case MKTAG('A','B','S','S'): | |
253 | if (size < 8) | |
254 | return AVERROR_INVALIDDATA; | |
255 | hour = avio_rb16(pb); | |
256 | min = avio_r8(pb); | |
257 | sec = avio_r8(pb); | |
258 | snprintf(abss, sizeof(abss), "%02dh:%02dm:%02ds:%d", hour, min, sec, avio_rb32(pb)); | |
259 | av_dict_set(&st->metadata, "absolute_start_time", abss, 0); | |
260 | break; | |
261 | ||
262 | case MKTAG('C','H','N','L'): | |
263 | if (size < 2) | |
264 | return AVERROR_INVALIDDATA; | |
265 | st->codec->channels = avio_rb16(pb); | |
266 | if (size < 2 + st->codec->channels * 4) | |
267 | return AVERROR_INVALIDDATA; | |
268 | st->codec->channel_layout = 0; | |
269 | if (st->codec->channels > FF_ARRAY_ELEMS(dsd_layout)) { | |
270 | avpriv_request_sample(s, "channel layout"); | |
271 | break; | |
272 | } | |
273 | for (i = 0; i < st->codec->channels; i++) | |
274 | dsd_layout[i] = avio_rl32(pb); | |
275 | for (i = 0; i < FF_ARRAY_ELEMS(dsd_channel_layout); i++) { | |
276 | const DSDLayoutDesc * d = &dsd_channel_layout[i]; | |
277 | if (av_get_channel_layout_nb_channels(d->layout) == st->codec->channels && | |
278 | !memcmp(d->dsd_layout, dsd_layout, st->codec->channels * sizeof(uint32_t))) { | |
279 | st->codec->channel_layout = d->layout; | |
280 | break; | |
281 | } | |
282 | } | |
283 | break; | |
284 | ||
285 | case MKTAG('C','M','P','R'): | |
286 | if (size < 4) | |
287 | return AVERROR_INVALIDDATA; | |
f6fa7814 DM |
288 | tag = avio_rl32(pb); |
289 | st->codec->codec_id = ff_codec_get_id(dsd_codec_tags, tag); | |
290 | if (!st->codec->codec_id) { | |
291 | av_log(s, AV_LOG_ERROR, "'%c%c%c%c' compression is not supported\n", | |
292 | tag&0xFF, (tag>>8)&0xFF, (tag>>16)&0xFF, (tag>>24)&0xFF); | |
293 | return AVERROR_PATCHWELCOME; | |
294 | } | |
2ba45a60 DM |
295 | break; |
296 | ||
297 | case MKTAG('F','S',' ',' '): | |
298 | if (size < 4) | |
299 | return AVERROR_INVALIDDATA; | |
300 | st->codec->sample_rate = avio_rb32(pb) / 8; | |
301 | break; | |
302 | ||
303 | case MKTAG('I','D','3',' '): | |
304 | id3v2_extra_meta = NULL; | |
305 | ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); | |
306 | if (id3v2_extra_meta) { | |
307 | if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { | |
308 | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
309 | return ret; | |
310 | } | |
311 | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
312 | } | |
313 | ||
314 | if (size < avio_tell(pb) - orig_pos) { | |
315 | av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n"); | |
316 | return AVERROR_INVALIDDATA; | |
317 | } | |
318 | break; | |
319 | ||
320 | case MKTAG('L','S','C','O'): | |
321 | if (size < 2) | |
322 | return AVERROR_INVALIDDATA; | |
323 | config = avio_rb16(pb); | |
324 | if (config != 0xFFFF) { | |
325 | if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config)) | |
326 | st->codec->channel_layout = dsd_loudspeaker_config[config]; | |
327 | if (!st->codec->channel_layout) | |
328 | avpriv_request_sample(s, "loudspeaker configuration %d", config); | |
329 | } | |
330 | break; | |
331 | } | |
332 | ||
333 | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
334 | } | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
339 | static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | |
340 | static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | |
341 | static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8}; | |
342 | static const uint8_t deep_argb[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 1, 0, 8, 0, 2, 0, 8}; | |
343 | static const uint8_t deep_abgr[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 3, 0, 8, 0, 2, 0, 8}; | |
344 | ||
345 | static int iff_read_header(AVFormatContext *s) | |
346 | { | |
347 | IffDemuxContext *iff = s->priv_data; | |
348 | AVIOContext *pb = s->pb; | |
349 | AVStream *st; | |
350 | uint8_t *buf; | |
351 | uint32_t chunk_id; | |
352 | uint64_t data_size; | |
353 | uint32_t screenmode = 0, num, den; | |
354 | unsigned transparency = 0; | |
355 | unsigned masking = 0; // no mask | |
356 | uint8_t fmt[16]; | |
357 | int fmt_size; | |
358 | ||
359 | st = avformat_new_stream(s, NULL); | |
360 | if (!st) | |
361 | return AVERROR(ENOMEM); | |
362 | ||
363 | st->codec->channels = 1; | |
364 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
365 | iff->is_64bit = avio_rl32(pb) == ID_FRM8; | |
366 | avio_skip(pb, iff->is_64bit ? 8 : 4); | |
367 | // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content | |
368 | st->codec->codec_tag = avio_rl32(pb); | |
369 | if (st->codec->codec_tag == ID_ANIM) { | |
370 | avio_skip(pb, 8); | |
371 | st->codec->codec_tag = avio_rl32(pb); | |
372 | } | |
373 | iff->bitmap_compression = -1; | |
374 | iff->svx8_compression = -1; | |
375 | iff->maud_bits = -1; | |
376 | iff->maud_compression = -1; | |
377 | ||
378 | while(!avio_feof(pb)) { | |
379 | uint64_t orig_pos; | |
380 | int res; | |
381 | const char *metadata_tag = NULL; | |
382 | int version, nb_comments, i; | |
383 | chunk_id = avio_rl32(pb); | |
384 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); | |
385 | orig_pos = avio_tell(pb); | |
386 | ||
387 | switch(chunk_id) { | |
388 | case ID_VHDR: | |
389 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
390 | ||
391 | if (data_size < 14) | |
392 | return AVERROR_INVALIDDATA; | |
393 | avio_skip(pb, 12); | |
394 | st->codec->sample_rate = avio_rb16(pb); | |
395 | if (data_size >= 16) { | |
396 | avio_skip(pb, 1); | |
397 | iff->svx8_compression = avio_r8(pb); | |
398 | } | |
399 | break; | |
400 | ||
401 | case ID_MHDR: | |
402 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
403 | ||
404 | if (data_size < 32) | |
405 | return AVERROR_INVALIDDATA; | |
406 | avio_skip(pb, 4); | |
407 | iff->maud_bits = avio_rb16(pb); | |
408 | avio_skip(pb, 2); | |
409 | num = avio_rb32(pb); | |
410 | den = avio_rb16(pb); | |
411 | if (!den) | |
412 | return AVERROR_INVALIDDATA; | |
413 | avio_skip(pb, 2); | |
414 | st->codec->sample_rate = num / den; | |
415 | st->codec->channels = avio_rb16(pb); | |
416 | iff->maud_compression = avio_rb16(pb); | |
417 | if (st->codec->channels == 1) | |
418 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
419 | else if (st->codec->channels == 2) | |
420 | st->codec->channel_layout = AV_CH_LAYOUT_STEREO; | |
421 | break; | |
422 | ||
423 | case ID_ABIT: | |
424 | case ID_BODY: | |
425 | case ID_DBOD: | |
426 | case ID_DSD: | |
427 | case ID_MDAT: | |
428 | iff->body_pos = avio_tell(pb); | |
429 | iff->body_end = iff->body_pos + data_size; | |
430 | iff->body_size = data_size; | |
431 | break; | |
432 | ||
433 | case ID_CHAN: | |
434 | if (data_size < 4) | |
435 | return AVERROR_INVALIDDATA; | |
436 | if (avio_rb32(pb) < 6) { | |
437 | st->codec->channels = 1; | |
438 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
439 | } else { | |
440 | st->codec->channels = 2; | |
441 | st->codec->channel_layout = AV_CH_LAYOUT_STEREO; | |
442 | } | |
443 | break; | |
444 | ||
445 | case ID_CAMG: | |
446 | if (data_size < 4) | |
447 | return AVERROR_INVALIDDATA; | |
448 | screenmode = avio_rb32(pb); | |
449 | break; | |
450 | ||
451 | case ID_CMAP: | |
452 | if (data_size < 3 || data_size > 768 || data_size % 3) { | |
453 | av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n", | |
454 | data_size); | |
455 | return AVERROR_INVALIDDATA; | |
456 | } | |
457 | st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE; | |
458 | st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
459 | if (!st->codec->extradata) | |
460 | return AVERROR(ENOMEM); | |
461 | if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) | |
462 | return AVERROR(EIO); | |
463 | break; | |
464 | ||
465 | case ID_BMHD: | |
466 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
467 | if (data_size <= 8) | |
468 | return AVERROR_INVALIDDATA; | |
469 | st->codec->width = avio_rb16(pb); | |
470 | st->codec->height = avio_rb16(pb); | |
471 | avio_skip(pb, 4); // x, y offset | |
472 | st->codec->bits_per_coded_sample = avio_r8(pb); | |
473 | if (data_size >= 10) | |
474 | masking = avio_r8(pb); | |
475 | if (data_size >= 11) | |
476 | iff->bitmap_compression = avio_r8(pb); | |
477 | if (data_size >= 14) { | |
478 | avio_skip(pb, 1); // padding | |
479 | transparency = avio_rb16(pb); | |
480 | } | |
481 | if (data_size >= 16) { | |
482 | st->sample_aspect_ratio.num = avio_r8(pb); | |
483 | st->sample_aspect_ratio.den = avio_r8(pb); | |
484 | } | |
485 | break; | |
486 | ||
487 | case ID_DPEL: | |
488 | if (data_size < 4 || (data_size & 3)) | |
489 | return AVERROR_INVALIDDATA; | |
490 | if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0) | |
491 | return fmt_size; | |
492 | if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24))) | |
493 | st->codec->pix_fmt = AV_PIX_FMT_RGB24; | |
494 | else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba))) | |
495 | st->codec->pix_fmt = AV_PIX_FMT_RGBA; | |
496 | else if (fmt_size == sizeof(deep_bgra) && !memcmp(fmt, deep_bgra, sizeof(deep_bgra))) | |
497 | st->codec->pix_fmt = AV_PIX_FMT_BGRA; | |
498 | else if (fmt_size == sizeof(deep_argb) && !memcmp(fmt, deep_argb, sizeof(deep_argb))) | |
499 | st->codec->pix_fmt = AV_PIX_FMT_ARGB; | |
500 | else if (fmt_size == sizeof(deep_abgr) && !memcmp(fmt, deep_abgr, sizeof(deep_abgr))) | |
501 | st->codec->pix_fmt = AV_PIX_FMT_ABGR; | |
502 | else { | |
503 | avpriv_request_sample(s, "color format %.16s", fmt); | |
504 | return AVERROR_PATCHWELCOME; | |
505 | } | |
506 | break; | |
507 | ||
508 | case ID_DGBL: | |
509 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
510 | if (data_size < 8) | |
511 | return AVERROR_INVALIDDATA; | |
512 | st->codec->width = avio_rb16(pb); | |
513 | st->codec->height = avio_rb16(pb); | |
514 | iff->bitmap_compression = avio_rb16(pb); | |
515 | st->sample_aspect_ratio.num = avio_r8(pb); | |
516 | st->sample_aspect_ratio.den = avio_r8(pb); | |
517 | st->codec->bits_per_coded_sample = 24; | |
518 | break; | |
519 | ||
520 | case ID_DLOC: | |
521 | if (data_size < 4) | |
522 | return AVERROR_INVALIDDATA; | |
523 | st->codec->width = avio_rb16(pb); | |
524 | st->codec->height = avio_rb16(pb); | |
525 | break; | |
526 | ||
527 | case ID_TVDC: | |
528 | if (data_size < sizeof(iff->tvdc)) | |
529 | return AVERROR_INVALIDDATA; | |
530 | res = avio_read(pb, iff->tvdc, sizeof(iff->tvdc)); | |
531 | if (res < 0) | |
532 | return res; | |
533 | break; | |
534 | ||
535 | case ID_ANNO: | |
536 | case ID_TEXT: metadata_tag = "comment"; break; | |
537 | case ID_AUTH: metadata_tag = "artist"; break; | |
538 | case ID_COPYRIGHT: metadata_tag = "copyright"; break; | |
539 | case ID_NAME: metadata_tag = "title"; break; | |
540 | ||
541 | /* DSD tags */ | |
542 | ||
543 | case MKTAG('F','V','E','R'): | |
544 | if (data_size < 4) | |
545 | return AVERROR_INVALIDDATA; | |
546 | version = avio_rb32(pb); | |
547 | av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF); | |
548 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
549 | break; | |
550 | ||
551 | case MKTAG('D','I','I','N'): | |
552 | res = parse_dsd_diin(s, st, orig_pos + data_size); | |
553 | if (res < 0) | |
554 | return res; | |
555 | break; | |
556 | ||
557 | case MKTAG('P','R','O','P'): | |
558 | if (data_size < 4) | |
559 | return AVERROR_INVALIDDATA; | |
560 | if (avio_rl32(pb) != MKTAG('S','N','D',' ')) { | |
561 | avpriv_request_sample(s, "unknown property type"); | |
562 | break; | |
563 | } | |
564 | res = parse_dsd_prop(s, st, orig_pos + data_size); | |
565 | if (res < 0) | |
566 | return res; | |
567 | break; | |
568 | ||
569 | case MKTAG('C','O','M','T'): | |
570 | if (data_size < 2) | |
571 | return AVERROR_INVALIDDATA; | |
572 | nb_comments = avio_rb16(pb); | |
573 | for (i = 0; i < nb_comments; i++) { | |
574 | int year, mon, day, hour, min, type, ref; | |
575 | char tmp[24]; | |
576 | const char *tag; | |
577 | int metadata_size; | |
578 | ||
579 | year = avio_rb16(pb); | |
580 | mon = avio_r8(pb); | |
581 | day = avio_r8(pb); | |
582 | hour = avio_r8(pb); | |
583 | min = avio_r8(pb); | |
584 | snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min); | |
585 | av_dict_set(&st->metadata, "comment_time", tmp, 0); | |
586 | ||
587 | type = avio_rb16(pb); | |
588 | ref = avio_rb16(pb); | |
589 | switch (type) { | |
590 | case 1: | |
591 | if (!i) | |
592 | tag = "channel_comment"; | |
593 | else { | |
594 | snprintf(tmp, sizeof(tmp), "channel%d_comment", ref); | |
595 | tag = tmp; | |
596 | } | |
597 | break; | |
598 | case 2: | |
599 | tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_source_comment[ref] : "source_comment"; | |
600 | break; | |
601 | case 3: | |
602 | tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history"; | |
603 | break; | |
604 | default: | |
605 | tag = "comment"; | |
606 | } | |
607 | ||
608 | metadata_size = avio_rb32(pb); | |
609 | if ((res = get_metadata(s, tag, metadata_size)) < 0) { | |
610 | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag); | |
611 | return res; | |
612 | } | |
613 | ||
614 | if (metadata_size & 1) | |
615 | avio_skip(pb, 1); | |
616 | } | |
617 | break; | |
618 | } | |
619 | ||
620 | if (metadata_tag) { | |
621 | if ((res = get_metadata(s, metadata_tag, data_size)) < 0) { | |
622 | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
623 | return res; | |
624 | } | |
625 | } | |
626 | avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); | |
627 | } | |
628 | ||
629 | avio_seek(pb, iff->body_pos, SEEK_SET); | |
630 | ||
631 | switch(st->codec->codec_type) { | |
632 | case AVMEDIA_TYPE_AUDIO: | |
633 | avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate); | |
634 | ||
635 | if (st->codec->codec_tag == ID_16SV) | |
636 | st->codec->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR; | |
637 | else if (st->codec->codec_tag == ID_MAUD) { | |
638 | if (iff->maud_bits == 8 && !iff->maud_compression) { | |
639 | st->codec->codec_id = AV_CODEC_ID_PCM_U8; | |
640 | } else if (iff->maud_bits == 16 && !iff->maud_compression) { | |
641 | st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; | |
642 | } else if (iff->maud_bits == 8 && iff->maud_compression == 2) { | |
643 | st->codec->codec_id = AV_CODEC_ID_PCM_ALAW; | |
644 | } else if (iff->maud_bits == 8 && iff->maud_compression == 3) { | |
645 | st->codec->codec_id = AV_CODEC_ID_PCM_MULAW; | |
646 | } else { | |
647 | avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits); | |
648 | return AVERROR_PATCHWELCOME; | |
649 | } | |
650 | } else if (st->codec->codec_tag != ID_DSD) { | |
651 | switch (iff->svx8_compression) { | |
652 | case COMP_NONE: | |
653 | st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; | |
654 | break; | |
655 | case COMP_FIB: | |
656 | st->codec->codec_id = AV_CODEC_ID_8SVX_FIB; | |
657 | break; | |
658 | case COMP_EXP: | |
659 | st->codec->codec_id = AV_CODEC_ID_8SVX_EXP; | |
660 | break; | |
661 | default: | |
662 | av_log(s, AV_LOG_ERROR, | |
663 | "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); | |
664 | return -1; | |
665 | } | |
666 | } | |
667 | ||
668 | st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id); | |
669 | st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample; | |
670 | st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; | |
671 | break; | |
672 | ||
673 | case AVMEDIA_TYPE_VIDEO: | |
674 | iff->bpp = st->codec->bits_per_coded_sample; | |
675 | if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { | |
676 | iff->ham = iff->bpp > 6 ? 6 : 4; | |
677 | st->codec->bits_per_coded_sample = 24; | |
678 | } | |
679 | iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8; | |
680 | iff->masking = masking; | |
681 | iff->transparency = transparency; | |
682 | ||
683 | if (!st->codec->extradata) { | |
684 | st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE; | |
685 | st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
686 | if (!st->codec->extradata) | |
687 | return AVERROR(ENOMEM); | |
688 | } | |
689 | av_assert0(st->codec->extradata_size >= IFF_EXTRA_VIDEO_SIZE); | |
690 | buf = st->codec->extradata; | |
691 | bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE); | |
692 | bytestream_put_byte(&buf, iff->bitmap_compression); | |
693 | bytestream_put_byte(&buf, iff->bpp); | |
694 | bytestream_put_byte(&buf, iff->ham); | |
695 | bytestream_put_byte(&buf, iff->flags); | |
696 | bytestream_put_be16(&buf, iff->transparency); | |
697 | bytestream_put_byte(&buf, iff->masking); | |
698 | bytestream_put_buffer(&buf, iff->tvdc, sizeof(iff->tvdc)); | |
699 | st->codec->codec_id = AV_CODEC_ID_IFF_ILBM; | |
700 | break; | |
701 | default: | |
702 | return -1; | |
703 | } | |
704 | ||
705 | return 0; | |
706 | } | |
707 | ||
708 | static int iff_read_packet(AVFormatContext *s, | |
709 | AVPacket *pkt) | |
710 | { | |
711 | IffDemuxContext *iff = s->priv_data; | |
712 | AVIOContext *pb = s->pb; | |
713 | AVStream *st = s->streams[0]; | |
714 | int ret; | |
715 | int64_t pos = avio_tell(pb); | |
716 | ||
717 | if (pos >= iff->body_end) | |
718 | return AVERROR_EOF; | |
719 | ||
720 | if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
721 | if (st->codec->codec_tag == ID_DSD || st->codec->codec_tag == ID_MAUD) { | |
722 | ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * st->codec->block_align)); | |
723 | } else { | |
724 | ret = av_get_packet(pb, pkt, iff->body_size); | |
725 | } | |
726 | } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | |
727 | uint8_t *buf; | |
728 | ||
729 | if (av_new_packet(pkt, iff->body_size + 2) < 0) { | |
730 | return AVERROR(ENOMEM); | |
731 | } | |
732 | ||
733 | buf = pkt->data; | |
734 | bytestream_put_be16(&buf, 2); | |
735 | ret = avio_read(pb, buf, iff->body_size); | |
736 | if (ret<0) { | |
737 | av_free_packet(pkt); | |
738 | } else if (ret < iff->body_size) | |
739 | av_shrink_packet(pkt, ret + 2); | |
740 | } else { | |
741 | av_assert0(0); | |
742 | } | |
743 | ||
744 | if (pos == iff->body_pos) | |
745 | pkt->flags |= AV_PKT_FLAG_KEY; | |
746 | if (ret < 0) | |
747 | return ret; | |
748 | pkt->stream_index = 0; | |
749 | return ret; | |
750 | } | |
751 | ||
752 | AVInputFormat ff_iff_demuxer = { | |
753 | .name = "iff", | |
754 | .long_name = NULL_IF_CONFIG_SMALL("IFF (Interchange File Format)"), | |
755 | .priv_data_size = sizeof(IffDemuxContext), | |
756 | .read_probe = iff_probe, | |
757 | .read_header = iff_read_header, | |
758 | .read_packet = iff_read_packet, | |
759 | .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, | |
760 | }; |