Libav
|
00001 /* 00002 * Beam Software VB decoder 00003 * Copyright (c) 2007 Konstantin Shishkov 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00027 #include <stdio.h> 00028 #include <stdlib.h> 00029 00030 #include "avcodec.h" 00031 #include "bytestream.h" 00032 00033 enum VBFlags{ 00034 VB_HAS_GMC = 0x01, 00035 VB_HAS_AUDIO = 0x04, 00036 VB_HAS_VIDEO = 0x08, 00037 VB_HAS_PALETTE = 0x10, 00038 VB_HAS_LENGTH = 0x20 00039 }; 00040 00041 typedef struct VBDecContext { 00042 AVCodecContext *avctx; 00043 AVFrame pic; 00044 00045 uint8_t *frame, *prev_frame; 00046 uint32_t pal[AVPALETTE_COUNT]; 00047 const uint8_t *stream; 00048 } VBDecContext; 00049 00050 static const uint16_t vb_patterns[64] = { 00051 0x0660, 0xFF00, 0xCCCC, 0xF000, 0x8888, 0x000F, 0x1111, 0xFEC8, 00052 0x8CEF, 0x137F, 0xF731, 0xC800, 0x008C, 0x0013, 0x3100, 0xCC00, 00053 0x00CC, 0x0033, 0x3300, 0x0FF0, 0x6666, 0x00F0, 0x0F00, 0x2222, 00054 0x4444, 0xF600, 0x8CC8, 0x006F, 0x1331, 0x318C, 0xC813, 0x33CC, 00055 0x6600, 0x0CC0, 0x0066, 0x0330, 0xF900, 0xC88C, 0x009F, 0x3113, 00056 0x6000, 0x0880, 0x0006, 0x0110, 0xCC88, 0xFC00, 0x00CF, 0x88CC, 00057 0x003F, 0x1133, 0x3311, 0xF300, 0x6FF6, 0x0603, 0x08C6, 0x8C63, 00058 0xC631, 0x6310, 0xC060, 0x0136, 0x136C, 0x36C8, 0x6C80, 0x324C 00059 }; 00060 00061 static void vb_decode_palette(VBDecContext *c, int data_size) 00062 { 00063 int start, size, i; 00064 00065 start = bytestream_get_byte(&c->stream); 00066 size = (bytestream_get_byte(&c->stream) - 1) & 0xFF; 00067 if(start + size > 255){ 00068 av_log(c->avctx, AV_LOG_ERROR, "Palette change runs beyond entry 256\n"); 00069 return; 00070 } 00071 if(size*3+2 > data_size){ 00072 av_log(c->avctx, AV_LOG_ERROR, "Palette data runs beyond chunk size\n"); 00073 return; 00074 } 00075 for(i = start; i <= start + size; i++) 00076 c->pal[i] = bytestream_get_be24(&c->stream); 00077 } 00078 00079 static inline int check_pixel(uint8_t *buf, uint8_t *start, uint8_t *end) 00080 { 00081 return buf >= start && buf < end; 00082 } 00083 00084 static inline int check_line(uint8_t *buf, uint8_t *start, uint8_t *end) 00085 { 00086 return buf >= start && (buf + 4) <= end; 00087 } 00088 00089 static int vb_decode_framedata(VBDecContext *c, const uint8_t *buf, int data_size, int offset) 00090 { 00091 uint8_t *prev, *cur; 00092 const uint8_t* data_end = buf + data_size; 00093 int blk, blocks, t, blk2; 00094 int blocktypes = 0; 00095 int x, y, a, b; 00096 int pattype, pattern; 00097 const int width = c->avctx->width; 00098 uint8_t *pstart = c->prev_frame; 00099 uint8_t *pend = c->prev_frame + width*c->avctx->height; 00100 00101 prev = c->prev_frame + offset; 00102 cur = c->frame; 00103 00104 blocks = (c->avctx->width >> 2) * (c->avctx->height >> 2); 00105 blk2 = 0; 00106 for(blk = 0; blk < blocks; blk++){ 00107 if(!(blk & 3)) { 00108 if(buf >= data_end){ 00109 av_log(c->avctx, AV_LOG_ERROR, "Data pointer out of bounds\n"); 00110 return -1; 00111 } 00112 blocktypes = bytestream_get_byte(&buf); 00113 } 00114 switch(blocktypes & 0xC0){ 00115 case 0x00: //skip 00116 for(y = 0; y < 4; y++) 00117 if(check_line(prev + y*width, pstart, pend)) 00118 memcpy(cur + y*width, prev + y*width, 4); 00119 else 00120 memset(cur + y*width, 0, 4); 00121 break; 00122 case 0x40: 00123 t = bytestream_get_byte(&buf); 00124 if(!t){ //raw block 00125 if(buf + 16 > data_end){ 00126 av_log(c->avctx, AV_LOG_ERROR, "Insufficient data\n"); 00127 return -1; 00128 } 00129 for(y = 0; y < 4; y++) 00130 memcpy(cur + y*width, buf + y*4, 4); 00131 buf += 16; 00132 }else{ // motion compensation 00133 x = ((t & 0xF)^8) - 8; 00134 y = ((t >> 4) ^8) - 8; 00135 t = x + y*width; 00136 for(y = 0; y < 4; y++) 00137 if(check_line(prev + t + y*width, pstart, pend)) 00138 memcpy(cur + y*width, prev + t + y*width, 4); 00139 else 00140 memset(cur + y*width, 0, 4); 00141 } 00142 break; 00143 case 0x80: // fill 00144 t = bytestream_get_byte(&buf); 00145 for(y = 0; y < 4; y++) 00146 memset(cur + y*width, t, 4); 00147 break; 00148 case 0xC0: // pattern fill 00149 if(buf + 2 > data_end){ 00150 av_log(c->avctx, AV_LOG_ERROR, "Insufficient data\n"); 00151 return -1; 00152 } 00153 t = bytestream_get_byte(&buf); 00154 pattype = t >> 6; 00155 pattern = vb_patterns[t & 0x3F]; 00156 switch(pattype){ 00157 case 0: 00158 a = bytestream_get_byte(&buf); 00159 b = bytestream_get_byte(&buf); 00160 for(y = 0; y < 4; y++) 00161 for(x = 0; x < 4; x++, pattern >>= 1) 00162 cur[x + y*width] = (pattern & 1) ? b : a; 00163 break; 00164 case 1: 00165 pattern = ~pattern; 00166 case 2: 00167 a = bytestream_get_byte(&buf); 00168 for(y = 0; y < 4; y++) 00169 for(x = 0; x < 4; x++, pattern >>= 1) 00170 if(pattern & 1 && check_pixel(prev + x + y*width, pstart, pend)) 00171 cur[x + y*width] = prev[x + y*width]; 00172 else 00173 cur[x + y*width] = a; 00174 break; 00175 case 3: 00176 av_log(c->avctx, AV_LOG_ERROR, "Invalid opcode seen @%d\n",blk); 00177 return -1; 00178 } 00179 break; 00180 } 00181 blocktypes <<= 2; 00182 cur += 4; 00183 prev += 4; 00184 blk2++; 00185 if(blk2 == (width >> 2)){ 00186 blk2 = 0; 00187 cur += width * 3; 00188 prev += width * 3; 00189 } 00190 } 00191 return 0; 00192 } 00193 00194 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) 00195 { 00196 const uint8_t *buf = avpkt->data; 00197 int buf_size = avpkt->size; 00198 VBDecContext * const c = avctx->priv_data; 00199 uint8_t *outptr, *srcptr; 00200 int i, j; 00201 int flags; 00202 uint32_t size; 00203 int rest = buf_size; 00204 int offset = 0; 00205 00206 if(c->pic.data[0]) 00207 avctx->release_buffer(avctx, &c->pic); 00208 c->pic.reference = 1; 00209 if(avctx->get_buffer(avctx, &c->pic) < 0){ 00210 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00211 return -1; 00212 } 00213 00214 c->stream = buf; 00215 flags = bytestream_get_le16(&c->stream); 00216 rest -= 2; 00217 00218 if(flags & VB_HAS_GMC){ 00219 i = (int16_t)bytestream_get_le16(&c->stream); 00220 j = (int16_t)bytestream_get_le16(&c->stream); 00221 offset = i + j * avctx->width; 00222 rest -= 4; 00223 } 00224 if(flags & VB_HAS_VIDEO){ 00225 size = bytestream_get_le32(&c->stream); 00226 if(size > rest){ 00227 av_log(avctx, AV_LOG_ERROR, "Frame size is too big\n"); 00228 return -1; 00229 } 00230 vb_decode_framedata(c, c->stream, size, offset); 00231 c->stream += size - 4; 00232 rest -= size; 00233 } 00234 if(flags & VB_HAS_PALETTE){ 00235 size = bytestream_get_le32(&c->stream); 00236 if(size > rest){ 00237 av_log(avctx, AV_LOG_ERROR, "Palette size is too big\n"); 00238 return -1; 00239 } 00240 vb_decode_palette(c, size); 00241 rest -= size; 00242 } 00243 00244 memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE); 00245 c->pic.palette_has_changed = flags & VB_HAS_PALETTE; 00246 00247 outptr = c->pic.data[0]; 00248 srcptr = c->frame; 00249 00250 for(i = 0; i < avctx->height; i++){ 00251 memcpy(outptr, srcptr, avctx->width); 00252 srcptr += avctx->width; 00253 outptr += c->pic.linesize[0]; 00254 } 00255 00256 FFSWAP(uint8_t*, c->frame, c->prev_frame); 00257 00258 *data_size = sizeof(AVFrame); 00259 *(AVFrame*)data = c->pic; 00260 00261 /* always report that the buffer was completely consumed */ 00262 return buf_size; 00263 } 00264 00265 static av_cold int decode_init(AVCodecContext *avctx) 00266 { 00267 VBDecContext * const c = avctx->priv_data; 00268 00269 c->avctx = avctx; 00270 avctx->pix_fmt = PIX_FMT_PAL8; 00271 00272 c->frame = av_mallocz(avctx->width * avctx->height); 00273 c->prev_frame = av_mallocz(avctx->width * avctx->height); 00274 00275 return 0; 00276 } 00277 00278 static av_cold int decode_end(AVCodecContext *avctx) 00279 { 00280 VBDecContext *c = avctx->priv_data; 00281 00282 av_freep(&c->frame); 00283 av_freep(&c->prev_frame); 00284 if(c->pic.data[0]) 00285 avctx->release_buffer(avctx, &c->pic); 00286 00287 return 0; 00288 } 00289 00290 AVCodec vb_decoder = { 00291 "vb", 00292 AVMEDIA_TYPE_VIDEO, 00293 CODEC_ID_VB, 00294 sizeof(VBDecContext), 00295 decode_init, 00296 NULL, 00297 decode_end, 00298 decode_frame, 00299 .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"), 00300 }; 00301