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] = 0xFF << 24 | 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 = 3;
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(rest < 0){
00225 av_log(avctx, AV_LOG_ERROR, "not enough data\n");
00226 return -1;
00227 }
00228 if(flags & VB_HAS_VIDEO){
00229 size = bytestream_get_le32(&c->stream);
00230 if(size > rest || size<4){
00231 av_log(avctx, AV_LOG_ERROR, "Frame size invalid\n");
00232 return -1;
00233 }
00234 vb_decode_framedata(c, c->stream, size, offset);
00235 c->stream += size - 4;
00236 rest -= size;
00237 }
00238 if(flags & VB_HAS_PALETTE){
00239 size = bytestream_get_le32(&c->stream);
00240 if(size > rest){
00241 av_log(avctx, AV_LOG_ERROR, "Palette size is too big\n");
00242 return -1;
00243 }
00244 vb_decode_palette(c, size);
00245 rest -= size;
00246 }
00247
00248 memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
00249 c->pic.palette_has_changed = flags & VB_HAS_PALETTE;
00250
00251 outptr = c->pic.data[0];
00252 srcptr = c->frame;
00253
00254 for(i = 0; i < avctx->height; i++){
00255 memcpy(outptr, srcptr, avctx->width);
00256 srcptr += avctx->width;
00257 outptr += c->pic.linesize[0];
00258 }
00259
00260 FFSWAP(uint8_t*, c->frame, c->prev_frame);
00261
00262 *data_size = sizeof(AVFrame);
00263 *(AVFrame*)data = c->pic;
00264
00265
00266 return buf_size;
00267 }
00268
00269 static av_cold int decode_init(AVCodecContext *avctx)
00270 {
00271 VBDecContext * const c = avctx->priv_data;
00272
00273 c->avctx = avctx;
00274 avctx->pix_fmt = PIX_FMT_PAL8;
00275 avcodec_get_frame_defaults(&c->pic);
00276
00277 c->frame = av_mallocz(avctx->width * avctx->height);
00278 c->prev_frame = av_mallocz(avctx->width * avctx->height);
00279
00280 return 0;
00281 }
00282
00283 static av_cold int decode_end(AVCodecContext *avctx)
00284 {
00285 VBDecContext *c = avctx->priv_data;
00286
00287 av_freep(&c->frame);
00288 av_freep(&c->prev_frame);
00289 if(c->pic.data[0])
00290 avctx->release_buffer(avctx, &c->pic);
00291
00292 return 0;
00293 }
00294
00295 AVCodec ff_vb_decoder = {
00296 .name = "vb",
00297 .type = AVMEDIA_TYPE_VIDEO,
00298 .id = CODEC_ID_VB,
00299 .priv_data_size = sizeof(VBDecContext),
00300 .init = decode_init,
00301 .close = decode_end,
00302 .decode = decode_frame,
00303 .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00304 };
00305