libavcodec/aasc.c
589f8220
 /*
a9f1d8cd
  * Autodesk RLE Decoder
41ed7ab4
  * Copyright (C) 2005 The FFmpeg project
589f8220
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
589f8220
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
b78e7197
  * version 2.1 of the License, or (at your option) any later version.
589f8220
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
589f8220
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
b78e7197
  * License along with FFmpeg; if not, write to the Free Software
5509bffa
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
589f8220
  */
 
 /**
ba87f080
  * @file
a9f1d8cd
  * Autodesk RLE Video Decoder by Konstantin Shishkov
589f8220
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "avcodec.h"
759001c5
 #include "internal.h"
44aa9771
 #include "msrledec.h"
589f8220
 
 typedef struct AascContext {
     AVCodecContext *avctx;
992f71e9
     GetByteContext gb;
759001c5
     AVFrame *frame;
bd971dda
 
     uint32_t palette[AVPALETTE_COUNT];
     int palette_size;
589f8220
 } AascContext;
 
98a6fff9
 static av_cold int aasc_decode_init(AVCodecContext *avctx)
589f8220
 {
e4141433
     AascContext *s = avctx->priv_data;
bd971dda
     uint8_t *ptr;
     int i;
589f8220
 
     s->avctx = avctx;
718b90d4
     switch (avctx->bits_per_coded_sample) {
bd971dda
     case 8:
ac627b3d
         avctx->pix_fmt = AV_PIX_FMT_PAL8;
bd971dda
 
         ptr = avctx->extradata;
         s->palette_size = FFMIN(avctx->extradata_size, AVPALETTE_SIZE);
         for (i = 0; i < s->palette_size / 4; i++) {
             s->palette[i] = 0xFFU << 24 | AV_RL32(ptr);
             ptr += 4;
         }
         break;
718b90d4
     case 16:
51e9d2db
         avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
718b90d4
         break;
     case 24:
ac627b3d
         avctx->pix_fmt = AV_PIX_FMT_BGR24;
718b90d4
         break;
     default:
         av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth: %d\n", avctx->bits_per_coded_sample);
         return -1;
     }
589f8220
 
759001c5
     s->frame = av_frame_alloc();
     if (!s->frame)
         return AVERROR(ENOMEM);
589f8220
 
     return 0;
 }
 
 static int aasc_decode_frame(AVCodecContext *avctx,
df9b9567
                               void *data, int *got_frame,
7a00bbad
                               AVPacket *avpkt)
589f8220
 {
7a00bbad
     const uint8_t *buf = avpkt->data;
c64cf2a3
     int buf_size       = avpkt->size;
     AascContext *s     = avctx->priv_data;
61904467
     int compr, i, stride, psize, ret;
589f8220
 
e1631f8e
     if (buf_size < 4) {
         av_log(avctx, AV_LOG_ERROR, "frame too short\n");
         return AVERROR_INVALIDDATA;
     }
 
1ec94b0f
     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
18009e60
         return ret;
589f8220
 
c64cf2a3
     compr     = AV_RL32(buf);
     buf      += 4;
56da1fd7
     buf_size -= 4;
8a57ca5c
     psize = avctx->bits_per_coded_sample / 8;
4d378776
     switch (avctx->codec_tag) {
     case MKTAG('A', 'A', 'S', '4'):
         bytestream2_init(&s->gb, buf - 4, buf_size + 4);
d3cc258a
         ff_msrle_decode(avctx, s->frame, 8, &s->gb);
4d378776
         break;
     case MKTAG('A', 'A', 'S', 'C'):
c64cf2a3
     switch (compr) {
56da1fd7
     case 0:
8a57ca5c
         stride = (avctx->width * psize + psize) & ~psize;
62b1e3b1
         if (buf_size < stride * avctx->height)
             return AVERROR_INVALIDDATA;
c64cf2a3
         for (i = avctx->height - 1; i >= 0; i--) {
80e9e63c
             memcpy(s->frame->data[0] + i * s->frame->linesize[0], buf, avctx->width * psize);
56da1fd7
             buf += stride;
be5db700
             buf_size -= stride;
56da1fd7
         }
         break;
     case 1:
e7117f1c
         bytestream2_init(&s->gb, buf, buf_size);
3496cec4
         ff_msrle_decode(avctx, s->frame, 8, &s->gb);
56da1fd7
         break;
     default:
         av_log(avctx, AV_LOG_ERROR, "Unknown compression type %d\n", compr);
18009e60
         return AVERROR_INVALIDDATA;
56da1fd7
     }
4d378776
         break;
     default:
         av_log(avctx, AV_LOG_ERROR, "Unknown FourCC: %X\n", avctx->codec_tag);
         return -1;
     }
589f8220
 
ac627b3d
     if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
80e9e63c
         memcpy(s->frame->data[1], s->palette, s->palette_size);
bd971dda
 
df9b9567
     *got_frame = 1;
759001c5
     if ((ret = av_frame_ref(data, s->frame)) < 0)
         return ret;
589f8220
 
     /* report that the buffer was completely consumed */
0be54ad2
     return avpkt->size;
589f8220
 }
 
98a6fff9
 static av_cold int aasc_decode_end(AVCodecContext *avctx)
589f8220
 {
e4141433
     AascContext *s = avctx->priv_data;
589f8220
 
759001c5
     av_frame_free(&s->frame);
589f8220
 
     return 0;
 }
 
e7e2df27
 AVCodec ff_aasc_decoder = {
ec6402b7
     .name           = "aasc",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("Autodesk RLE"),
ec6402b7
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_AASC,
ec6402b7
     .priv_data_size = sizeof(AascContext),
     .init           = aasc_decode_init,
     .close          = aasc_decode_end,
     .decode         = aasc_decode_frame,
def97856
     .capabilities   = AV_CODEC_CAP_DR1,
91ed4e71
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
589f8220
 };