OLD | NEW |
1 /* | 1 /* |
2 * IFF (.iff) file demuxer | 2 * IFF (.iff) file demuxer |
3 * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> | 3 * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net> |
| 4 * Copyright (c) 2010 Peter Ross <pross@xvid.org> |
4 * | 5 * |
5 * This file is part of FFmpeg. | 6 * This file is part of FFmpeg. |
6 * | 7 * |
7 * FFmpeg is free software; you can redistribute it and/or | 8 * FFmpeg is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
9 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
10 * version 2.1 of the License, or (at your option) any later version. | 11 * version 2.1 of the License, or (at your option) any later version. |
11 * | 12 * |
12 * FFmpeg is distributed in the hope that it will be useful, | 13 * FFmpeg is distributed in the hope that it will be useful, |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 * Lesser General Public License for more details. | 16 * Lesser General Public License for more details. |
16 * | 17 * |
17 * You should have received a copy of the GNU Lesser General Public | 18 * You should have received a copy of the GNU Lesser General Public |
18 * License along with FFmpeg; if not, write to the Free Software | 19 * License along with FFmpeg; if not, write to the Free Software |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 */ | 21 */ |
21 | 22 |
22 /** | 23 /** |
23 * @file libavformat/iff.c | 24 * @file libavformat/iff.c |
24 * IFF file demuxer | 25 * IFF file demuxer |
25 * by Jaikrishnan Menon | 26 * by Jaikrishnan Menon |
26 * for more information on the .iff file format, visit: | 27 * for more information on the .iff file format, visit: |
27 * http://wiki.multimedia.cx/index.php?title=IFF | 28 * http://wiki.multimedia.cx/index.php?title=IFF |
28 */ | 29 */ |
29 | 30 |
30 #include "libavutil/intreadwrite.h" | 31 #include "libavutil/intreadwrite.h" |
| 32 #include "libavcodec/iff.h" |
31 #include "avformat.h" | 33 #include "avformat.h" |
32 | 34 |
33 #define ID_8SVX MKTAG('8','S','V','X') | 35 #define ID_8SVX MKTAG('8','S','V','X') |
34 #define ID_VHDR MKTAG('V','H','D','R') | 36 #define ID_VHDR MKTAG('V','H','D','R') |
35 #define ID_ATAK MKTAG('A','T','A','K') | 37 #define ID_ATAK MKTAG('A','T','A','K') |
36 #define ID_RLSE MKTAG('R','L','S','E') | 38 #define ID_RLSE MKTAG('R','L','S','E') |
37 #define ID_CHAN MKTAG('C','H','A','N') | 39 #define ID_CHAN MKTAG('C','H','A','N') |
| 40 #define ID_PBM MKTAG('P','B','M',' ') |
| 41 #define ID_ILBM MKTAG('I','L','B','M') |
| 42 #define ID_BMHD MKTAG('B','M','H','D') |
| 43 #define ID_CMAP MKTAG('C','M','A','P') |
38 | 44 |
39 #define ID_FORM MKTAG('F','O','R','M') | 45 #define ID_FORM MKTAG('F','O','R','M') |
40 #define ID_ANNO MKTAG('A','N','N','O') | 46 #define ID_ANNO MKTAG('A','N','N','O') |
41 #define ID_AUTH MKTAG('A','U','T','H') | 47 #define ID_AUTH MKTAG('A','U','T','H') |
42 #define ID_CHRS MKTAG('C','H','R','S') | 48 #define ID_CHRS MKTAG('C','H','R','S') |
43 #define ID_COPYRIGHT MKTAG('(','c',')',' ') | 49 #define ID_COPYRIGHT MKTAG('(','c',')',' ') |
44 #define ID_CSET MKTAG('C','S','E','T') | 50 #define ID_CSET MKTAG('C','S','E','T') |
45 #define ID_FVER MKTAG('F','V','E','R') | 51 #define ID_FVER MKTAG('F','V','E','R') |
46 #define ID_NAME MKTAG('N','A','M','E') | 52 #define ID_NAME MKTAG('N','A','M','E') |
47 #define ID_TEXT MKTAG('T','E','X','T') | 53 #define ID_TEXT MKTAG('T','E','X','T') |
48 #define ID_BODY MKTAG('B','O','D','Y') | 54 #define ID_BODY MKTAG('B','O','D','Y') |
| 55 #define ID_ANNO MKTAG('A','N','N','O') |
49 | 56 |
50 #define LEFT 2 | 57 #define LEFT 2 |
51 #define RIGHT 4 | 58 #define RIGHT 4 |
52 #define STEREO 6 | 59 #define STEREO 6 |
53 | 60 |
54 #define PACKET_SIZE 1024 | 61 #define PACKET_SIZE 1024 |
55 | 62 |
56 typedef enum {COMP_NONE, COMP_FIB, COMP_EXP} svx8_compression_type; | 63 typedef enum {COMP_NONE, COMP_FIB, COMP_EXP} svx8_compression_type; |
| 64 typedef enum {BITMAP_RAW, BITMAP_BYTERUN1} bitmap_compression_type; |
57 | 65 |
58 typedef struct { | 66 typedef struct { |
59 uint32_t body_size; | 67 uint32_t body_size; |
60 uint32_t sent_bytes; | 68 uint32_t sent_bytes; |
61 uint32_t audio_frame_count; | 69 uint32_t audio_frame_count; |
62 } IffDemuxContext; | 70 } IffDemuxContext; |
63 | 71 |
64 | 72 |
65 static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size) | 73 static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size) |
66 { | 74 { |
67 uint8_t *end = dest + size; | 75 uint8_t *end = dest + size; |
68 size = size>>1; | 76 size = size>>1; |
69 | 77 |
70 while(dest < end) { | 78 while(dest < end) { |
71 *dest++ = *src; | 79 *dest++ = *src; |
72 *dest++ = *(src+size); | 80 *dest++ = *(src+size); |
73 src++; | 81 src++; |
74 } | 82 } |
75 } | 83 } |
76 | 84 |
77 static int iff_probe(AVProbeData *p) | 85 static int iff_probe(AVProbeData *p) |
78 { | 86 { |
79 const uint8_t *d = p->buf; | 87 const uint8_t *d = p->buf; |
80 | 88 |
81 if ( AV_RL32(d) == ID_FORM && | 89 if ( AV_RL32(d) == ID_FORM && |
82 AV_RL32(d+8) == ID_8SVX) | 90 (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == I
D_ILBM) ) |
83 return AVPROBE_SCORE_MAX; | 91 return AVPROBE_SCORE_MAX; |
84 return 0; | 92 return 0; |
85 } | 93 } |
86 | 94 |
87 static int iff_read_header(AVFormatContext *s, | 95 static int iff_read_header(AVFormatContext *s, |
88 AVFormatParameters *ap) | 96 AVFormatParameters *ap) |
89 { | 97 { |
90 IffDemuxContext *iff = s->priv_data; | 98 IffDemuxContext *iff = s->priv_data; |
91 ByteIOContext *pb = s->pb; | 99 ByteIOContext *pb = s->pb; |
92 AVStream *st; | 100 AVStream *st; |
93 uint32_t chunk_id, data_size; | 101 uint32_t chunk_id, data_size; |
94 int padding, done = 0; | 102 int padding, done = 0; |
| 103 int compression = -1; |
| 104 char *buf; |
95 | 105 |
96 st = av_new_stream(s, 0); | 106 st = av_new_stream(s, 0); |
97 if (!st) | 107 if (!st) |
98 return AVERROR(ENOMEM); | 108 return AVERROR(ENOMEM); |
99 | 109 |
100 st->codec->channels = 1; | 110 st->codec->channels = 1; |
101 url_fskip(pb, 12); | 111 url_fskip(pb, 8); |
| 112 // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and i
nterlaced (ILBM) content |
| 113 st->codec->codec_tag = get_le32(pb); |
102 | 114 |
103 while(!done && !url_feof(pb)) { | 115 while(!done && !url_feof(pb)) { |
104 chunk_id = get_le32(pb); | 116 chunk_id = get_le32(pb); |
105 data_size = get_be32(pb); | 117 data_size = get_be32(pb); |
106 padding = data_size & 1; | 118 padding = data_size & 1; |
107 | 119 |
108 switch(chunk_id) { | 120 switch(chunk_id) { |
109 case ID_VHDR: | 121 case ID_VHDR: |
| 122 st->codec->codec_type = CODEC_TYPE_AUDIO; |
110 url_fskip(pb, 12); | 123 url_fskip(pb, 12); |
111 st->codec->sample_rate = get_be16(pb); | 124 st->codec->sample_rate = get_be16(pb); |
112 url_fskip(pb, 1); | 125 url_fskip(pb, 1); |
113 st->codec->codec_tag = get_byte(pb); | 126 compression = get_byte(pb); |
114 url_fskip(pb, 4); | 127 url_fskip(pb, 4); |
115 break; | 128 break; |
116 | 129 |
117 case ID_BODY: | 130 case ID_BODY: |
118 iff->body_size = data_size; | 131 iff->body_size = data_size; |
119 done = 1; | 132 done = 1; |
120 break; | 133 break; |
121 | 134 |
122 case ID_CHAN: | 135 case ID_CHAN: |
123 st->codec->channels = (get_be32(pb) < 6) ? 1 : 2; | 136 st->codec->channels = (get_be32(pb) < 6) ? 1 : 2; |
124 break; | 137 break; |
125 | 138 |
| 139 case ID_CMAP: |
| 140 st->codec->extradata_size = data_size; |
| 141 st->codec->extradata = av_malloc(data_size); |
| 142 if (!st->codec->extradata) |
| 143 return AVERROR(ENOMEM); |
| 144 if (get_buffer(pb, st->codec->extradata, data_size) < 0) |
| 145 return AVERROR(EIO); |
| 146 break; |
| 147 |
| 148 case ID_BMHD: |
| 149 st->codec->codec_type = CODEC_TYPE_VIDEO; |
| 150 st->codec->width = get_be16(pb); |
| 151 st->codec->height = get_be16(pb); |
| 152 url_fskip(pb, 4); // x, y offset |
| 153 st->codec->bits_per_coded_sample = get_byte(pb); |
| 154 url_fskip(pb, 1); // masking |
| 155 compression = get_byte(pb); |
| 156 url_fskip(pb, 3); // paddding, transparent |
| 157 st->sample_aspect_ratio.num = get_byte(pb); |
| 158 st->sample_aspect_ratio.den = get_byte(pb); |
| 159 url_fskip(pb, 4); // source page width, height |
| 160 break; |
| 161 |
| 162 case ID_ANNO: |
| 163 buf = av_malloc(data_size + 1); |
| 164 if (!buf) |
| 165 break; |
| 166 get_buffer(pb, buf, data_size); |
| 167 buf[data_size] = 0; |
| 168 av_metadata_set2(&s->metadata, "comment", buf, AV_METADATA_DONT_STRD
UP_VAL); |
| 169 break; |
| 170 |
126 default: | 171 default: |
127 url_fseek(pb, data_size + padding, SEEK_CUR); | 172 url_fseek(pb, data_size + padding, SEEK_CUR); |
128 break; | 173 break; |
129 } | 174 } |
130 } | 175 } |
131 | 176 |
132 if(!st->codec->sample_rate) | 177 switch(st->codec->codec_type) { |
133 return AVERROR_INVALIDDATA; | 178 case CODEC_TYPE_AUDIO: |
| 179 av_set_pts_info(st, 32, 1, st->codec->sample_rate); |
134 | 180 |
135 av_set_pts_info(st, 32, 1, st->codec->sample_rate); | 181 switch(compression) { |
136 st->codec->codec_type = CODEC_TYPE_AUDIO; | |
137 | |
138 switch(st->codec->codec_tag) { | |
139 case COMP_NONE: | 182 case COMP_NONE: |
140 st->codec->codec_id = CODEC_ID_PCM_S8; | 183 st->codec->codec_id = CODEC_ID_PCM_S8; |
141 break; | 184 break; |
142 case COMP_FIB: | 185 case COMP_FIB: |
143 st->codec->codec_id = CODEC_ID_8SVX_FIB; | 186 st->codec->codec_id = CODEC_ID_8SVX_FIB; |
144 break; | 187 break; |
145 case COMP_EXP: | 188 case COMP_EXP: |
146 st->codec->codec_id = CODEC_ID_8SVX_EXP; | 189 st->codec->codec_id = CODEC_ID_8SVX_EXP; |
147 break; | 190 break; |
148 default: | 191 default: |
149 av_log(s, AV_LOG_ERROR, "iff: unknown compression method\n"); | 192 av_log(s, AV_LOG_ERROR, "iff: unknown compression method\n"); |
150 return -1; | 193 return -1; |
151 } | 194 } |
152 | 195 |
153 st->codec->bits_per_coded_sample = 8; | 196 st->codec->bits_per_coded_sample = 8; |
154 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->cod
ec->bits_per_coded_sample; | 197 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->cod
ec->bits_per_coded_sample; |
155 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sam
ple; | 198 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sam
ple; |
| 199 break; |
| 200 |
| 201 case CODEC_TYPE_VIDEO: |
| 202 switch (compression) { |
| 203 case BITMAP_RAW: |
| 204 if (st->codec->codec_tag == ID_ILBM) { |
| 205 st->codec->codec_id = CODEC_ID_IFF_ILBM; |
| 206 } else { |
| 207 st->codec->codec_id = CODEC_ID_RAWVIDEO; |
| 208 st->codec->pix_fmt = PIX_FMT_PAL8; |
| 209 st->codec->codec_tag = 0; |
| 210 } |
| 211 break; |
| 212 case BITMAP_BYTERUN1: |
| 213 st->codec->codec_id = CODEC_ID_IFF_BYTERUN1; |
| 214 break; |
| 215 default: |
| 216 av_log(s, AV_LOG_ERROR, "unknown compression method\n"); |
| 217 return AVERROR_INVALIDDATA; |
| 218 } |
| 219 break; |
| 220 default: |
| 221 return -1; |
| 222 } |
156 | 223 |
157 return 0; | 224 return 0; |
158 } | 225 } |
159 | 226 |
160 static int iff_read_packet(AVFormatContext *s, | 227 static int iff_read_packet(AVFormatContext *s, |
161 AVPacket *pkt) | 228 AVPacket *pkt) |
162 { | 229 { |
163 IffDemuxContext *iff = s->priv_data; | 230 IffDemuxContext *iff = s->priv_data; |
164 ByteIOContext *pb = s->pb; | 231 ByteIOContext *pb = s->pb; |
| 232 AVStream *st = s->streams[0]; |
165 int ret; | 233 int ret; |
166 | 234 |
167 if(iff->sent_bytes > iff->body_size) | 235 if(iff->sent_bytes >= iff->body_size) |
168 return AVERROR(EIO); | 236 return AVERROR(EIO); |
169 | 237 |
170 if(s->streams[0]->codec->channels == 2) { | 238 if(s->streams[0]->codec->channels == 2) { |
171 uint8_t sample_buffer[PACKET_SIZE]; | 239 uint8_t sample_buffer[PACKET_SIZE]; |
172 | 240 |
173 ret = get_buffer(pb, sample_buffer, PACKET_SIZE); | 241 ret = get_buffer(pb, sample_buffer, PACKET_SIZE); |
174 if(av_new_packet(pkt, PACKET_SIZE) < 0) { | 242 if(av_new_packet(pkt, PACKET_SIZE) < 0) { |
175 av_log(s, AV_LOG_ERROR, "iff: cannot allocate packet \n"); | 243 av_log(s, AV_LOG_ERROR, "iff: cannot allocate packet \n"); |
176 return AVERROR(ENOMEM); | 244 return AVERROR(ENOMEM); |
177 } | 245 } |
178 interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE); | 246 interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE); |
179 } | 247 } else if (s->streams[0]->codec->codec_id == CODEC_ID_RAWVIDEO) { |
180 else { | 248 if(av_new_packet(pkt, iff->body_size + AVPALETTE_SIZE) < 0) { |
| 249 return AVERROR(ENOMEM); |
| 250 } |
| 251 |
| 252 ret = ff_cmap_read_palette(st->codec, (uint32_t*)(pkt->data + iff->body_
size)); |
| 253 if (ret < 0) |
| 254 return ret; |
| 255 av_freep(&st->codec->extradata); |
| 256 st->codec->extradata_size = 0; |
| 257 |
| 258 ret = get_buffer(pb, pkt->data, iff->body_size); |
| 259 } else if (s->streams[0]->codec->codec_type == CODEC_TYPE_VIDEO) { |
| 260 ret = av_get_packet(pb, pkt, iff->body_size); |
| 261 } else { |
181 ret = av_get_packet(pb, pkt, PACKET_SIZE); | 262 ret = av_get_packet(pb, pkt, PACKET_SIZE); |
182 } | 263 } |
183 | 264 |
184 if(iff->sent_bytes == 0) | 265 if(iff->sent_bytes == 0) |
185 pkt->flags |= PKT_FLAG_KEY; | 266 pkt->flags |= PKT_FLAG_KEY; |
186 | 267 |
187 iff->sent_bytes += PACKET_SIZE; | 268 if(s->streams[0]->codec->codec_type == CODEC_TYPE_AUDIO) { |
| 269 iff->sent_bytes += PACKET_SIZE; |
| 270 } else { |
| 271 iff->sent_bytes = iff->body_size; |
| 272 } |
188 pkt->stream_index = 0; | 273 pkt->stream_index = 0; |
189 pkt->pts = iff->audio_frame_count; | 274 if(s->streams[0]->codec->codec_type == CODEC_TYPE_AUDIO) { |
190 iff->audio_frame_count += ret / s->streams[0]->codec->channels; | 275 pkt->pts = iff->audio_frame_count; |
| 276 iff->audio_frame_count += ret / s->streams[0]->codec->channels; |
| 277 } |
191 return ret; | 278 return ret; |
192 } | 279 } |
193 | 280 |
194 AVInputFormat iff_demuxer = { | 281 AVInputFormat iff_demuxer = { |
195 "IFF", | 282 "IFF", |
196 NULL_IF_CONFIG_SMALL("IFF format"), | 283 NULL_IF_CONFIG_SMALL("IFF format"), |
197 sizeof(IffDemuxContext), | 284 sizeof(IffDemuxContext), |
198 iff_probe, | 285 iff_probe, |
199 iff_read_header, | 286 iff_read_header, |
200 iff_read_packet, | 287 iff_read_packet, |
201 }; | 288 }; |
OLD | NEW |