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

Peter Ross pross at xvid.org
Sun Jul 22 07:21:55 CEST 2012


On Sun, Jul 22, 2012 at 03:31:34AM +0000, Paul B Mahol wrote:
> 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.

Tranforming an (already ugly) image demuxer into an image+video demuxer is always
going to be messy. But spliting up patches is never pointless; it simplifies the
review and improves utility of git-bitsect.

> ---
>  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");

Unrelated.

>          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++) {

The extradata to side_data changeover ought to have been done in a separate patch.

> @@ -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);

Ditto for the bytestream2 upgrade here.

>          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')

Is ANHD needed for playback?

> +#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))

Ok. But would have done this separately.

>          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;

Why s/data_size/chunk_size/g? and s/orig_pos/chunk_pos?  This adds a pile of text changes, that could have been done before after.

> +    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;

IFF_EXTRA_VIDEO_SIZE was require when the 9-byte header and palette were included in extradata.
Since this patch breaks compatbility with earlier LAVF/LAVCs, the value can be omitted, and
extradata_size used instead within libavcodec.

> -        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


In summary, I see at least three patches here:
 -  Unrelated/cosmetic/ident changes
 -  Big change to way header/palette info is passed between the demuxer and decoder
 -  Mods to handle the IFF ANIM loop
     (which btw, is the most interesting part, but obfuscated by the above).


Cheers,

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120722/bcf9f983/attachment.asc>


More information about the ffmpeg-devel mailing list