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 GetByteContext 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 = bytestream2_get_byte(&c->stream);
00066 size = (bytestream2_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] = 0xFFU << 24 | bytestream2_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, int offset)
00090 {
00091 GetByteContext g;
00092 uint8_t *prev, *cur;
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 g = c->stream;
00102
00103 prev = c->prev_frame + offset;
00104 cur = c->frame;
00105
00106 blocks = (c->avctx->width >> 2) * (c->avctx->height >> 2);
00107 blk2 = 0;
00108 for(blk = 0; blk < blocks; blk++){
00109 if(!(blk & 3)) {
00110 blocktypes = bytestream2_get_byte(&g);
00111 }
00112 switch(blocktypes & 0xC0){
00113 case 0x00:
00114 for(y = 0; y < 4; y++)
00115 if(check_line(prev + y*width, pstart, pend))
00116 memcpy(cur + y*width, prev + y*width, 4);
00117 else
00118 memset(cur + y*width, 0, 4);
00119 break;
00120 case 0x40:
00121 t = bytestream2_get_byte(&g);
00122 if(!t){
00123 if (bytestream2_get_bytes_left(&g) < 16) {
00124 av_log(c->avctx, AV_LOG_ERROR, "Insufficient data\n");
00125 return -1;
00126 }
00127 for(y = 0; y < 4; y++)
00128 bytestream2_get_buffer(&g, cur + y * width, 4);
00129 }else{
00130 x = ((t & 0xF)^8) - 8;
00131 y = ((t >> 4) ^8) - 8;
00132 t = x + y*width;
00133 for(y = 0; y < 4; y++)
00134 if(check_line(prev + t + y*width, pstart, pend))
00135 memcpy(cur + y*width, prev + t + y*width, 4);
00136 else
00137 memset(cur + y*width, 0, 4);
00138 }
00139 break;
00140 case 0x80:
00141 t = bytestream2_get_byte(&g);
00142 for(y = 0; y < 4; y++)
00143 memset(cur + y*width, t, 4);
00144 break;
00145 case 0xC0:
00146 t = bytestream2_get_byte(&g);
00147 pattype = t >> 6;
00148 pattern = vb_patterns[t & 0x3F];
00149 switch(pattype){
00150 case 0:
00151 a = bytestream2_get_byte(&g);
00152 b = bytestream2_get_byte(&g);
00153 for(y = 0; y < 4; y++)
00154 for(x = 0; x < 4; x++, pattern >>= 1)
00155 cur[x + y*width] = (pattern & 1) ? b : a;
00156 break;
00157 case 1:
00158 pattern = ~pattern;
00159 case 2:
00160 a = bytestream2_get_byte(&g);
00161 for(y = 0; y < 4; y++)
00162 for(x = 0; x < 4; x++, pattern >>= 1)
00163 if(pattern & 1 && check_pixel(prev + x + y*width, pstart, pend))
00164 cur[x + y*width] = prev[x + y*width];
00165 else
00166 cur[x + y*width] = a;
00167 break;
00168 case 3:
00169 av_log(c->avctx, AV_LOG_ERROR, "Invalid opcode seen @%d\n",blk);
00170 return -1;
00171 }
00172 break;
00173 }
00174 blocktypes <<= 2;
00175 cur += 4;
00176 prev += 4;
00177 blk2++;
00178 if(blk2 == (width >> 2)){
00179 blk2 = 0;
00180 cur += width * 3;
00181 prev += width * 3;
00182 }
00183 }
00184 return 0;
00185 }
00186
00187 static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt)
00188 {
00189 VBDecContext * const c = avctx->priv_data;
00190 uint8_t *outptr, *srcptr;
00191 int i, j;
00192 int flags;
00193 uint32_t size;
00194 int offset = 0;
00195
00196 bytestream2_init(&c->stream, avpkt->data, avpkt->size);
00197
00198 if(c->pic.data[0])
00199 avctx->release_buffer(avctx, &c->pic);
00200 c->pic.reference = 3;
00201 if(avctx->get_buffer(avctx, &c->pic) < 0){
00202 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00203 return -1;
00204 }
00205
00206 flags = bytestream2_get_le16(&c->stream);
00207
00208 if(flags & VB_HAS_GMC){
00209 i = (int16_t)bytestream2_get_le16(&c->stream);
00210 j = (int16_t)bytestream2_get_le16(&c->stream);
00211 offset = i + j * avctx->width;
00212 }
00213 if(flags & VB_HAS_VIDEO){
00214 size = bytestream2_get_le32(&c->stream);
00215 if(size > bytestream2_get_bytes_left(&c->stream)+4 || size<4){
00216 av_log(avctx, AV_LOG_ERROR, "Frame size invalid\n");
00217 return -1;
00218 }
00219 vb_decode_framedata(c, offset);
00220 bytestream2_skip(&c->stream, size - 4);
00221 }
00222 if(flags & VB_HAS_PALETTE){
00223 size = bytestream2_get_le32(&c->stream);
00224 vb_decode_palette(c, size);
00225 }
00226
00227 memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
00228 c->pic.palette_has_changed = flags & VB_HAS_PALETTE;
00229
00230 outptr = c->pic.data[0];
00231 srcptr = c->frame;
00232
00233 for(i = 0; i < avctx->height; i++){
00234 memcpy(outptr, srcptr, avctx->width);
00235 srcptr += avctx->width;
00236 outptr += c->pic.linesize[0];
00237 }
00238
00239 FFSWAP(uint8_t*, c->frame, c->prev_frame);
00240
00241 *data_size = sizeof(AVFrame);
00242 *(AVFrame*)data = c->pic;
00243
00244
00245 return avpkt->size;
00246 }
00247
00248 static av_cold int decode_init(AVCodecContext *avctx)
00249 {
00250 VBDecContext * const c = avctx->priv_data;
00251
00252 c->avctx = avctx;
00253 avctx->pix_fmt = PIX_FMT_PAL8;
00254 avcodec_get_frame_defaults(&c->pic);
00255
00256 c->frame = av_mallocz(avctx->width * avctx->height);
00257 c->prev_frame = av_mallocz(avctx->width * avctx->height);
00258
00259 return 0;
00260 }
00261
00262 static av_cold int decode_end(AVCodecContext *avctx)
00263 {
00264 VBDecContext *c = avctx->priv_data;
00265
00266 av_freep(&c->frame);
00267 av_freep(&c->prev_frame);
00268 if(c->pic.data[0])
00269 avctx->release_buffer(avctx, &c->pic);
00270
00271 return 0;
00272 }
00273
00274 AVCodec ff_vb_decoder = {
00275 .name = "vb",
00276 .type = AVMEDIA_TYPE_VIDEO,
00277 .id = CODEC_ID_VB,
00278 .priv_data_size = sizeof(VBDecContext),
00279 .init = decode_init,
00280 .close = decode_end,
00281 .decode = decode_frame,
00282 .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00283 };