00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00032 #include "libavutil/intreadwrite.h"
00033 #include "avformat.h"
00034
00035 #define ID_8SVX MKTAG('8','S','V','X')
00036 #define ID_VHDR MKTAG('V','H','D','R')
00037 #define ID_ATAK MKTAG('A','T','A','K')
00038 #define ID_RLSE MKTAG('R','L','S','E')
00039 #define ID_CHAN MKTAG('C','H','A','N')
00040 #define ID_PBM MKTAG('P','B','M',' ')
00041 #define ID_ILBM MKTAG('I','L','B','M')
00042 #define ID_BMHD MKTAG('B','M','H','D')
00043 #define ID_CMAP MKTAG('C','M','A','P')
00044
00045 #define ID_FORM MKTAG('F','O','R','M')
00046 #define ID_ANNO MKTAG('A','N','N','O')
00047 #define ID_AUTH MKTAG('A','U','T','H')
00048 #define ID_CHRS MKTAG('C','H','R','S')
00049 #define ID_COPYRIGHT MKTAG('(','c',')',' ')
00050 #define ID_CSET MKTAG('C','S','E','T')
00051 #define ID_FVER MKTAG('F','V','E','R')
00052 #define ID_NAME MKTAG('N','A','M','E')
00053 #define ID_TEXT MKTAG('T','E','X','T')
00054 #define ID_BODY MKTAG('B','O','D','Y')
00055 #define ID_ANNO MKTAG('A','N','N','O')
00056
00057 #define LEFT 2
00058 #define RIGHT 4
00059 #define STEREO 6
00060
00061 #define PACKET_SIZE 1024
00062
00063 typedef enum {
00064 COMP_NONE,
00065 COMP_FIB,
00066 COMP_EXP
00067 } svx8_compression_type;
00068
00069 typedef enum {
00070 BITMAP_RAW,
00071 BITMAP_BYTERUN1
00072 } bitmap_compression_type;
00073
00074 typedef struct {
00075 uint64_t body_pos;
00076 uint32_t body_size;
00077 uint32_t sent_bytes;
00078 uint32_t audio_frame_count;
00079 } IffDemuxContext;
00080
00081
00082 static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size)
00083 {
00084 uint8_t *end = dest + size;
00085 size = size>>1;
00086
00087 while(dest < end) {
00088 *dest++ = *src;
00089 *dest++ = *(src+size);
00090 src++;
00091 }
00092 }
00093
00094
00095 static int get_metadata(AVFormatContext *s,
00096 const char *const tag,
00097 const unsigned data_size)
00098 {
00099 uint8_t *buf = ((data_size + 1) == 0) ? NULL : av_malloc(data_size + 1);
00100
00101 if (!buf)
00102 return AVERROR(ENOMEM);
00103
00104 if (avio_read(s->pb, buf, data_size) < 0) {
00105 av_free(buf);
00106 return AVERROR(EIO);
00107 }
00108 buf[data_size] = 0;
00109 av_metadata_set2(&s->metadata, tag, buf, AV_METADATA_DONT_STRDUP_VAL);
00110 return 0;
00111 }
00112
00113 static int iff_probe(AVProbeData *p)
00114 {
00115 const uint8_t *d = p->buf;
00116
00117 if ( AV_RL32(d) == ID_FORM &&
00118 (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM) )
00119 return AVPROBE_SCORE_MAX;
00120 return 0;
00121 }
00122
00123 static int iff_read_header(AVFormatContext *s,
00124 AVFormatParameters *ap)
00125 {
00126 IffDemuxContext *iff = s->priv_data;
00127 AVIOContext *pb = s->pb;
00128 AVStream *st;
00129 uint32_t chunk_id, data_size;
00130 int compression = -1;
00131
00132 st = av_new_stream(s, 0);
00133 if (!st)
00134 return AVERROR(ENOMEM);
00135
00136 st->codec->channels = 1;
00137 avio_seek(pb, 8, SEEK_CUR);
00138
00139 st->codec->codec_tag = avio_rl32(pb);
00140
00141 while(!url_feof(pb)) {
00142 uint64_t orig_pos;
00143 int res;
00144 const char *metadata_tag = NULL;
00145 chunk_id = avio_rl32(pb);
00146 data_size = avio_rb32(pb);
00147 orig_pos = avio_tell(pb);
00148
00149 switch(chunk_id) {
00150 case ID_VHDR:
00151 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00152
00153 if (data_size < 14)
00154 return AVERROR_INVALIDDATA;
00155 avio_seek(pb, 12, SEEK_CUR);
00156 st->codec->sample_rate = avio_rb16(pb);
00157 if (data_size >= 16) {
00158 avio_seek(pb, 1, SEEK_CUR);
00159 compression = avio_r8(pb);
00160 }
00161 break;
00162
00163 case ID_BODY:
00164 iff->body_pos = avio_tell(pb);
00165 iff->body_size = data_size;
00166 break;
00167
00168 case ID_CHAN:
00169 if (data_size < 4)
00170 return AVERROR_INVALIDDATA;
00171 st->codec->channels = (avio_rb32(pb) < 6) ? 1 : 2;
00172 break;
00173
00174 case ID_CMAP:
00175 st->codec->extradata_size = data_size;
00176 st->codec->extradata = av_malloc(data_size);
00177 if (!st->codec->extradata)
00178 return AVERROR(ENOMEM);
00179 if (avio_read(pb, st->codec->extradata, data_size) < 0)
00180 return AVERROR(EIO);
00181 break;
00182
00183 case ID_BMHD:
00184 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00185 if (data_size <= 8)
00186 return AVERROR_INVALIDDATA;
00187 st->codec->width = avio_rb16(pb);
00188 st->codec->height = avio_rb16(pb);
00189 avio_seek(pb, 4, SEEK_CUR);
00190 st->codec->bits_per_coded_sample = avio_r8(pb);
00191 if (data_size >= 11) {
00192 avio_seek(pb, 1, SEEK_CUR);
00193 compression = avio_r8(pb);
00194 }
00195 if (data_size >= 16) {
00196 avio_seek(pb, 3, SEEK_CUR);
00197 st->sample_aspect_ratio.num = avio_r8(pb);
00198 st->sample_aspect_ratio.den = avio_r8(pb);
00199 }
00200 break;
00201
00202 case ID_ANNO:
00203 case ID_TEXT:
00204 metadata_tag = "comment";
00205 break;
00206
00207 case ID_AUTH:
00208 metadata_tag = "artist";
00209 break;
00210
00211 case ID_COPYRIGHT:
00212 metadata_tag = "copyright";
00213 break;
00214
00215 case ID_NAME:
00216 metadata_tag = "title";
00217 break;
00218 }
00219
00220 if (metadata_tag) {
00221 if ((res = get_metadata(s, metadata_tag, data_size)) < 0) {
00222 av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!", metadata_tag);
00223 return res;
00224 }
00225 }
00226 avio_seek(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1), SEEK_CUR);
00227 }
00228
00229 avio_seek(pb, iff->body_pos, SEEK_SET);
00230
00231 switch(st->codec->codec_type) {
00232 case AVMEDIA_TYPE_AUDIO:
00233 av_set_pts_info(st, 32, 1, st->codec->sample_rate);
00234
00235 switch(compression) {
00236 case COMP_NONE:
00237 st->codec->codec_id = CODEC_ID_PCM_S8;
00238 break;
00239 case COMP_FIB:
00240 st->codec->codec_id = CODEC_ID_8SVX_FIB;
00241 break;
00242 case COMP_EXP:
00243 st->codec->codec_id = CODEC_ID_8SVX_EXP;
00244 break;
00245 default:
00246 av_log(s, AV_LOG_ERROR, "unknown compression method\n");
00247 return -1;
00248 }
00249
00250 st->codec->bits_per_coded_sample = 8;
00251 st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample;
00252 st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
00253 break;
00254
00255 case AVMEDIA_TYPE_VIDEO:
00256 switch (compression) {
00257 case BITMAP_RAW:
00258 st->codec->codec_id = CODEC_ID_IFF_ILBM;
00259 break;
00260 case BITMAP_BYTERUN1:
00261 st->codec->codec_id = CODEC_ID_IFF_BYTERUN1;
00262 break;
00263 default:
00264 av_log(s, AV_LOG_ERROR, "unknown compression method\n");
00265 return AVERROR_INVALIDDATA;
00266 }
00267 break;
00268 default:
00269 return -1;
00270 }
00271
00272 return 0;
00273 }
00274
00275 static int iff_read_packet(AVFormatContext *s,
00276 AVPacket *pkt)
00277 {
00278 IffDemuxContext *iff = s->priv_data;
00279 AVIOContext *pb = s->pb;
00280 AVStream *st = s->streams[0];
00281 int ret;
00282
00283 if(iff->sent_bytes >= iff->body_size)
00284 return AVERROR(EIO);
00285
00286 if(st->codec->channels == 2) {
00287 uint8_t sample_buffer[PACKET_SIZE];
00288
00289 ret = avio_read(pb, sample_buffer, PACKET_SIZE);
00290 if(av_new_packet(pkt, PACKET_SIZE) < 0) {
00291 av_log(s, AV_LOG_ERROR, "cannot allocate packet\n");
00292 return AVERROR(ENOMEM);
00293 }
00294 interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE);
00295 } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00296 ret = av_get_packet(pb, pkt, iff->body_size);
00297 } else {
00298 ret = av_get_packet(pb, pkt, PACKET_SIZE);
00299 }
00300
00301 if(iff->sent_bytes == 0)
00302 pkt->flags |= AV_PKT_FLAG_KEY;
00303
00304 if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00305 iff->sent_bytes += PACKET_SIZE;
00306 } else {
00307 iff->sent_bytes = iff->body_size;
00308 }
00309 pkt->stream_index = 0;
00310 if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00311 pkt->pts = iff->audio_frame_count;
00312 iff->audio_frame_count += ret / st->codec->channels;
00313 }
00314 return ret;
00315 }
00316
00317 AVInputFormat ff_iff_demuxer = {
00318 "IFF",
00319 NULL_IF_CONFIG_SMALL("IFF format"),
00320 sizeof(IffDemuxContext),
00321 iff_probe,
00322 iff_read_header,
00323 iff_read_packet,
00324 };