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; | |
288 | st->codec->codec_id = ff_codec_get_id(dsd_codec_tags, avio_rl32(pb)); | |
289 | break; | |
290 | ||
291 | case MKTAG('F','S',' ',' '): | |
292 | if (size < 4) | |
293 | return AVERROR_INVALIDDATA; | |
294 | st->codec->sample_rate = avio_rb32(pb) / 8; | |
295 | break; | |
296 | ||
297 | case MKTAG('I','D','3',' '): | |
298 | id3v2_extra_meta = NULL; | |
299 | ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); | |
300 | if (id3v2_extra_meta) { | |
301 | if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) { | |
302 | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
303 | return ret; | |
304 | } | |
305 | ff_id3v2_free_extra_meta(&id3v2_extra_meta); | |
306 | } | |
307 | ||
308 | if (size < avio_tell(pb) - orig_pos) { | |
309 | av_log(s, AV_LOG_ERROR, "id3 exceeds chunk size\n"); | |
310 | return AVERROR_INVALIDDATA; | |
311 | } | |
312 | break; | |
313 | ||
314 | case MKTAG('L','S','C','O'): | |
315 | if (size < 2) | |
316 | return AVERROR_INVALIDDATA; | |
317 | config = avio_rb16(pb); | |
318 | if (config != 0xFFFF) { | |
319 | if (config < FF_ARRAY_ELEMS(dsd_loudspeaker_config)) | |
320 | st->codec->channel_layout = dsd_loudspeaker_config[config]; | |
321 | if (!st->codec->channel_layout) | |
322 | avpriv_request_sample(s, "loudspeaker configuration %d", config); | |
323 | } | |
324 | break; | |
325 | } | |
326 | ||
327 | avio_skip(pb, size - (avio_tell(pb) - orig_pos) + (size & 1)); | |
328 | } | |
329 | ||
330 | return 0; | |
331 | } | |
332 | ||
333 | static const uint8_t deep_rgb24[] = {0, 0, 0, 3, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | |
334 | static const uint8_t deep_rgba[] = {0, 0, 0, 4, 0, 1, 0, 8, 0, 2, 0, 8, 0, 3, 0, 8}; | |
335 | static const uint8_t deep_bgra[] = {0, 0, 0, 4, 0, 3, 0, 8, 0, 2, 0, 8, 0, 1, 0, 8}; | |
336 | static const uint8_t deep_argb[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 1, 0, 8, 0, 2, 0, 8}; | |
337 | static const uint8_t deep_abgr[] = {0, 0, 0, 4, 0,17, 0, 8, 0, 3, 0, 8, 0, 2, 0, 8}; | |
338 | ||
339 | static int iff_read_header(AVFormatContext *s) | |
340 | { | |
341 | IffDemuxContext *iff = s->priv_data; | |
342 | AVIOContext *pb = s->pb; | |
343 | AVStream *st; | |
344 | uint8_t *buf; | |
345 | uint32_t chunk_id; | |
346 | uint64_t data_size; | |
347 | uint32_t screenmode = 0, num, den; | |
348 | unsigned transparency = 0; | |
349 | unsigned masking = 0; // no mask | |
350 | uint8_t fmt[16]; | |
351 | int fmt_size; | |
352 | ||
353 | st = avformat_new_stream(s, NULL); | |
354 | if (!st) | |
355 | return AVERROR(ENOMEM); | |
356 | ||
357 | st->codec->channels = 1; | |
358 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
359 | iff->is_64bit = avio_rl32(pb) == ID_FRM8; | |
360 | avio_skip(pb, iff->is_64bit ? 8 : 4); | |
361 | // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content | |
362 | st->codec->codec_tag = avio_rl32(pb); | |
363 | if (st->codec->codec_tag == ID_ANIM) { | |
364 | avio_skip(pb, 8); | |
365 | st->codec->codec_tag = avio_rl32(pb); | |
366 | } | |
367 | iff->bitmap_compression = -1; | |
368 | iff->svx8_compression = -1; | |
369 | iff->maud_bits = -1; | |
370 | iff->maud_compression = -1; | |
371 | ||
372 | while(!avio_feof(pb)) { | |
373 | uint64_t orig_pos; | |
374 | int res; | |
375 | const char *metadata_tag = NULL; | |
376 | int version, nb_comments, i; | |
377 | chunk_id = avio_rl32(pb); | |
378 | data_size = iff->is_64bit ? avio_rb64(pb) : avio_rb32(pb); | |
379 | orig_pos = avio_tell(pb); | |
380 | ||
381 | switch(chunk_id) { | |
382 | case ID_VHDR: | |
383 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
384 | ||
385 | if (data_size < 14) | |
386 | return AVERROR_INVALIDDATA; | |
387 | avio_skip(pb, 12); | |
388 | st->codec->sample_rate = avio_rb16(pb); | |
389 | if (data_size >= 16) { | |
390 | avio_skip(pb, 1); | |
391 | iff->svx8_compression = avio_r8(pb); | |
392 | } | |
393 | break; | |
394 | ||
395 | case ID_MHDR: | |
396 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
397 | ||
398 | if (data_size < 32) | |
399 | return AVERROR_INVALIDDATA; | |
400 | avio_skip(pb, 4); | |
401 | iff->maud_bits = avio_rb16(pb); | |
402 | avio_skip(pb, 2); | |
403 | num = avio_rb32(pb); | |
404 | den = avio_rb16(pb); | |
405 | if (!den) | |
406 | return AVERROR_INVALIDDATA; | |
407 | avio_skip(pb, 2); | |
408 | st->codec->sample_rate = num / den; | |
409 | st->codec->channels = avio_rb16(pb); | |
410 | iff->maud_compression = avio_rb16(pb); | |
411 | if (st->codec->channels == 1) | |
412 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
413 | else if (st->codec->channels == 2) | |
414 | st->codec->channel_layout = AV_CH_LAYOUT_STEREO; | |
415 | break; | |
416 | ||
417 | case ID_ABIT: | |
418 | case ID_BODY: | |
419 | case ID_DBOD: | |
420 | case ID_DSD: | |
421 | case ID_MDAT: | |
422 | iff->body_pos = avio_tell(pb); | |
423 | iff->body_end = iff->body_pos + data_size; | |
424 | iff->body_size = data_size; | |
425 | break; | |
426 | ||
427 | case ID_CHAN: | |
428 | if (data_size < 4) | |
429 | return AVERROR_INVALIDDATA; | |
430 | if (avio_rb32(pb) < 6) { | |
431 | st->codec->channels = 1; | |
432 | st->codec->channel_layout = AV_CH_LAYOUT_MONO; | |
433 | } else { | |
434 | st->codec->channels = 2; | |
435 | st->codec->channel_layout = AV_CH_LAYOUT_STEREO; | |
436 | } | |
437 | break; | |
438 | ||
439 | case ID_CAMG: | |
440 | if (data_size < 4) | |
441 | return AVERROR_INVALIDDATA; | |
442 | screenmode = avio_rb32(pb); | |
443 | break; | |
444 | ||
445 | case ID_CMAP: | |
446 | if (data_size < 3 || data_size > 768 || data_size % 3) { | |
447 | av_log(s, AV_LOG_ERROR, "Invalid CMAP chunk size %"PRIu64"\n", | |
448 | data_size); | |
449 | return AVERROR_INVALIDDATA; | |
450 | } | |
451 | st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE; | |
452 | st->codec->extradata = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
453 | if (!st->codec->extradata) | |
454 | return AVERROR(ENOMEM); | |
455 | if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0) | |
456 | return AVERROR(EIO); | |
457 | break; | |
458 | ||
459 | case ID_BMHD: | |
460 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
461 | if (data_size <= 8) | |
462 | return AVERROR_INVALIDDATA; | |
463 | st->codec->width = avio_rb16(pb); | |
464 | st->codec->height = avio_rb16(pb); | |
465 | avio_skip(pb, 4); // x, y offset | |
466 | st->codec->bits_per_coded_sample = avio_r8(pb); | |
467 | if (data_size >= 10) | |
468 | masking = avio_r8(pb); | |
469 | if (data_size >= 11) | |
470 | iff->bitmap_compression = avio_r8(pb); | |
471 | if (data_size >= 14) { | |
472 | avio_skip(pb, 1); // padding | |
473 | transparency = avio_rb16(pb); | |
474 | } | |
475 | if (data_size >= 16) { | |
476 | st->sample_aspect_ratio.num = avio_r8(pb); | |
477 | st->sample_aspect_ratio.den = avio_r8(pb); | |
478 | } | |
479 | break; | |
480 | ||
481 | case ID_DPEL: | |
482 | if (data_size < 4 || (data_size & 3)) | |
483 | return AVERROR_INVALIDDATA; | |
484 | if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0) | |
485 | return fmt_size; | |
486 | if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24))) | |
487 | st->codec->pix_fmt = AV_PIX_FMT_RGB24; | |
488 | else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba))) | |
489 | st->codec->pix_fmt = AV_PIX_FMT_RGBA; | |
490 | else if (fmt_size == sizeof(deep_bgra) && !memcmp(fmt, deep_bgra, sizeof(deep_bgra))) | |
491 | st->codec->pix_fmt = AV_PIX_FMT_BGRA; | |
492 | else if (fmt_size == sizeof(deep_argb) && !memcmp(fmt, deep_argb, sizeof(deep_argb))) | |
493 | st->codec->pix_fmt = AV_PIX_FMT_ARGB; | |
494 | else if (fmt_size == sizeof(deep_abgr) && !memcmp(fmt, deep_abgr, sizeof(deep_abgr))) | |
495 | st->codec->pix_fmt = AV_PIX_FMT_ABGR; | |
496 | else { | |
497 | avpriv_request_sample(s, "color format %.16s", fmt); | |
498 | return AVERROR_PATCHWELCOME; | |
499 | } | |
500 | break; | |
501 | ||
502 | case ID_DGBL: | |
503 | st->codec->codec_type = AVMEDIA_TYPE_VIDEO; | |
504 | if (data_size < 8) | |
505 | return AVERROR_INVALIDDATA; | |
506 | st->codec->width = avio_rb16(pb); | |
507 | st->codec->height = avio_rb16(pb); | |
508 | iff->bitmap_compression = avio_rb16(pb); | |
509 | st->sample_aspect_ratio.num = avio_r8(pb); | |
510 | st->sample_aspect_ratio.den = avio_r8(pb); | |
511 | st->codec->bits_per_coded_sample = 24; | |
512 | break; | |
513 | ||
514 | case ID_DLOC: | |
515 | if (data_size < 4) | |
516 | return AVERROR_INVALIDDATA; | |
517 | st->codec->width = avio_rb16(pb); | |
518 | st->codec->height = avio_rb16(pb); | |
519 | break; | |
520 | ||
521 | case ID_TVDC: | |
522 | if (data_size < sizeof(iff->tvdc)) | |
523 | return AVERROR_INVALIDDATA; | |
524 | res = avio_read(pb, iff->tvdc, sizeof(iff->tvdc)); | |
525 | if (res < 0) | |
526 | return res; | |
527 | break; | |
528 | ||
529 | case ID_ANNO: | |
530 | case ID_TEXT: metadata_tag = "comment"; break; | |
531 | case ID_AUTH: metadata_tag = "artist"; break; | |
532 | case ID_COPYRIGHT: metadata_tag = "copyright"; break; | |
533 | case ID_NAME: metadata_tag = "title"; break; | |
534 | ||
535 | /* DSD tags */ | |
536 | ||
537 | case MKTAG('F','V','E','R'): | |
538 | if (data_size < 4) | |
539 | return AVERROR_INVALIDDATA; | |
540 | version = avio_rb32(pb); | |
541 | av_log(s, AV_LOG_DEBUG, "DSIFF v%d.%d.%d.%d\n",version >> 24, (version >> 16) & 0xFF, (version >> 8) & 0xFF, version & 0xFF); | |
542 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; | |
543 | break; | |
544 | ||
545 | case MKTAG('D','I','I','N'): | |
546 | res = parse_dsd_diin(s, st, orig_pos + data_size); | |
547 | if (res < 0) | |
548 | return res; | |
549 | break; | |
550 | ||
551 | case MKTAG('P','R','O','P'): | |
552 | if (data_size < 4) | |
553 | return AVERROR_INVALIDDATA; | |
554 | if (avio_rl32(pb) != MKTAG('S','N','D',' ')) { | |
555 | avpriv_request_sample(s, "unknown property type"); | |
556 | break; | |
557 | } | |
558 | res = parse_dsd_prop(s, st, orig_pos + data_size); | |
559 | if (res < 0) | |
560 | return res; | |
561 | break; | |
562 | ||
563 | case MKTAG('C','O','M','T'): | |
564 | if (data_size < 2) | |
565 | return AVERROR_INVALIDDATA; | |
566 | nb_comments = avio_rb16(pb); | |
567 | for (i = 0; i < nb_comments; i++) { | |
568 | int year, mon, day, hour, min, type, ref; | |
569 | char tmp[24]; | |
570 | const char *tag; | |
571 | int metadata_size; | |
572 | ||
573 | year = avio_rb16(pb); | |
574 | mon = avio_r8(pb); | |
575 | day = avio_r8(pb); | |
576 | hour = avio_r8(pb); | |
577 | min = avio_r8(pb); | |
578 | snprintf(tmp, sizeof(tmp), "%04d-%02d-%02d %02d:%02d", year, mon, day, hour, min); | |
579 | av_dict_set(&st->metadata, "comment_time", tmp, 0); | |
580 | ||
581 | type = avio_rb16(pb); | |
582 | ref = avio_rb16(pb); | |
583 | switch (type) { | |
584 | case 1: | |
585 | if (!i) | |
586 | tag = "channel_comment"; | |
587 | else { | |
588 | snprintf(tmp, sizeof(tmp), "channel%d_comment", ref); | |
589 | tag = tmp; | |
590 | } | |
591 | break; | |
592 | case 2: | |
593 | tag = ref < FF_ARRAY_ELEMS(dsd_source_comment) ? dsd_source_comment[ref] : "source_comment"; | |
594 | break; | |
595 | case 3: | |
596 | tag = ref < FF_ARRAY_ELEMS(dsd_history_comment) ? dsd_history_comment[ref] : "file_history"; | |
597 | break; | |
598 | default: | |
599 | tag = "comment"; | |
600 | } | |
601 | ||
602 | metadata_size = avio_rb32(pb); | |
603 | if ((res = get_metadata(s, tag, metadata_size)) < 0) { | |
604 | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", tag); | |
605 | return res; | |
606 | } | |
607 | ||
608 | if (metadata_size & 1) | |
609 | avio_skip(pb, 1); | |
610 | } | |
611 | break; | |
612 | } | |
613 | ||
614 | if (metadata_tag) { | |
615 | if ((res = get_metadata(s, metadata_tag, data_size)) < 0) { | |
616 | av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag); | |
617 | return res; | |
618 | } | |
619 | } | |
620 | avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1)); | |
621 | } | |
622 | ||
623 | avio_seek(pb, iff->body_pos, SEEK_SET); | |
624 | ||
625 | switch(st->codec->codec_type) { | |
626 | case AVMEDIA_TYPE_AUDIO: | |
627 | avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate); | |
628 | ||
629 | if (st->codec->codec_tag == ID_16SV) | |
630 | st->codec->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR; | |
631 | else if (st->codec->codec_tag == ID_MAUD) { | |
632 | if (iff->maud_bits == 8 && !iff->maud_compression) { | |
633 | st->codec->codec_id = AV_CODEC_ID_PCM_U8; | |
634 | } else if (iff->maud_bits == 16 && !iff->maud_compression) { | |
635 | st->codec->codec_id = AV_CODEC_ID_PCM_S16BE; | |
636 | } else if (iff->maud_bits == 8 && iff->maud_compression == 2) { | |
637 | st->codec->codec_id = AV_CODEC_ID_PCM_ALAW; | |
638 | } else if (iff->maud_bits == 8 && iff->maud_compression == 3) { | |
639 | st->codec->codec_id = AV_CODEC_ID_PCM_MULAW; | |
640 | } else { | |
641 | avpriv_request_sample(s, "compression %d and bit depth %d", iff->maud_compression, iff->maud_bits); | |
642 | return AVERROR_PATCHWELCOME; | |
643 | } | |
644 | } else if (st->codec->codec_tag != ID_DSD) { | |
645 | switch (iff->svx8_compression) { | |
646 | case COMP_NONE: | |
647 | st->codec->codec_id = AV_CODEC_ID_PCM_S8_PLANAR; | |
648 | break; | |
649 | case COMP_FIB: | |
650 | st->codec->codec_id = AV_CODEC_ID_8SVX_FIB; | |
651 | break; | |
652 | case COMP_EXP: | |
653 | st->codec->codec_id = AV_CODEC_ID_8SVX_EXP; | |
654 | break; | |
655 | default: | |
656 | av_log(s, AV_LOG_ERROR, | |
657 | "Unknown SVX8 compression method '%d'\n", iff->svx8_compression); | |
658 | return -1; | |
659 | } | |
660 | } | |
661 | ||
662 | st->codec->bits_per_coded_sample = av_get_bits_per_sample(st->codec->codec_id); | |
663 | st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample; | |
664 | st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; | |
665 | break; | |
666 | ||
667 | case AVMEDIA_TYPE_VIDEO: | |
668 | iff->bpp = st->codec->bits_per_coded_sample; | |
669 | if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) { | |
670 | iff->ham = iff->bpp > 6 ? 6 : 4; | |
671 | st->codec->bits_per_coded_sample = 24; | |
672 | } | |
673 | iff->flags = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8; | |
674 | iff->masking = masking; | |
675 | iff->transparency = transparency; | |
676 | ||
677 | if (!st->codec->extradata) { | |
678 | st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE; | |
679 | st->codec->extradata = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); | |
680 | if (!st->codec->extradata) | |
681 | return AVERROR(ENOMEM); | |
682 | } | |
683 | av_assert0(st->codec->extradata_size >= IFF_EXTRA_VIDEO_SIZE); | |
684 | buf = st->codec->extradata; | |
685 | bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE); | |
686 | bytestream_put_byte(&buf, iff->bitmap_compression); | |
687 | bytestream_put_byte(&buf, iff->bpp); | |
688 | bytestream_put_byte(&buf, iff->ham); | |
689 | bytestream_put_byte(&buf, iff->flags); | |
690 | bytestream_put_be16(&buf, iff->transparency); | |
691 | bytestream_put_byte(&buf, iff->masking); | |
692 | bytestream_put_buffer(&buf, iff->tvdc, sizeof(iff->tvdc)); | |
693 | st->codec->codec_id = AV_CODEC_ID_IFF_ILBM; | |
694 | break; | |
695 | default: | |
696 | return -1; | |
697 | } | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
702 | static int iff_read_packet(AVFormatContext *s, | |
703 | AVPacket *pkt) | |
704 | { | |
705 | IffDemuxContext *iff = s->priv_data; | |
706 | AVIOContext *pb = s->pb; | |
707 | AVStream *st = s->streams[0]; | |
708 | int ret; | |
709 | int64_t pos = avio_tell(pb); | |
710 | ||
711 | if (pos >= iff->body_end) | |
712 | return AVERROR_EOF; | |
713 | ||
714 | if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |
715 | if (st->codec->codec_tag == ID_DSD || st->codec->codec_tag == ID_MAUD) { | |
716 | ret = av_get_packet(pb, pkt, FFMIN(iff->body_end - pos, 1024 * st->codec->block_align)); | |
717 | } else { | |
718 | ret = av_get_packet(pb, pkt, iff->body_size); | |
719 | } | |
720 | } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | |
721 | uint8_t *buf; | |
722 | ||
723 | if (av_new_packet(pkt, iff->body_size + 2) < 0) { | |
724 | return AVERROR(ENOMEM); | |
725 | } | |
726 | ||
727 | buf = pkt->data; | |
728 | bytestream_put_be16(&buf, 2); | |
729 | ret = avio_read(pb, buf, iff->body_size); | |
730 | if (ret<0) { | |
731 | av_free_packet(pkt); | |
732 | } else if (ret < iff->body_size) | |
733 | av_shrink_packet(pkt, ret + 2); | |
734 | } else { | |
735 | av_assert0(0); | |
736 | } | |
737 | ||
738 | if (pos == iff->body_pos) | |
739 | pkt->flags |= AV_PKT_FLAG_KEY; | |
740 | if (ret < 0) | |
741 | return ret; | |
742 | pkt->stream_index = 0; | |
743 | return ret; | |
744 | } | |
745 | ||
746 | AVInputFormat ff_iff_demuxer = { | |
747 | .name = "iff", | |
748 | .long_name = NULL_IF_CONFIG_SMALL("IFF (Interchange File Format)"), | |
749 | .priv_data_size = sizeof(IffDemuxContext), | |
750 | .read_probe = iff_probe, | |
751 | .read_header = iff_read_header, | |
752 | .read_packet = iff_read_packet, | |
753 | .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, | |
754 | }; |