• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavcodec/bethsoftvideo.c

Go to the documentation of this file.
00001 /*
00002  * Bethesda VID video decoder
00003  * Copyright (C) 2007 Nicholas Tung
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * Libav is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00030 #include "libavutil/common.h"
00031 #include "dsputil.h"
00032 #include "bethsoftvideo.h"
00033 #include "bytestream.h"
00034 
00035 typedef struct BethsoftvidContext {
00036     AVFrame frame;
00037     GetByteContext g;
00038 } BethsoftvidContext;
00039 
00040 static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx)
00041 {
00042     BethsoftvidContext *vid = avctx->priv_data;
00043     vid->frame.reference = 1;
00044     vid->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
00045         FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
00046     avctx->pix_fmt = PIX_FMT_PAL8;
00047     return 0;
00048 }
00049 
00050 static int set_palette(BethsoftvidContext *ctx)
00051 {
00052     uint32_t *palette = (uint32_t *)ctx->frame.data[1];
00053     int a;
00054 
00055     if (bytestream2_get_bytes_left(&ctx->g) < 256*3)
00056         return AVERROR_INVALIDDATA;
00057 
00058     for(a = 0; a < 256; a++){
00059         palette[a] = bytestream2_get_be24u(&ctx->g) * 4;
00060     }
00061     ctx->frame.palette_has_changed = 1;
00062     return 256*3;
00063 }
00064 
00065 static int bethsoftvid_decode_frame(AVCodecContext *avctx,
00066                               void *data, int *data_size,
00067                               AVPacket *avpkt)
00068 {
00069     BethsoftvidContext * vid = avctx->priv_data;
00070     char block_type;
00071     uint8_t * dst;
00072     uint8_t * frame_end;
00073     int remaining = avctx->width;          // number of bytes remaining on a line
00074     const int wrap_to_next_line = vid->frame.linesize[0] - avctx->width;
00075     int code;
00076     int yoffset;
00077 
00078     if (avctx->reget_buffer(avctx, &vid->frame)) {
00079         av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00080         return -1;
00081     }
00082 
00083     bytestream2_init(&vid->g, avpkt->data, avpkt->size);
00084     dst = vid->frame.data[0];
00085     frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height;
00086 
00087     switch(block_type = bytestream2_get_byte(&vid->g)){
00088         case PALETTE_BLOCK: {
00089             return set_palette(vid);
00090         }
00091         case VIDEO_YOFF_P_FRAME:
00092             yoffset = bytestream2_get_le16(&vid->g);
00093             if(yoffset >= avctx->height)
00094                 return -1;
00095             dst += vid->frame.linesize[0] * yoffset;
00096     }
00097 
00098     // main code
00099     while((code = bytestream2_get_byte(&vid->g))){
00100         int length = code & 0x7f;
00101 
00102         // copy any bytes starting at the current position, and ending at the frame width
00103         while(length > remaining){
00104             if(code < 0x80)
00105                 bytestream2_get_buffer(&vid->g, dst, remaining);
00106             else if(block_type == VIDEO_I_FRAME)
00107                 memset(dst, bytestream2_peek_byte(&vid->g), remaining);
00108             length -= remaining;      // decrement the number of bytes to be copied
00109             dst += remaining + wrap_to_next_line;    // skip over extra bytes at end of frame
00110             remaining = avctx->width;
00111             if(dst == frame_end)
00112                 goto end;
00113         }
00114 
00115         // copy any remaining bytes after / if line overflows
00116         if(code < 0x80)
00117             bytestream2_get_buffer(&vid->g, dst, length);
00118         else if(block_type == VIDEO_I_FRAME)
00119             memset(dst, bytestream2_get_byte(&vid->g), length);
00120         remaining -= length;
00121         dst += length;
00122     }
00123     end:
00124 
00125     *data_size = sizeof(AVFrame);
00126     *(AVFrame*)data = vid->frame;
00127 
00128     return avpkt->size;
00129 }
00130 
00131 static av_cold int bethsoftvid_decode_end(AVCodecContext *avctx)
00132 {
00133     BethsoftvidContext * vid = avctx->priv_data;
00134     if(vid->frame.data[0])
00135         avctx->release_buffer(avctx, &vid->frame);
00136     return 0;
00137 }
00138 
00139 AVCodec ff_bethsoftvid_decoder = {
00140     .name = "bethsoftvid",
00141     .type = AVMEDIA_TYPE_VIDEO,
00142     .id = CODEC_ID_BETHSOFTVID,
00143     .priv_data_size = sizeof(BethsoftvidContext),
00144     .init = bethsoftvid_decode_init,
00145     .close = bethsoftvid_decode_end,
00146     .decode = bethsoftvid_decode_frame,
00147     .capabilities = CODEC_CAP_DR1,
00148     .long_name = NULL_IF_CONFIG_SMALL("Bethesda VID video"),
00149 };
Generated on Thu Jan 24 2013 17:08:50 for Libav by doxygen 1.7.1