00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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:
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){
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{
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:
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:
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
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 avcodec_get_frame_defaults(&c->pic);
00272
00273 c->frame = av_mallocz(avctx->width * avctx->height);
00274 c->prev_frame = av_mallocz(avctx->width * avctx->height);
00275
00276 return 0;
00277 }
00278
00279 static av_cold int decode_end(AVCodecContext *avctx)
00280 {
00281 VBDecContext *c = avctx->priv_data;
00282
00283 av_freep(&c->frame);
00284 av_freep(&c->prev_frame);
00285 if(c->pic.data[0])
00286 avctx->release_buffer(avctx, &c->pic);
00287
00288 return 0;
00289 }
00290
00291 AVCodec ff_vb_decoder = {
00292 "vb",
00293 AVMEDIA_TYPE_VIDEO,
00294 CODEC_ID_VB,
00295 sizeof(VBDecContext),
00296 decode_init,
00297 NULL,
00298 decode_end,
00299 decode_frame,
00300 .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00301 };
00302