Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Bethesda VID video decoder
  3.  * Copyright (C) 2007 Nicholas Tung
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * @brief Bethesda Softworks VID Video Decoder
  25.  * @author Nicholas Tung [ntung (at. ntung com] (2007-03)
  26.  * @see http://wiki.multimedia.cx/index.php?title=Bethsoft_VID
  27.  * @see http://www.svatopluk.com/andux/docs/dfvid.html
  28.  */
  29.  
  30. #include "libavutil/common.h"
  31. #include "avcodec.h"
  32. #include "bethsoftvideo.h"
  33. #include "bytestream.h"
  34. #include "internal.h"
  35.  
  36. typedef struct BethsoftvidContext {
  37.     AVFrame frame;
  38.     GetByteContext g;
  39. } BethsoftvidContext;
  40.  
  41. static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
  42. {
  43.     BethsoftvidContext *vid = avctx->priv_data;
  44.     avcodec_get_frame_defaults(&vid->frame);
  45.     avctx->pix_fmt = AV_PIX_FMT_PAL8;
  46.     return 0;
  47. }
  48.  
  49. static int set_palette(BethsoftvidContext *ctx)
  50. {
  51.     uint32_t *palette = (uint32_t *)ctx->frame.data[1];
  52.     int a;
  53.  
  54.     if (bytestream2_get_bytes_left(&ctx->g) < 256*3)
  55.         return AVERROR_INVALIDDATA;
  56.  
  57.     for(a = 0; a < 256; a++){
  58.         palette[a] = 0xFFU << 24 | bytestream2_get_be24u(&ctx->g) * 4;
  59.         palette[a] |= palette[a] >> 6 & 0x30303;
  60.     }
  61.     ctx->frame.palette_has_changed = 1;
  62.     return 0;
  63. }
  64.  
  65. static int bethsoftvid_decode_frame(AVCodecContext *avctx,
  66.                               void *data, int *got_frame,
  67.                               AVPacket *avpkt)
  68. {
  69.     BethsoftvidContext * vid = avctx->priv_data;
  70.     char block_type;
  71.     uint8_t * dst;
  72.     uint8_t * frame_end;
  73.     int remaining = avctx->width;          // number of bytes remaining on a line
  74.     int wrap_to_next_line;
  75.     int code, ret;
  76.     int yoffset;
  77.  
  78.     if ((ret = ff_reget_buffer(avctx, &vid->frame)) < 0)
  79.         return ret;
  80.     wrap_to_next_line = vid->frame.linesize[0] - avctx->width;
  81.  
  82.     if (avpkt->side_data_elems > 0 &&
  83.         avpkt->side_data[0].type == AV_PKT_DATA_PALETTE) {
  84.         bytestream2_init(&vid->g, avpkt->side_data[0].data,
  85.                          avpkt->side_data[0].size);
  86.         if ((ret = set_palette(vid)) < 0)
  87.             return ret;
  88.     }
  89.  
  90.     bytestream2_init(&vid->g, avpkt->data, avpkt->size);
  91.     dst = vid->frame.data[0];
  92.     frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height;
  93.  
  94.     switch(block_type = bytestream2_get_byte(&vid->g)){
  95.         case PALETTE_BLOCK: {
  96.             *got_frame = 0;
  97.             if ((ret = set_palette(vid)) < 0) {
  98.                 av_log(avctx, AV_LOG_ERROR, "error reading palette\n");
  99.                 return ret;
  100.             }
  101.             return bytestream2_tell(&vid->g);
  102.         }
  103.         case VIDEO_YOFF_P_FRAME:
  104.             yoffset = bytestream2_get_le16(&vid->g);
  105.             if(yoffset >= avctx->height)
  106.                 return AVERROR_INVALIDDATA;
  107.             dst += vid->frame.linesize[0] * yoffset;
  108.     }
  109.  
  110.     // main code
  111.     while((code = bytestream2_get_byte(&vid->g))){
  112.         int length = code & 0x7f;
  113.  
  114.         // copy any bytes starting at the current position, and ending at the frame width
  115.         while(length > remaining){
  116.             if(code < 0x80)
  117.                 bytestream2_get_buffer(&vid->g, dst, remaining);
  118.             else if(block_type == VIDEO_I_FRAME)
  119.                 memset(dst, bytestream2_peek_byte(&vid->g), remaining);
  120.             length -= remaining;      // decrement the number of bytes to be copied
  121.             dst += remaining + wrap_to_next_line;    // skip over extra bytes at end of frame
  122.             remaining = avctx->width;
  123.             if(dst == frame_end)
  124.                 goto end;
  125.         }
  126.  
  127.         // copy any remaining bytes after / if line overflows
  128.         if(code < 0x80)
  129.             bytestream2_get_buffer(&vid->g, dst, length);
  130.         else if(block_type == VIDEO_I_FRAME)
  131.             memset(dst, bytestream2_get_byte(&vid->g), length);
  132.         remaining -= length;
  133.         dst += length;
  134.     }
  135.     end:
  136.  
  137.     if ((ret = av_frame_ref(data, &vid->frame)) < 0)
  138.         return ret;
  139.  
  140.     *got_frame = 1;
  141.  
  142.     return avpkt->size;
  143. }
  144.  
  145. static av_cold int bethsoftvid_decode_end(AVCodecContext *avctx)
  146. {
  147.     BethsoftvidContext * vid = avctx->priv_data;
  148.     av_frame_unref(&vid->frame);
  149.     return 0;
  150. }
  151.  
  152. AVCodec ff_bethsoftvid_decoder = {
  153.     .name           = "bethsoftvid",
  154.     .long_name      = NULL_IF_CONFIG_SMALL("Bethesda VID video"),
  155.     .type           = AVMEDIA_TYPE_VIDEO,
  156.     .id             = AV_CODEC_ID_BETHSOFTVID,
  157.     .priv_data_size = sizeof(BethsoftvidContext),
  158.     .init           = bethsoftvid_decode_init,
  159.     .close          = bethsoftvid_decode_end,
  160.     .decode         = bethsoftvid_decode_frame,
  161.     .capabilities   = CODEC_CAP_DR1,
  162. };
  163.