• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/iff.c

Go to the documentation of this file.
00001 /*
00002  * IFF (.iff) file demuxer
00003  * Copyright (c) 2008 Jaikrishnan Menon <realityman@gmx.net>
00004  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
00005  * Copyright (c) 2010 Sebastian Vater <cdgs.basty@googlemail.com>
00006  *
00007  * This file is part of FFmpeg.
00008  *
00009  * FFmpeg is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * FFmpeg is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with FFmpeg; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00022  */
00023 
00032 #include "libavutil/intreadwrite.h"
00033 #include "libavcodec/iff.h"
00034 #include "avformat.h"
00035 
00036 #define ID_8SVX       MKTAG('8','S','V','X')
00037 #define ID_VHDR       MKTAG('V','H','D','R')
00038 #define ID_ATAK       MKTAG('A','T','A','K')
00039 #define ID_RLSE       MKTAG('R','L','S','E')
00040 #define ID_CHAN       MKTAG('C','H','A','N')
00041 #define ID_PBM        MKTAG('P','B','M',' ')
00042 #define ID_ILBM       MKTAG('I','L','B','M')
00043 #define ID_BMHD       MKTAG('B','M','H','D')
00044 #define ID_CMAP       MKTAG('C','M','A','P')
00045 
00046 #define ID_FORM       MKTAG('F','O','R','M')
00047 #define ID_ANNO       MKTAG('A','N','N','O')
00048 #define ID_AUTH       MKTAG('A','U','T','H')
00049 #define ID_CHRS       MKTAG('C','H','R','S')
00050 #define ID_COPYRIGHT  MKTAG('(','c',')',' ')
00051 #define ID_CSET       MKTAG('C','S','E','T')
00052 #define ID_FVER       MKTAG('F','V','E','R')
00053 #define ID_NAME       MKTAG('N','A','M','E')
00054 #define ID_TEXT       MKTAG('T','E','X','T')
00055 #define ID_BODY       MKTAG('B','O','D','Y')
00056 #define ID_ANNO       MKTAG('A','N','N','O')
00057 
00058 #define LEFT    2
00059 #define RIGHT   4
00060 #define STEREO  6
00061 
00062 #define PACKET_SIZE 1024
00063 
00064 typedef enum {
00065     COMP_NONE,
00066     COMP_FIB,
00067     COMP_EXP
00068 } svx8_compression_type;
00069 
00070 typedef enum {
00071     BITMAP_RAW,
00072     BITMAP_BYTERUN1
00073 } bitmap_compression_type;
00074 
00075 typedef struct {
00076     uint64_t  body_pos;
00077     uint32_t  body_size;
00078     uint32_t  sent_bytes;
00079     uint32_t  audio_frame_count;
00080 } IffDemuxContext;
00081 
00082 
00083 static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size)
00084 {
00085     uint8_t *end = dest + size;
00086     size = size>>1;
00087 
00088     while(dest < end) {
00089         *dest++ = *src;
00090         *dest++ = *(src+size);
00091         src++;
00092     }
00093 }
00094 
00095 static int iff_probe(AVProbeData *p)
00096 {
00097     const uint8_t *d = p->buf;
00098 
00099     if ( AV_RL32(d)   == ID_FORM &&
00100          (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ILBM) )
00101         return AVPROBE_SCORE_MAX;
00102     return 0;
00103 }
00104 
00105 static int iff_read_header(AVFormatContext *s,
00106                            AVFormatParameters *ap)
00107 {
00108     IffDemuxContext *iff = s->priv_data;
00109     ByteIOContext *pb = s->pb;
00110     AVStream *st;
00111     uint32_t chunk_id, data_size;
00112     int compression = -1;
00113     char *buf;
00114 
00115     st = av_new_stream(s, 0);
00116     if (!st)
00117         return AVERROR(ENOMEM);
00118 
00119     st->codec->channels = 1;
00120     url_fskip(pb, 8);
00121     // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
00122     st->codec->codec_tag = get_le32(pb);
00123 
00124     while(!url_feof(pb)) {
00125         uint64_t orig_pos;
00126         chunk_id = get_le32(pb);
00127         data_size = get_be32(pb);
00128         orig_pos = url_ftell(pb);
00129 
00130         switch(chunk_id) {
00131         case ID_VHDR:
00132             st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00133 
00134             if (data_size < 14)
00135                 return AVERROR_INVALIDDATA;
00136             url_fskip(pb, 12);
00137             st->codec->sample_rate = get_be16(pb);
00138             if (data_size >= 16) {
00139                 url_fskip(pb, 1);
00140                 compression        = get_byte(pb);
00141             }
00142             break;
00143 
00144         case ID_BODY:
00145             iff->body_pos = url_ftell(pb);
00146             iff->body_size = data_size;
00147             break;
00148 
00149         case ID_CHAN:
00150             if (data_size < 4)
00151                 return AVERROR_INVALIDDATA;
00152             st->codec->channels = (get_be32(pb) < 6) ? 1 : 2;
00153             break;
00154 
00155         case ID_CMAP:
00156             st->codec->extradata_size = data_size;
00157             st->codec->extradata      = av_malloc(data_size);
00158             if (!st->codec->extradata)
00159                 return AVERROR(ENOMEM);
00160             if (get_buffer(pb, st->codec->extradata, data_size) < 0)
00161                 return AVERROR(EIO);
00162             break;
00163 
00164         case ID_BMHD:
00165             st->codec->codec_type            = AVMEDIA_TYPE_VIDEO;
00166             if (data_size <= 8)
00167                 return AVERROR_INVALIDDATA;
00168             st->codec->width                 = get_be16(pb);
00169             st->codec->height                = get_be16(pb);
00170             url_fskip(pb, 4); // x, y offset
00171             st->codec->bits_per_coded_sample = get_byte(pb);
00172             if (data_size >= 11) {
00173                 url_fskip(pb, 1); // masking
00174                 compression                  = get_byte(pb);
00175             }
00176             if (data_size >= 16) {
00177                 url_fskip(pb, 3); // paddding, transparent
00178                 st->sample_aspect_ratio.num  = get_byte(pb);
00179                 st->sample_aspect_ratio.den  = get_byte(pb);
00180             }
00181             break;
00182 
00183         case ID_ANNO:
00184             buf = av_malloc(data_size + 1);
00185             if (!buf)
00186                 break;
00187             get_buffer(pb, buf, data_size);
00188             buf[data_size] = 0;
00189             av_metadata_set2(&s->metadata, "comment", buf, AV_METADATA_DONT_STRDUP_VAL);
00190             break;
00191         }
00192 
00193         url_fskip(pb, data_size - (url_ftell(pb) - orig_pos) + (data_size & 1));
00194     }
00195 
00196     url_fseek(pb, iff->body_pos, SEEK_SET);
00197 
00198     switch(st->codec->codec_type) {
00199     case AVMEDIA_TYPE_AUDIO:
00200         av_set_pts_info(st, 32, 1, st->codec->sample_rate);
00201 
00202         switch(compression) {
00203         case COMP_NONE:
00204             st->codec->codec_id = CODEC_ID_PCM_S8;
00205             break;
00206         case COMP_FIB:
00207             st->codec->codec_id = CODEC_ID_8SVX_FIB;
00208             break;
00209         case COMP_EXP:
00210             st->codec->codec_id = CODEC_ID_8SVX_EXP;
00211             break;
00212         default:
00213             av_log(s, AV_LOG_ERROR, "iff: unknown compression method\n");
00214             return -1;
00215         }
00216 
00217         st->codec->bits_per_coded_sample = 8;
00218         st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample;
00219         st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
00220         break;
00221 
00222     case AVMEDIA_TYPE_VIDEO:
00223         switch (compression) {
00224         case BITMAP_RAW:
00225             if (st->codec->codec_tag == ID_ILBM) {
00226                 st->codec->codec_id = CODEC_ID_IFF_ILBM;
00227             } else {
00228                 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00229                 st->codec->pix_fmt  = PIX_FMT_PAL8;
00230                 st->codec->codec_tag = 0;
00231             }
00232             break;
00233         case BITMAP_BYTERUN1:
00234             st->codec->codec_id = CODEC_ID_IFF_BYTERUN1;
00235             break;
00236         default:
00237             av_log(s, AV_LOG_ERROR, "unknown compression method\n");
00238             return AVERROR_INVALIDDATA;
00239         }
00240         break;
00241     default:
00242         return -1;
00243     }
00244 
00245     return 0;
00246 }
00247 
00248 static int iff_read_packet(AVFormatContext *s,
00249                            AVPacket *pkt)
00250 {
00251     IffDemuxContext *iff = s->priv_data;
00252     ByteIOContext *pb = s->pb;
00253     AVStream *st = s->streams[0];
00254     int ret;
00255 
00256     if(iff->sent_bytes >= iff->body_size)
00257         return AVERROR(EIO);
00258 
00259     if(s->streams[0]->codec->channels == 2) {
00260         uint8_t sample_buffer[PACKET_SIZE];
00261 
00262         ret = get_buffer(pb, sample_buffer, PACKET_SIZE);
00263         if(av_new_packet(pkt, PACKET_SIZE) < 0) {
00264             av_log(s, AV_LOG_ERROR, "iff: cannot allocate packet \n");
00265             return AVERROR(ENOMEM);
00266         }
00267         interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE);
00268     } else if (s->streams[0]->codec->codec_id == CODEC_ID_RAWVIDEO) {
00269         if(av_new_packet(pkt, iff->body_size + AVPALETTE_SIZE) < 0) {
00270             return AVERROR(ENOMEM);
00271         }
00272 
00273         ret = ff_cmap_read_palette(st->codec, (uint32_t*)(pkt->data + iff->body_size));
00274         if (ret < 0)
00275             return ret;
00276         av_freep(&st->codec->extradata);
00277         st->codec->extradata_size = 0;
00278 
00279         ret = get_buffer(pb, pkt->data, iff->body_size);
00280     } else if (s->streams[0]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
00281         ret = av_get_packet(pb, pkt, iff->body_size);
00282     } else {
00283         ret = av_get_packet(pb, pkt, PACKET_SIZE);
00284     }
00285 
00286     if(iff->sent_bytes == 0)
00287         pkt->flags |= AV_PKT_FLAG_KEY;
00288 
00289     if(s->streams[0]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00290         iff->sent_bytes += PACKET_SIZE;
00291     } else {
00292         iff->sent_bytes = iff->body_size;
00293     }
00294     pkt->stream_index = 0;
00295     if(s->streams[0]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
00296         pkt->pts = iff->audio_frame_count;
00297         iff->audio_frame_count += ret / s->streams[0]->codec->channels;
00298     }
00299     return ret;
00300 }
00301 
00302 AVInputFormat iff_demuxer = {
00303     "IFF",
00304     NULL_IF_CONFIG_SMALL("IFF format"),
00305     sizeof(IffDemuxContext),
00306     iff_probe,
00307     iff_read_header,
00308     iff_read_packet,
00309 };

Generated on Fri Sep 16 2011 17:17:37 for FFmpeg by  doxygen 1.7.1