libavcodec/avs.c
26376701
 /*
  * AVS video decoder.
  * Copyright (c) 2006  Aurelien Jacobs <aurel@gnuage.org>
  *
b78e7197
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
26376701
  * 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.
26376701
  *
b78e7197
  * FFmpeg is distributed in the hope that it will be useful,
26376701
  * 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
e5a389a1
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26376701
  */
 
 #include "avcodec.h"
9106a698
 #include "get_bits.h"
759001c5
 #include "internal.h"
26376701
 
7f9f771e
 typedef struct AvsContext {
33329c6e
     AVFrame *frame;
e998ba4f
 } AvsContext;
26376701
 
 typedef enum {
     AVS_VIDEO     = 0x01,
     AVS_AUDIO     = 0x02,
     AVS_PALETTE   = 0x03,
     AVS_GAME_DATA = 0x04,
e998ba4f
 } AvsBlockType;
26376701
 
 typedef enum {
     AVS_I_FRAME     = 0x00,
     AVS_P_FRAME_3X3 = 0x01,
     AVS_P_FRAME_2X2 = 0x02,
     AVS_P_FRAME_2X3 = 0x03,
e998ba4f
 } AvsVideoSubType;
26376701
 
 
 static int
 avs_decode_frame(AVCodecContext * avctx,
df9b9567
                  void *data, int *got_frame, AVPacket *avpkt)
26376701
 {
7a00bbad
     const uint8_t *buf = avpkt->data;
7afe9e56
     const uint8_t *buf_end = avpkt->data + avpkt->size;
7a00bbad
     int buf_size = avpkt->size;
e998ba4f
     AvsContext *const avs = avctx->priv_data;
26376701
     AVFrame *picture = data;
33329c6e
     AVFrame *const p =  avs->frame;
ebc07904
     const uint8_t *table, *vect;
     uint8_t *out;
e83c1e2d
     int i, j, x, y, stride, ret, vect_w = 3, vect_h = 3;
e998ba4f
     AvsVideoSubType sub_type;
     AvsBlockType type;
76e65a1b
     GetBitContext change_map = {0}; //init to silence warning
26376701
 
1ec94b0f
     if ((ret = ff_reget_buffer(avctx, p)) < 0)
e83c1e2d
         return ret;
ce5e49b0
     p->pict_type = AV_PICTURE_TYPE_P;
26376701
     p->key_frame = 0;
 
33329c6e
     out    = p->data[0];
     stride = p->linesize[0];
26376701
 
7afe9e56
     if (buf_end - buf < 4)
         return AVERROR_INVALIDDATA;
26376701
     sub_type = buf[0];
     type = buf[1];
     buf += 4;
 
     if (type == AVS_PALETTE) {
         int first, last;
33329c6e
         uint32_t *pal = (uint32_t *) p->data[1];
26376701
 
fead30d4
         first = AV_RL16(buf);
         last = first + AV_RL16(buf + 2);
7afe9e56
         if (first >= 256 || last > 256 || buf_end - buf < 4 + 4 + 3 * (last - first))
             return AVERROR_INVALIDDATA;
26376701
         buf += 4;
7b40f46f
         for (i=first; i<last; i++, buf+=3) {
26376701
             pal[i] = (buf[0] << 18) | (buf[1] << 10) | (buf[2] << 2);
b12d92ef
             pal[i] |= 0xFFU << 24 | (pal[i] >> 6) & 0x30303;
7b40f46f
         }
26376701
 
         sub_type = buf[0];
         type = buf[1];
         buf += 4;
     }
 
     if (type != AVS_VIDEO)
e83c1e2d
         return AVERROR_INVALIDDATA;
26376701
 
     switch (sub_type) {
     case AVS_I_FRAME:
ce5e49b0
         p->pict_type = AV_PICTURE_TYPE_I;
26376701
         p->key_frame = 1;
     case AVS_P_FRAME_3X3:
         vect_w = 3;
         vect_h = 3;
         break;
 
     case AVS_P_FRAME_2X2:
         vect_w = 2;
         vect_h = 2;
         break;
 
     case AVS_P_FRAME_2X3:
         vect_w = 2;
         vect_h = 3;
         break;
 
     default:
e83c1e2d
       return AVERROR_INVALIDDATA;
26376701
     }
 
7afe9e56
     if (buf_end - buf < 256 * vect_w * vect_h)
         return AVERROR_INVALIDDATA;
26376701
     table = buf + (256 * vect_w * vect_h);
     if (sub_type != AVS_I_FRAME) {
         int map_size = ((318 / vect_w + 7) / 8) * (198 / vect_h);
7afe9e56
         if (buf_end - table < map_size)
             return AVERROR_INVALIDDATA;
e5e0580b
         init_get_bits(&change_map, table, map_size * 8);
26376701
         table += map_size;
     }
 
     for (y=0; y<198; y+=vect_h) {
         for (x=0; x<318; x+=vect_w) {
             if (sub_type == AVS_I_FRAME || get_bits1(&change_map)) {
7afe9e56
                 if (buf_end - table < 1)
                     return AVERROR_INVALIDDATA;
26376701
                 vect = &buf[*table++ * (vect_w * vect_h)];
                 for (j=0; j<vect_w; j++) {
                     out[(y + 0) * stride + x + j] = vect[(0 * vect_w) + j];
                     out[(y + 1) * stride + x + j] = vect[(1 * vect_w) + j];
                     if (vect_h == 3)
                         out[(y + 2) * stride + x + j] =
                             vect[(2 * vect_w) + j];
                 }
             }
         }
         if (sub_type != AVS_I_FRAME)
             align_get_bits(&change_map);
     }
 
33329c6e
     if ((ret = av_frame_ref(picture, p)) < 0)
759001c5
         return ret;
df9b9567
     *got_frame = 1;
26376701
 
     return buf_size;
 }
 
98a6fff9
 static av_cold int avs_decode_init(AVCodecContext * avctx)
26376701
 {
3b199d29
     AvsContext *s = avctx->priv_data;
33329c6e
 
     s->frame = av_frame_alloc();
     if (!s->frame)
         return AVERROR(ENOMEM);
 
716d413c
     avctx->pix_fmt = AV_PIX_FMT_PAL8;
33329c6e
 
c7384664
     return ff_set_dimensions(avctx, 318, 198);
26376701
 }
 
80dc7c01
 static av_cold int avs_decode_end(AVCodecContext *avctx)
 {
     AvsContext *s = avctx->priv_data;
33329c6e
     av_frame_free(&s->frame);
80dc7c01
     return 0;
 }
 
 
e7e2df27
 AVCodec ff_avs_decoder = {
ec6402b7
     .name           = "avs",
b2bed932
     .long_name      = NULL_IF_CONFIG_SMALL("AVS (Audio Video Standard) video"),
ec6402b7
     .type           = AVMEDIA_TYPE_VIDEO,
36ef5369
     .id             = AV_CODEC_ID_AVS,
ec6402b7
     .priv_data_size = sizeof(AvsContext),
     .init           = avs_decode_init,
     .decode         = avs_decode_frame,
80dc7c01
     .close          = avs_decode_end,
def97856
     .capabilities   = AV_CODEC_CAP_DR1,
91ed4e71
     .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
26376701
 };