Mercurial > libavformat.hg
annotate iff.c @ 6099:ed24da0b0cee libavformat
bgr/rgb444 for nut
author | michael |
---|---|
date | Sun, 06 Jun 2010 11:43:53 +0000 |
parents | 5b6f32f1546f |
children | 7d8e6562ce1a |
rev | line source |
---|---|
3189 | 1 /* |
3198 | 2 * IFF (.iff) file demuxer |
3189 | 3 * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> |
5625 | 4 * Copyright (c) 2010 Peter Ross <pross@xvid.org> |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
5 * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com> |
3189 | 6 * |
7 * This file is part of FFmpeg. | |
8 * | |
9 * FFmpeg is free software; you can redistribute it and/or | |
10 * modify it under the terms of the GNU Lesser General Public | |
11 * License as published by the Free Software Foundation; either | |
12 * version 2.1 of the License, or (at your option) any later version. | |
13 * | |
14 * FFmpeg is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 * Lesser General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU Lesser General Public | |
20 * License along with FFmpeg; if not, write to the Free Software | |
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 */ | |
23 | |
24 /** | |
5969
178de7695c6c
Remove explicit filename from Doxygen @file commands.
diego
parents:
5913
diff
changeset
|
25 * @file |
3198 | 26 * IFF file demuxer |
3189 | 27 * by Jaikrishnan Menon |
28 * for more information on the .iff file format, visit: | |
29 * http://wiki.multimedia.cx/index.php?title=IFF | |
30 */ | |
31 | |
4201
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
4090
diff
changeset
|
32 #include "libavutil/intreadwrite.h" |
5773
fd3b7b9b63a8
IFF: move ff_cmap_read_palette() prototype to a header file
mru
parents:
5660
diff
changeset
|
33 #include "libavcodec/iff.h" |
3189 | 34 #include "avformat.h" |
35 | |
36 #define ID_8SVX MKTAG('8','S','V','X') | |
37 #define ID_VHDR MKTAG('V','H','D','R') | |
38 #define ID_ATAK MKTAG('A','T','A','K') | |
39 #define ID_RLSE MKTAG('R','L','S','E') | |
40 #define ID_CHAN MKTAG('C','H','A','N') | |
5625 | 41 #define ID_PBM MKTAG('P','B','M',' ') |
42 #define ID_ILBM MKTAG('I','L','B','M') | |
43 #define ID_BMHD MKTAG('B','M','H','D') | |
44 #define ID_CMAP MKTAG('C','M','A','P') | |
3189 | 45 |
46 #define ID_FORM MKTAG('F','O','R','M') | |
47 #define ID_ANNO MKTAG('A','N','N','O') | |
48 #define ID_AUTH MKTAG('A','U','T','H') | |
49 #define ID_CHRS MKTAG('C','H','R','S') | |
50 #define ID_COPYRIGHT MKTAG('(','c',')',' ') | |
51 #define ID_CSET MKTAG('C','S','E','T') | |
52 #define ID_FVER MKTAG('F','V','E','R') | |
53 #define ID_NAME MKTAG('N','A','M','E') | |
54 #define ID_TEXT MKTAG('T','E','X','T') | |
55 #define ID_BODY MKTAG('B','O','D','Y') | |
5660 | 56 #define ID_ANNO MKTAG('A','N','N','O') |
3189 | 57 |
58 #define LEFT 2 | |
59 #define RIGHT 4 | |
60 #define STEREO 6 | |
61 | |
62 #define PACKET_SIZE 1024 | |
63 | |
5971
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
64 typedef enum { |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
65 COMP_NONE, |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
66 COMP_FIB, |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
67 COMP_EXP |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
68 } svx8_compression_type; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
69 |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
70 typedef enum { |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
71 BITMAP_RAW, |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
72 BITMAP_BYTERUN1 |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
73 } bitmap_compression_type; |
3189 | 74 |
75 typedef struct { | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
76 uint64_t body_pos; |
3189 | 77 uint32_t body_size; |
78 uint32_t sent_bytes; | |
79 uint32_t audio_frame_count; | |
80 } IffDemuxContext; | |
81 | |
3285 | 82 |
83 static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size) | |
84 { | |
85 uint8_t *end = dest + size; | |
86 size = size>>1; | |
87 | |
88 while(dest < end) { | |
89 *dest++ = *src; | |
90 *dest++ = *(src+size); | |
91 src++; | |
92 } | |
93 } | |
94 | |
5994 | 95 /* Metadata string read */ |
96 static int get_metadata(AVFormatContext *s, | |
97 const char *const tag, | |
98 const unsigned data_size) | |
99 { | |
100 uint8_t *buf = ((data_size + 1) == 0) ? NULL : av_malloc(data_size + 1); | |
101 | |
102 if (!buf) | |
103 return AVERROR(ENOMEM); | |
104 | |
105 if (get_buffer(s->pb, buf, data_size) < 0) { | |
106 av_free(buf); | |
107 return AVERROR(EIO); | |
108 } | |
109 buf[data_size] = 0; | |
110 av_metadata_set2(&s->metadata, tag, buf, AV_METADATA_DONT_STRDUP_VAL); | |
111 return 0; | |
112 } | |
113 | |
3189 | 114 static int iff_probe(AVProbeData *p) |
115 { | |
116 const uint8_t *d = p->buf; | |
117 | |
118 if ( AV_RL32(d) == ID_FORM && | |
5625 | 119 (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM) ) |
3189 | 120 return AVPROBE_SCORE_MAX; |
121 return 0; | |
122 } | |
123 | |
124 static int iff_read_header(AVFormatContext *s, | |
125 AVFormatParameters *ap) | |
126 { | |
127 IffDemuxContext *iff = s->priv_data; | |
128 ByteIOContext *pb = s->pb; | |
129 AVStream *st; | |
130 uint32_t chunk_id, data_size; | |
5625 | 131 int compression = -1; |
3189 | 132 |
133 st = av_new_stream(s, 0); | |
134 if (!st) | |
5985 | 135 return AVERROR(ENOMEM); |
3189 | 136 |
137 st->codec->channels = 1; | |
5625 | 138 url_fskip(pb, 8); |
139 // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content | |
140 st->codec->codec_tag = get_le32(pb); | |
3189 | 141 |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
142 while(!url_feof(pb)) { |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
143 uint64_t orig_pos; |
5994 | 144 int res; |
145 const char *metadata_tag = NULL; | |
3189 | 146 chunk_id = get_le32(pb); |
147 data_size = get_be32(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
148 orig_pos = url_ftell(pb); |
3189 | 149 |
150 switch(chunk_id) { | |
151 case ID_VHDR: | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5773
diff
changeset
|
152 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
153 |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
154 if (data_size < 14) |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
155 return AVERROR_INVALIDDATA; |
3189 | 156 url_fskip(pb, 12); |
157 st->codec->sample_rate = get_be16(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
158 if (data_size >= 16) { |
5985 | 159 url_fskip(pb, 1); |
160 compression = get_byte(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
161 } |
3189 | 162 break; |
163 | |
164 case ID_BODY: | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
165 iff->body_pos = url_ftell(pb); |
3189 | 166 iff->body_size = data_size; |
167 break; | |
168 | |
169 case ID_CHAN: | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
170 if (data_size < 4) |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
171 return AVERROR_INVALIDDATA; |
3189 | 172 st->codec->channels = (get_be32(pb) < 6) ? 1 : 2; |
173 break; | |
174 | |
5625 | 175 case ID_CMAP: |
176 st->codec->extradata_size = data_size; | |
177 st->codec->extradata = av_malloc(data_size); | |
178 if (!st->codec->extradata) | |
179 return AVERROR(ENOMEM); | |
180 if (get_buffer(pb, st->codec->extradata, data_size) < 0) | |
181 return AVERROR(EIO); | |
182 break; | |
183 | |
184 case ID_BMHD: | |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5773
diff
changeset
|
185 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
186 if (data_size <= 8) |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
187 return AVERROR_INVALIDDATA; |
5625 | 188 st->codec->width = get_be16(pb); |
189 st->codec->height = get_be16(pb); | |
190 url_fskip(pb, 4); // x, y offset | |
191 st->codec->bits_per_coded_sample = get_byte(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
192 if (data_size >= 11) { |
5985 | 193 url_fskip(pb, 1); // masking |
194 compression = get_byte(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
195 } |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
196 if (data_size >= 16) { |
5985 | 197 url_fskip(pb, 3); // paddding, transparent |
198 st->sample_aspect_ratio.num = get_byte(pb); | |
199 st->sample_aspect_ratio.den = get_byte(pb); | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
200 } |
5625 | 201 break; |
202 | |
5660 | 203 case ID_ANNO: |
5994 | 204 case ID_TEXT: |
205 metadata_tag = "comment"; | |
206 break; | |
207 | |
208 case ID_AUTH: | |
209 metadata_tag = "artist"; | |
210 break; | |
211 | |
212 case ID_COPYRIGHT: | |
213 metadata_tag = "copyright"; | |
214 break; | |
215 | |
216 case ID_NAME: | |
217 metadata_tag = "title"; | |
5660 | 218 break; |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
219 } |
5660 | 220 |
5994 | 221 if (metadata_tag) { |
222 if ((res = get_metadata(s, metadata_tag, data_size)) < 0) { | |
223 av_log(s, AV_LOG_ERROR, "iff: cannot allocate metadata tag %s!", metadata_tag); | |
224 return res; | |
225 } | |
226 } | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
227 url_fskip(pb, data_size - (url_ftell(pb) - orig_pos) + (data_size & 1)); |
3189 | 228 } |
229 | |
5984
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
230 url_fseek(pb, iff->body_pos, SEEK_SET); |
55c714a8fb00
Make the IFF demuxer a little more standards-compliant, e.g. respect the size
rbultje
parents:
5971
diff
changeset
|
231 |
5625 | 232 switch(st->codec->codec_type) { |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5773
diff
changeset
|
233 case AVMEDIA_TYPE_AUDIO: |
5971
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
234 av_set_pts_info(st, 32, 1, st->codec->sample_rate); |
3189 | 235 |
5971
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
236 switch(compression) { |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
237 case COMP_NONE: |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
238 st->codec->codec_id = CODEC_ID_PCM_S8; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
239 break; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
240 case COMP_FIB: |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
241 st->codec->codec_id = CODEC_ID_8SVX_FIB; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
242 break; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
243 case COMP_EXP: |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
244 st->codec->codec_id = CODEC_ID_8SVX_EXP; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
245 break; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
246 default: |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
247 av_log(s, AV_LOG_ERROR, "iff: unknown compression method\n"); |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
248 return -1; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
249 } |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
250 |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
251 st->codec->bits_per_coded_sample = 8; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
252 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample; |
43548500ffbc
Reindent / reformat some code with broken indenting.
rbultje
parents:
5969
diff
changeset
|
253 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample; |
3189 | 254 break; |
5625 | 255 |
5910
536e5527c1e0
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
5773
diff
changeset
|
256 case AVMEDIA_TYPE_VIDEO: |
5625 | 257 switch (compression) { |
258 case BITMAP_RAW: | |
6002 | 259 st->codec->codec_id = CODEC_ID_IFF_ILBM; |
5625 | 260 break; |
261 case BITMAP_BYTERUN1: | |
262 st->codec->codec_id = CODEC_ID_IFF_BYTERUN1; | |
263 break; | |
264 default: | |
265 av_log(s, AV_LOG_ERROR, "unknown compression method\n"); | |
266 return AVERROR_INVALIDDATA; | |
267 } | |
268 break; | |
269 default: | |
270 return -1; | |
271 } | |
3189 | 272 |
273 return 0; | |
274 } | |
275 | |
276 static int iff_read_packet(AVFormatContext *s, | |
277 AVPacket *pkt) | |
278 { | |
279 IffDemuxContext *iff = s->priv_data; | |
280 ByteIOContext *pb = s->pb; | |
5625 | 281 AVStream *st = s->streams[0]; |
3189 | 282 int ret; |
283 | |
5625 | 284 if(iff->sent_bytes >= iff->body_size) |
3189 | 285 return AVERROR(EIO); |
3285 | 286 |
5996
39d22a65f36a
Replace usage of s->streams[0]->* with st->*, which is shorter.
rbultje
parents:
5994
diff
changeset
|
287 if(st->codec->channels == 2) { |
3285 | 288 uint8_t sample_buffer[PACKET_SIZE]; |
289 | |
290 ret = get_buffer(pb, sample_buffer, PACKET_SIZE); | |
291 if(av_new_packet(pkt, PACKET_SIZE) < 0) { | |
292 av_log(s, AV_LOG_ERROR, "iff: cannot allocate packet \n"); | |
293 return AVERROR(ENOMEM); | |
294 } | |
295 interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE); | |
5996
39d22a65f36a
Replace usage of s->streams[0]->* with st->*, which is shorter.
rbultje
parents:
5994
diff
changeset
|
296 } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
5625 | 297 ret = av_get_packet(pb, pkt, iff->body_size); |
298 } else { | |
3285 | 299 ret = av_get_packet(pb, pkt, PACKET_SIZE); |
300 } | |
3189 | 301 |
302 if(iff->sent_bytes == 0) | |
5913
11bb10c37225
Replace all occurences of PKT_FLAG_KEY with AV_PKT_FLAG_KEY.
cehoyos
parents:
5910
diff
changeset
|
303 pkt->flags |= AV_PKT_FLAG_KEY; |
3189 | 304 |
5996
39d22a65f36a
Replace usage of s->streams[0]->* with st->*, which is shorter.
rbultje
parents:
5994
diff
changeset
|
305 if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
5626 | 306 iff->sent_bytes += PACKET_SIZE; |
5625 | 307 } else { |
308 iff->sent_bytes = iff->body_size; | |
309 } | |
3189 | 310 pkt->stream_index = 0; |
5996
39d22a65f36a
Replace usage of s->streams[0]->* with st->*, which is shorter.
rbultje
parents:
5994
diff
changeset
|
311 if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
5626 | 312 pkt->pts = iff->audio_frame_count; |
5996
39d22a65f36a
Replace usage of s->streams[0]->* with st->*, which is shorter.
rbultje
parents:
5994
diff
changeset
|
313 iff->audio_frame_count += ret / st->codec->channels; |
5625 | 314 } |
3189 | 315 return ret; |
316 } | |
317 | |
318 AVInputFormat iff_demuxer = { | |
319 "IFF", | |
3424
7a0230981402
Make long_names in lavf/lavdev optional depending on CONFIG_SMALL.
diego
parents:
3285
diff
changeset
|
320 NULL_IF_CONFIG_SMALL("IFF format"), |
3189 | 321 sizeof(IffDemuxContext), |
322 iff_probe, | |
323 iff_read_header, | |
324 iff_read_packet, | |
325 }; |