[FFmpeg-devel] [RFC] [PATCH] iff: ANIM suppport

Paul B Mahol onemda at gmail.com
Sun Jul 22 05:31:34 CEST 2012


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
Currently only first frame is decoded correctly.

The reason I post this patch is to show why rewritting code is required.

No, I do not plan to separate this patch in smaller patches because it
is mostly pointless.
---
 libavcodec/iff.c  |  161 ++++++++++--------------
 libavformat/iff.c |  359 +++++++++++++++++++++++++++++------------------------
 2 files changed, 261 insertions(+), 259 deletions(-)

diff --git a/libavcodec/iff.c b/libavcodec/iff.c
index 57ce570..c8f2339 100644
--- a/libavcodec/iff.c
+++ b/libavcodec/iff.c
@@ -42,6 +42,7 @@ typedef struct {
     AVFrame frame;
     int planesize;
     uint8_t * planebuf;
+    int       planebuf_size;
     uint8_t * ham_buf;      ///< temporary buffer for planar to chunky conversation
     uint32_t *ham_palbuf;   ///< HAM decode table
     uint32_t *mask_buf;     ///< temporary buffer for palette indices
@@ -52,7 +53,6 @@ typedef struct {
     unsigned  flags;        ///< 1 for EHB, 0 is no extra half darkening
     unsigned  transparency; ///< TODO: transparency color index in palette
     unsigned  masking;      ///< TODO: masking method used
-    int init; // 1 if buffer and palette data already initialized, 0 otherwise
 } IffContext;
 
 #define LUT8_PART(plane, v)                             \
@@ -135,22 +135,28 @@ static av_always_inline uint32_t gray2rgb(const uint32_t x) {
 }
 
 /**
- * Convert CMAP buffer (stored in extradata) to lavc palette format
+ * Convert CMAP buffer (stored in packet side data) to lavc palette format
  */
-static int ff_cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
+static int ff_cmap_read_palette(AVCodecContext *avctx, AVPacket *avpkt, uint32_t *pal)
 {
     IffContext *s = avctx->priv_data;
     int count, i;
-    const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
-    int palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
+    const uint8_t *palette;
+    int palette_size;
+
+    if (avpkt->side_data_elems <= 0 ||
+        avpkt->side_data[0].type != AV_PKT_DATA_PALETTE)
+        return AVERROR_INVALIDDATA;
 
+    palette      = avpkt->side_data[0].data;
+    palette_size = avpkt->side_data[0].size;
     if (avctx->bits_per_coded_sample > 8) {
-        av_log(avctx, AV_LOG_ERROR, "bit_per_coded_sample > 8 not supported\n");
+        av_log(avctx, AV_LOG_ERROR, "bits_per_coded_sample > 8 not supported\n");
         return AVERROR_INVALIDDATA;
     }
 
     count = 1 << avctx->bits_per_coded_sample;
-    // If extradata is smaller than actually needed, fill the remaining with black.
+    // If palette_size is smaller than actually needed, fill the remaining with black.
     count = FFMIN(palette_size / 3, count);
     if (count) {
         for (i=0; i < count; i++) {
@@ -187,49 +193,54 @@ static int ff_cmap_read_palette(AVCodecContext *avctx, uint32_t *pal)
  * @return 0 in case of success, a negative error code otherwise
  */
 static int extract_header(AVCodecContext *const avctx,
-                          const AVPacket *const avpkt) {
-    const uint8_t *buf;
+                          const AVPacket *const avpkt)
+{
+    const uint8_t *palette;
     unsigned buf_size;
     IffContext *s = avctx->priv_data;
-    int palette_size;
+    int palette_size = 0;
+    GetByteContext gb;
+
+    s->planesize = FFALIGN(avctx->width, 16) >> 3; // Align plane size in bits to word-boundary
+    av_fast_padded_malloc(&s->planebuf, &s->planebuf_size, s->planesize + FF_INPUT_BUFFER_PADDING_SIZE);
+    if (!s->planebuf)
+        return AVERROR(ENOMEM);
 
-    if (avctx->extradata_size < 2) {
-        av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
+    s->bpp = avctx->bits_per_coded_sample;
+    if (avpkt->size < 2)
         return AVERROR_INVALIDDATA;
+
+    if (avpkt->side_data_elems > 0 &&
+        avpkt->side_data[0].type == AV_PKT_DATA_PALETTE) {
+        palette_size = avpkt->side_data[0].size;
+        palette      = avpkt->side_data[0].data;
     }
-    palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
 
-    if (avpkt) {
-        int image_size;
-        if (avpkt->size < 2)
-            return AVERROR_INVALIDDATA;
-        image_size = avpkt->size - AV_RB16(avpkt->data);
-        buf = avpkt->data;
-        buf_size = bytestream_get_be16(&buf);
-        if (buf_size <= 1 || image_size <= 1) {
-            av_log(avctx, AV_LOG_ERROR,
-                   "Invalid image size received: %u -> image data offset: %d\n",
-                   buf_size, image_size);
-            return AVERROR_INVALIDDATA;
-        }
+    if (avctx->bits_per_coded_sample <= 8) {
+        avctx->pix_fmt = avctx->bits_per_coded_sample < 8 ||
+                         palette_size ? PIX_FMT_PAL8 : PIX_FMT_GRAY8;
+    } else if (avctx->bits_per_coded_sample <= 32) {
+        if (avctx->codec_tag != MKTAG('D','E','E','P'))
+            avctx->pix_fmt = PIX_FMT_BGR32;
     } else {
-        buf = avctx->extradata;
-        buf_size = bytestream_get_be16(&buf);
-        if (buf_size <= 1 || palette_size < 0) {
-            av_log(avctx, AV_LOG_ERROR,
-                   "Invalid palette size received: %u -> palette data offset: %d\n",
-                   buf_size, palette_size);
-            return AVERROR_INVALIDDATA;
-        }
+        return AVERROR_INVALIDDATA;
+    }
+
+    bytestream2_init(&gb, avctx->extradata, avctx->extradata_size);
+    buf_size = bytestream2_get_be16(&gb);
+    if (buf_size <= 1) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Invalid image size received: %u\n", buf_size);
+        return AVERROR_INVALIDDATA;
     }
 
     if (buf_size > 8) {
-        s->compression  = bytestream_get_byte(&buf);
-        s->bpp          = bytestream_get_byte(&buf);
-        s->ham          = bytestream_get_byte(&buf);
-        s->flags        = bytestream_get_byte(&buf);
-        s->transparency = bytestream_get_be16(&buf);
-        s->masking      = bytestream_get_byte(&buf);
+        s->compression  = bytestream2_get_byte(&gb);
+        s->bpp          = bytestream2_get_byte(&gb);
+        s->ham          = bytestream2_get_byte(&gb);
+        s->flags        = bytestream2_get_byte(&gb);
+        s->transparency = bytestream2_get_be16(&gb);
+        s->masking      = bytestream2_get_byte(&gb);
         if (s->masking == MASK_HAS_MASK) {
             if (s->bpp >= 8) {
                 avctx->pix_fmt = PIX_FMT_RGB32;
@@ -263,7 +274,6 @@ static int extract_header(AVCodecContext *const avctx,
         if (s->ham) {
             int i, count = FFMIN(palette_size / 3, 1 << s->ham);
             int ham_count;
-            const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata);
 
             s->ham_buf = av_malloc((s->planesize * 8) + FF_INPUT_BUFFER_PADDING_SIZE);
             if (!s->ham_buf)
@@ -313,36 +323,8 @@ static int extract_header(AVCodecContext *const avctx,
 static av_cold int decode_init(AVCodecContext *avctx)
 {
     IffContext *s = avctx->priv_data;
-    int err;
-
-    if (avctx->bits_per_coded_sample <= 8) {
-        int palette_size;
-
-        if (avctx->extradata_size >= 2)
-            palette_size = avctx->extradata_size - AV_RB16(avctx->extradata);
-        else
-            palette_size = 0;
-        avctx->pix_fmt = (avctx->bits_per_coded_sample < 8) ||
-                         (avctx->extradata_size >= 2 && palette_size) ? PIX_FMT_PAL8 : PIX_FMT_GRAY8;
-    } else if (avctx->bits_per_coded_sample <= 32) {
-        if (avctx->codec_tag != MKTAG('D','E','E','P'))
-            avctx->pix_fmt = PIX_FMT_BGR32;
-    } else {
-        return AVERROR_INVALIDDATA;
-    }
 
-    if ((err = av_image_check_size(avctx->width, avctx->height, 0, avctx)))
-        return err;
-    s->planesize = FFALIGN(avctx->width, 16) >> 3; // Align plane size in bits to word-boundary
-    s->planebuf = av_malloc(s->planesize + FF_INPUT_BUFFER_PADDING_SIZE);
-    if (!s->planebuf)
-        return AVERROR(ENOMEM);
-
-    s->bpp = avctx->bits_per_coded_sample;
     avcodec_get_frame_defaults(&s->frame);
-
-    if ((err = extract_header(avctx, NULL)) < 0)
-        return err;
     s->frame.reference = 3;
 
     return 0;
@@ -467,27 +449,22 @@ static int decode_frame_ilbm(AVCodecContext *avctx,
                             AVPacket *avpkt)
 {
     IffContext *s = avctx->priv_data;
-    const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL;
-    const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0;
+    const uint8_t *buf = avpkt->data;
+    const int buf_size = avpkt->size;
     const uint8_t *buf_end = buf+buf_size;
     int y, plane, res;
 
     if ((res = extract_header(avctx, avpkt)) < 0)
         return res;
 
-    if (s->init) {
-        if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
-            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
-            return res;
-        }
-    } else if ((res = avctx->get_buffer(avctx, &s->frame)) < 0) {
-        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+    if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
         return res;
-    } else if (avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == PIX_FMT_PAL8) {
-        if ((res = ff_cmap_read_palette(avctx, (uint32_t*)s->frame.data[1])) < 0)
+    }
+    if (avctx->bits_per_coded_sample <= 8 && avctx->pix_fmt == PIX_FMT_PAL8) {
+        if ((res = ff_cmap_read_palette(avctx, avpkt, (uint32_t*)s->frame.data[1])) < 0)
             return res;
     }
-    s->init = 1;
 
     if (avctx->codec_tag == MKTAG('A','C','B','M')) {
         if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) {
@@ -585,29 +562,25 @@ static int decode_frame_byterun1(AVCodecContext *avctx,
                             AVPacket *avpkt)
 {
     IffContext *s = avctx->priv_data;
-    const uint8_t *buf = avpkt->size >= 2 ? avpkt->data + AV_RB16(avpkt->data) : NULL;
-    const int buf_size = avpkt->size >= 2 ? avpkt->size - AV_RB16(avpkt->data) : 0;
+    const uint8_t *buf = avpkt->data;
+    const int buf_size = avpkt->size;
     const uint8_t *buf_end = buf+buf_size;
     int y, plane, res;
 
     if ((res = extract_header(avctx, avpkt)) < 0)
         return res;
-    if (s->init) {
-        if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
-            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
-            return res;
-        }
-    } else if ((res = avctx->get_buffer(avctx, &s->frame)) < 0) {
-        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+
+    if ((res = avctx->reget_buffer(avctx, &s->frame)) < 0) {
+        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
         return res;
-    } else if (avctx->pix_fmt == PIX_FMT_PAL8) {
-        if ((res = ff_cmap_read_palette(avctx, (uint32_t*)s->frame.data[1])) < 0)
+    }
+    if (avctx->pix_fmt == PIX_FMT_PAL8) {
+        if ((res = ff_cmap_read_palette(avctx, avpkt, (uint32_t*)s->frame.data[1])) < 0)
             return res;
     } else if (avctx->pix_fmt == PIX_FMT_RGB32 && avctx->bits_per_coded_sample <= 8) {
-        if ((res = ff_cmap_read_palette(avctx, s->mask_palbuf)) < 0)
+        if ((res = ff_cmap_read_palette(avctx, avpkt, s->mask_palbuf)) < 0)
             return res;
     }
-    s->init = 1;
 
     if (avctx->codec_tag == MKTAG('I','L','B','M')) { //interleaved
         if (avctx->pix_fmt == PIX_FMT_PAL8 || avctx->pix_fmt == PIX_FMT_GRAY8) {
diff --git a/libavformat/iff.c b/libavformat/iff.c
index cd3d5be..d9b043a 100644
--- a/libavformat/iff.c
+++ b/libavformat/iff.c
@@ -61,6 +61,9 @@
 #define ID_BODY       MKTAG('B','O','D','Y')
 #define ID_DBOD       MKTAG('D','B','O','D')
 #define ID_DPEL       MKTAG('D','P','E','L')
+#define ID_ANIM       MKTAG('A','N','I','M')
+#define ID_ANHD       MKTAG('A','N','H','D')
+#define ID_DLTA       MKTAG('D','L','T','A')
 
 #define LEFT    2
 #define RIGHT   4
@@ -70,9 +73,7 @@
  * This number of bytes if added at the beginning of each AVPacket
  * which contain additional information about video properties
  * which has to be shared between demuxer and decoder.
- * This number may change between frames, e.g. the demuxer might
- * set it to smallest possible size of 2 to indicate that there's
- * no extradata changing in this frame.
+ * This number may change between frames.
  */
 #define IFF_EXTRA_VIDEO_SIZE 9
 
@@ -88,16 +89,10 @@ typedef enum {
 } bitmap_compression_type;
 
 typedef struct {
-    uint64_t  body_pos;
-    uint32_t  body_size;
-    uint32_t  sent_bytes;
-    svx8_compression_type   svx8_compression;
-    bitmap_compression_type bitmap_compression;  ///< delta compression method used
-    unsigned  bpp;          ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
-    unsigned  ham;          ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
-    unsigned  flags;        ///< 1 for EHB, 0 is no extra half darkening
-    unsigned  transparency; ///< transparency color index in palette
-    unsigned  masking;      ///< masking method used
+    int       tag;
+    uint32_t  form_size;
+    uint8_t   *palette;
+    int       palette_size;
 } IffDemuxContext;
 
 /* Metadata string read */
@@ -119,12 +114,27 @@ static int get_metadata(AVFormatContext *s,
     return 0;
 }
 
+static int create_stream(AVFormatContext *s, AVStream **st)
+{
+    if (*st)
+        return AVERROR_INVALIDDATA;
+    *st = avformat_new_stream(s, NULL);
+    if (!*st)
+        return AVERROR(ENOMEM);
+    return 0;
+}
+
 static int iff_probe(AVProbeData *p)
 {
     const uint8_t *d = p->buf;
 
-    if ( AV_RL32(d)   == ID_FORM &&
-         (AV_RL32(d+8) == ID_8SVX || AV_RL32(d+8) == ID_PBM || AV_RL32(d+8) == ID_ACBM || AV_RL32(d+8) == ID_DEEP || AV_RL32(d+8) == ID_ILBM) )
+    if ( AV_RL32(d)   == ID_FORM  &&
+        (AV_RL32(d+8) == ID_8SVX  ||
+         AV_RL32(d+8) == ID_PBM   ||
+         AV_RL32(d+8) == ID_ACBM  ||
+         AV_RL32(d+8) == ID_DEEP  ||
+         AV_RL32(d+8) == ID_ILBM  ||
+         AV_RL32(d+8) == ID_ANIM))
         return AVPROBE_SCORE_MAX;
     return 0;
 }
@@ -136,127 +146,178 @@ static int iff_read_header(AVFormatContext *s)
 {
     IffDemuxContext *iff = s->priv_data;
     AVIOContext *pb = s->pb;
-    AVStream *st;
+    s->ctx_flags |= AVFMTCTX_NOHEADER;
+
+    if (avio_rl32(pb) != ID_FORM)
+        return AVERROR_INVALIDDATA;
+    iff->form_size = avio_rb32(pb);
+
+    iff->tag = avio_rl32(pb);
+    if (iff->tag == ID_ANIM) {
+        if (avio_rl32(pb) != ID_FORM)
+            return AVERROR_INVALIDDATA;
+        iff->form_size = avio_rb32(pb);
+        iff->tag = avio_rl32(pb);
+        if (iff->tag != ID_ILBM)
+            return AVERROR_INVALIDDATA;
+    }
+
+    return 0;
+}
+
+static int iff_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    bitmap_compression_type bitmap_compression;  ///< delta compression method used
+    unsigned  bpp;          ///< bits per plane to decode (differs from bits_per_coded_sample if HAM)
+    unsigned  ham;          ///< 0 if non-HAM or number of hold bits (6 for bpp > 6, 4 otherwise)
+    unsigned  flags;        ///< 1 for EHB, 0 is no extra half darkening
+    unsigned  transparency = 0; ///< transparency color index in palette
+    IffDemuxContext *iff = s->priv_data;
+    AVIOContext *pb = s->pb;
+    AVStream *st = NULL;
     uint8_t *buf;
-    uint32_t chunk_id, data_size;
+    uint32_t chunk_id, chunk_size, palette_size = 0;
+    uint64_t chunk_pos;
     uint32_t screenmode = 0;
-    unsigned transparency = 0;
     unsigned masking = 0; // no mask
     uint8_t fmt[16];
-    int fmt_size;
-
-    st = avformat_new_stream(s, NULL);
-    if (!st)
-        return AVERROR(ENOMEM);
+    int tag, ret, compr = 0, fmt_size, channels = 1;
 
-    st->codec->channels = 1;
-    avio_skip(pb, 8);
-    // codec_tag used by ByteRun1 decoder to distinguish progressive (PBM) and interlaced (ILBM) content
-    st->codec->codec_tag = avio_rl32(pb);
+    tag = iff->tag;
+    if (url_feof(pb))
+        return AVERROR_EOF;
 
-    while(!url_feof(pb)) {
-        uint64_t orig_pos;
-        int res;
+    while (!url_feof(pb)) {
         const char *metadata_tag = NULL;
-        chunk_id = avio_rl32(pb);
-        data_size = avio_rb32(pb);
-        orig_pos = avio_tell(pb);
+
+        chunk_id   = avio_rl32(pb);
+        chunk_size = avio_rb32(pb);
+        chunk_pos  = avio_tell(pb);
 
         switch(chunk_id) {
+        case ID_FORM:
+            iff->tag = avio_rl32(pb);
+            goto done;
         case ID_VHDR:
-            st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
-
-            if (data_size < 14)
+            if (chunk_size < 14)
                 return AVERROR_INVALIDDATA;
+            if ((ret = create_stream(s, &st)) < 0)
+                return ret;
+            st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
             avio_skip(pb, 12);
             st->codec->sample_rate = avio_rb16(pb);
-            if (data_size >= 16) {
+            if (chunk_size >= 16) {
                 avio_skip(pb, 1);
-                iff->svx8_compression = avio_r8(pb);
+                compr = avio_r8(pb);
             }
+            switch (compr) {
+            case COMP_NONE:
+                st->codec->codec_id = CODEC_ID_PCM_S8_PLANAR;
+                break;
+            case COMP_FIB:
+                st->codec->codec_id = CODEC_ID_8SVX_FIB;
+                break;
+            case COMP_EXP:
+                st->codec->codec_id = CODEC_ID_8SVX_EXP;
+                break;
+            default:
+                av_log(s, AV_LOG_ERROR,
+                       "Unknown SVX8 compression method '%d'\n", compr);
+                return AVERROR_INVALIDDATA;
+            }
+            st->codec->bits_per_coded_sample = compr == COMP_NONE ? 8 : 4;
+            avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate);
             break;
 
         case ID_ABIT:
         case ID_BODY:
         case ID_DBOD:
-            iff->body_pos = avio_tell(pb);
-            iff->body_size = data_size;
+            pkt->flags |= AV_PKT_FLAG_KEY;
+        case ID_DLTA:
+            av_get_packet(pb, pkt, chunk_size);
             break;
 
         case ID_CHAN:
-            if (data_size < 4)
+            if (chunk_size < 4)
                 return AVERROR_INVALIDDATA;
-            st->codec->channels = (avio_rb32(pb) < 6) ? 1 : 2;
+            channels = (avio_rb32(pb) < 6) ? 1 : 2;
             break;
 
         case ID_CAMG:
-            if (data_size < 4)
+            if (chunk_size < 4)
                 return AVERROR_INVALIDDATA;
-            screenmode                = avio_rb32(pb);
+            screenmode = avio_rb32(pb);
             break;
 
         case ID_CMAP:
-            st->codec->extradata_size = data_size + IFF_EXTRA_VIDEO_SIZE;
-            st->codec->extradata      = av_malloc(data_size + IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
-            if (!st->codec->extradata)
+            palette_size = chunk_size;
+            av_fast_padded_malloc(&iff->palette, &iff->palette_size, palette_size);
+            if (!iff->palette)
                 return AVERROR(ENOMEM);
-            if (avio_read(pb, st->codec->extradata + IFF_EXTRA_VIDEO_SIZE, data_size) < 0)
+            if (avio_read(pb, iff->palette, palette_size) != palette_size)
                 return AVERROR(EIO);
             break;
 
         case ID_BMHD:
-            iff->bitmap_compression = -1;
+            if ((ret = create_stream(s, &st)) < 0)
+                return ret;
+            bitmap_compression = -1;
             st->codec->codec_type            = AVMEDIA_TYPE_VIDEO;
-            if (data_size <= 8)
+            if (chunk_size <= 8)
                 return AVERROR_INVALIDDATA;
             st->codec->width                 = avio_rb16(pb);
             st->codec->height                = avio_rb16(pb);
             avio_skip(pb, 4); // x, y offset
             st->codec->bits_per_coded_sample = avio_r8(pb);
-            if (data_size >= 10)
+            if (chunk_size >= 10)
                 masking                      = avio_r8(pb);
-            if (data_size >= 11)
-                iff->bitmap_compression      = avio_r8(pb);
-            if (data_size >= 14) {
+            if (chunk_size >= 11)
+                bitmap_compression           = avio_r8(pb);
+            if (chunk_size >= 14) {
                 avio_skip(pb, 1); // padding
                 transparency                 = avio_rb16(pb);
             }
-            if (data_size >= 16) {
+            if (chunk_size >= 16) {
                 st->sample_aspect_ratio.num  = avio_r8(pb);
                 st->sample_aspect_ratio.den  = avio_r8(pb);
             }
             break;
 
         case ID_DPEL:
-            if (data_size < 4 || (data_size & 3))
+            if (!st)
+                return AVERROR_INVALIDDATA;
+            if (chunk_size < 16 || (chunk_size & 3))
                 return AVERROR_INVALIDDATA;
             if ((fmt_size = avio_read(pb, fmt, sizeof(fmt))) < 0)
                 return fmt_size;
-            if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24)))
+            if (fmt_size == sizeof(deep_rgb24) && !memcmp(fmt, deep_rgb24, sizeof(deep_rgb24))) {
                 st->codec->pix_fmt = PIX_FMT_RGB24;
-            else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba)))
+                st->codec->bits_per_coded_sample = 24;
+            } else if (fmt_size == sizeof(deep_rgba) && !memcmp(fmt, deep_rgba, sizeof(deep_rgba))) {
                 st->codec->pix_fmt = PIX_FMT_RGBA;
-            else {
+                st->codec->bits_per_coded_sample = 32;
+            } else {
                 av_log_ask_for_sample(s, "unsupported color format\n");
                 return AVERROR_PATCHWELCOME;
             }
             break;
 
         case ID_DGBL:
-            st->codec->codec_type            = AVMEDIA_TYPE_VIDEO;
-            if (data_size < 8)
+            if ((ret = create_stream(s, &st)) < 0)
+                return ret;
+            st->codec->codec_type       = AVMEDIA_TYPE_VIDEO;
+            if (chunk_size < 8)
                 return AVERROR_INVALIDDATA;
-            st->codec->width                 = avio_rb16(pb);
-            st->codec->height                = avio_rb16(pb);
-            iff->bitmap_compression          = avio_rb16(pb);
-            if (iff->bitmap_compression != 0) {
+            st->codec->width            = avio_rb16(pb);
+            st->codec->height           = avio_rb16(pb);
+            bitmap_compression          = avio_rb16(pb);
+            if (bitmap_compression) {
                 av_log(s, AV_LOG_ERROR,
-                       "compression %i not supported\n", iff->bitmap_compression);
+                       "compression %i not supported\n", bitmap_compression);
                 return AVERROR_PATCHWELCOME;
             }
-            st->sample_aspect_ratio.num      = avio_r8(pb);
-            st->sample_aspect_ratio.den      = avio_r8(pb);
-            st->codec->bits_per_coded_sample = 24;
+            st->sample_aspect_ratio.num = avio_r8(pb);
+            st->sample_aspect_ratio.den = avio_r8(pb);
             break;
 
         case ID_ANNO:
@@ -264,122 +325,89 @@ static int iff_read_header(AVFormatContext *s)
         case ID_AUTH:      metadata_tag = "artist";    break;
         case ID_COPYRIGHT: metadata_tag = "copyright"; break;
         case ID_NAME:      metadata_tag = "title";     break;
+        default:
+            av_log(s, AV_LOG_DEBUG, "unsupported chunk id: %X\n", chunk_id);
         }
 
         if (metadata_tag) {
-            if ((res = get_metadata(s, metadata_tag, data_size)) < 0) {
-                av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!", metadata_tag);
-                return res;
+            if ((ret = get_metadata(s, metadata_tag, chunk_size)) < 0) {
+                av_log(s, AV_LOG_ERROR, "cannot allocate metadata tag %s!\n", metadata_tag);
+                return ret;
             }
         }
-        avio_skip(pb, data_size - (avio_tell(pb) - orig_pos) + (data_size & 1));
+        avio_skip(pb, chunk_size - (avio_tell(pb) - chunk_pos) + (chunk_size & 1));
     }
 
-    avio_seek(pb, iff->body_pos, SEEK_SET);
-
-    switch(st->codec->codec_type) {
-    case AVMEDIA_TYPE_AUDIO:
-        avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate);
-
-        switch (iff->svx8_compression) {
-        case COMP_NONE:
-            st->codec->codec_id = CODEC_ID_PCM_S8_PLANAR;
-            break;
-        case COMP_FIB:
-            st->codec->codec_id = CODEC_ID_8SVX_FIB;
+done:
+    if (!s->nb_streams)
+        return AVERROR_INVALIDDATA;
+    if (st) {
+        switch(st->codec->codec_type) {
+        case AVMEDIA_TYPE_AUDIO:
+            st->codec->channels = channels;
+            st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample;
+            st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
             break;
-        case COMP_EXP:
-            st->codec->codec_id = CODEC_ID_8SVX_EXP;
-            break;
-        default:
-            av_log(s, AV_LOG_ERROR,
-                   "Unknown SVX8 compression method '%d'\n", iff->svx8_compression);
-            return -1;
-        }
 
-        st->codec->bits_per_coded_sample = iff->svx8_compression == COMP_NONE ? 8 : 4;
-        st->codec->bit_rate = st->codec->channels * st->codec->sample_rate * st->codec->bits_per_coded_sample;
-        st->codec->block_align = st->codec->channels * st->codec->bits_per_coded_sample;
-        break;
+        case AVMEDIA_TYPE_VIDEO:
+            bpp     = st->codec->bits_per_coded_sample;
+            if ((screenmode & 0x800 /* Hold And Modify */) && bpp <= 8) {
+                ham = bpp > 6 ? 6 : 4;
+                st->codec->bits_per_coded_sample = 24;
+            } else {
+                ham = 0;
+            }
+            flags   = (screenmode & 0x80 /* Extra HalfBrite */) && bpp <= 8;
 
-    case AVMEDIA_TYPE_VIDEO:
-        iff->bpp          = st->codec->bits_per_coded_sample;
-        if ((screenmode & 0x800 /* Hold And Modify */) && iff->bpp <= 8) {
-            iff->ham      = iff->bpp > 6 ? 6 : 4;
-            st->codec->bits_per_coded_sample = 24;
-        }
-        iff->flags        = (screenmode & 0x80 /* Extra HalfBrite */) && iff->bpp <= 8;
-        iff->masking      = masking;
-        iff->transparency = transparency;
+            if (!st->codec->extradata) {
+                st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE;
+                st->codec->extradata      = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
+                if (!st->codec->extradata)
+                    return AVERROR(ENOMEM);
+            }
+            buf = st->codec->extradata;
+            bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE);
+            bytestream_put_byte(&buf, bitmap_compression);
+            bytestream_put_byte(&buf, bpp);
+            bytestream_put_byte(&buf, ham);
+            bytestream_put_byte(&buf, flags);
+            bytestream_put_be16(&buf, transparency);
+            bytestream_put_byte(&buf, masking);
+            st->codec->codec_tag = tag;
 
-        if (!st->codec->extradata) {
-            st->codec->extradata_size = IFF_EXTRA_VIDEO_SIZE;
-            st->codec->extradata      = av_malloc(IFF_EXTRA_VIDEO_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
-            if (!st->codec->extradata)
-                return AVERROR(ENOMEM);
-        }
-        buf = st->codec->extradata;
-        bytestream_put_be16(&buf, IFF_EXTRA_VIDEO_SIZE);
-        bytestream_put_byte(&buf, iff->bitmap_compression);
-        bytestream_put_byte(&buf, iff->bpp);
-        bytestream_put_byte(&buf, iff->ham);
-        bytestream_put_byte(&buf, iff->flags);
-        bytestream_put_be16(&buf, iff->transparency);
-        bytestream_put_byte(&buf, iff->masking);
+            if (palette_size) {
+                uint8_t *npal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, palette_size);
+                if (!npal) {
+                    return AVERROR(ENOMEM);
+                }
+                memcpy(npal, iff->palette, palette_size);
+            }
 
-        switch (iff->bitmap_compression) {
-        case BITMAP_RAW:
-            st->codec->codec_id = CODEC_ID_IFF_ILBM;
-            break;
-        case BITMAP_BYTERUN1:
-            st->codec->codec_id = CODEC_ID_IFF_BYTERUN1;
+            switch (bitmap_compression) {
+            case BITMAP_RAW:
+                st->codec->codec_id = CODEC_ID_IFF_ILBM;
+                break;
+            case BITMAP_BYTERUN1:
+                st->codec->codec_id = CODEC_ID_IFF_BYTERUN1;
+                break;
+            default:
+                av_log(s, AV_LOG_ERROR,
+                    "Unknown bitmap compression method '%d'\n", bitmap_compression);
+                return AVERROR_INVALIDDATA;
+            }
             break;
-        default:
-            av_log(s, AV_LOG_ERROR,
-                   "Unknown bitmap compression method '%d'\n", iff->bitmap_compression);
-            return AVERROR_INVALIDDATA;
         }
-        break;
-    default:
-        return -1;
     }
 
-    return 0;
+    pkt->stream_index = 0;
+    return pkt->size;
 }
 
-static int iff_read_packet(AVFormatContext *s,
-                           AVPacket *pkt)
+static int iff_read_close(AVFormatContext *s)
 {
     IffDemuxContext *iff = s->priv_data;
-    AVIOContext *pb = s->pb;
-    AVStream *st = s->streams[0];
-    int ret;
-
-    if(iff->sent_bytes >= iff->body_size)
-        return AVERROR_EOF;
-
-    if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
-        ret = av_get_packet(pb, pkt, iff->body_size);
-    } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-        uint8_t *buf;
-
-        if (av_new_packet(pkt, iff->body_size + 2) < 0) {
-            return AVERROR(ENOMEM);
-        }
-
-        buf = pkt->data;
-        bytestream_put_be16(&buf, 2);
-        ret = avio_read(pb, buf, iff->body_size);
-    } else {
-        av_abort();
-    }
-
-    if(iff->sent_bytes == 0)
-        pkt->flags |= AV_PKT_FLAG_KEY;
-    iff->sent_bytes = iff->body_size;
-
-    pkt->stream_index = 0;
-    return ret;
+    av_freep(&iff->palette);
+    return 0;
 }
 
 AVInputFormat ff_iff_demuxer = {
@@ -389,4 +417,5 @@ AVInputFormat ff_iff_demuxer = {
     .read_probe     = iff_probe,
     .read_header    = iff_read_header,
     .read_packet    = iff_read_packet,
+    .read_close     = iff_read_close,
 };
-- 
1.7.7



More information about the ffmpeg-devel mailing list