Libav 0.7.1
|
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 } BethsoftvidContext; 00038 00039 static av_cold int bethsoftvid_decode_init(AVCodecContext *avctx) 00040 { 00041 BethsoftvidContext *vid = avctx->priv_data; 00042 vid->frame.reference = 1; 00043 vid->frame.buffer_hints = FF_BUFFER_HINTS_VALID | 00044 FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; 00045 avctx->pix_fmt = PIX_FMT_PAL8; 00046 return 0; 00047 } 00048 00049 static void set_palette(AVFrame * frame, const uint8_t * palette_buffer) 00050 { 00051 uint32_t * palette = (uint32_t *)frame->data[1]; 00052 int a; 00053 for(a = 0; a < 256; a++){ 00054 palette[a] = AV_RB24(&palette_buffer[a * 3]) * 4; 00055 } 00056 frame->palette_has_changed = 1; 00057 } 00058 00059 static int bethsoftvid_decode_frame(AVCodecContext *avctx, 00060 void *data, int *data_size, 00061 AVPacket *avpkt) 00062 { 00063 const uint8_t *buf = avpkt->data; 00064 int buf_size = avpkt->size; 00065 BethsoftvidContext * vid = avctx->priv_data; 00066 char block_type; 00067 uint8_t * dst; 00068 uint8_t * frame_end; 00069 int remaining = avctx->width; // number of bytes remaining on a line 00070 const int wrap_to_next_line = vid->frame.linesize[0] - avctx->width; 00071 int code; 00072 int yoffset; 00073 00074 if (avctx->reget_buffer(avctx, &vid->frame)) { 00075 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00076 return -1; 00077 } 00078 dst = vid->frame.data[0]; 00079 frame_end = vid->frame.data[0] + vid->frame.linesize[0] * avctx->height; 00080 00081 switch(block_type = *buf++){ 00082 case PALETTE_BLOCK: 00083 set_palette(&vid->frame, buf); 00084 return 0; 00085 case VIDEO_YOFF_P_FRAME: 00086 yoffset = bytestream_get_le16(&buf); 00087 if(yoffset >= avctx->height) 00088 return -1; 00089 dst += vid->frame.linesize[0] * yoffset; 00090 } 00091 00092 // main code 00093 while((code = *buf++)){ 00094 int length = code & 0x7f; 00095 00096 // copy any bytes starting at the current position, and ending at the frame width 00097 while(length > remaining){ 00098 if(code < 0x80) 00099 bytestream_get_buffer(&buf, dst, remaining); 00100 else if(block_type == VIDEO_I_FRAME) 00101 memset(dst, buf[0], remaining); 00102 length -= remaining; // decrement the number of bytes to be copied 00103 dst += remaining + wrap_to_next_line; // skip over extra bytes at end of frame 00104 remaining = avctx->width; 00105 if(dst == frame_end) 00106 goto end; 00107 } 00108 00109 // copy any remaining bytes after / if line overflows 00110 if(code < 0x80) 00111 bytestream_get_buffer(&buf, dst, length); 00112 else if(block_type == VIDEO_I_FRAME) 00113 memset(dst, *buf++, length); 00114 remaining -= length; 00115 dst += length; 00116 } 00117 end: 00118 00119 *data_size = sizeof(AVFrame); 00120 *(AVFrame*)data = vid->frame; 00121 00122 return buf_size; 00123 } 00124 00125 static av_cold int bethsoftvid_decode_end(AVCodecContext *avctx) 00126 { 00127 BethsoftvidContext * vid = avctx->priv_data; 00128 if(vid->frame.data[0]) 00129 avctx->release_buffer(avctx, &vid->frame); 00130 return 0; 00131 } 00132 00133 AVCodec ff_bethsoftvid_decoder = { 00134 .name = "bethsoftvid", 00135 .type = AVMEDIA_TYPE_VIDEO, 00136 .id = CODEC_ID_BETHSOFTVID, 00137 .priv_data_size = sizeof(BethsoftvidContext), 00138 .init = bethsoftvid_decode_init, 00139 .close = bethsoftvid_decode_end, 00140 .decode = bethsoftvid_decode_frame, 00141 .capabilities = CODEC_CAP_DR1, 00142 .long_name = NULL_IF_CONFIG_SMALL("Bethesda VID video"), 00143 };