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 #include "internal.h"
00033
00034 enum VBFlags{
00035 VB_HAS_GMC = 0x01,
00036 VB_HAS_AUDIO = 0x04,
00037 VB_HAS_VIDEO = 0x08,
00038 VB_HAS_PALETTE = 0x10,
00039 VB_HAS_LENGTH = 0x20
00040 };
00041
00042 typedef struct VBDecContext {
00043 AVCodecContext *avctx;
00044 AVFrame pic;
00045
00046 uint8_t *frame, *prev_frame;
00047 uint32_t pal[AVPALETTE_COUNT];
00048 GetByteContext stream;
00049 } VBDecContext;
00050
00051 static const uint16_t vb_patterns[64] = {
00052 0x0660, 0xFF00, 0xCCCC, 0xF000, 0x8888, 0x000F, 0x1111, 0xFEC8,
00053 0x8CEF, 0x137F, 0xF731, 0xC800, 0x008C, 0x0013, 0x3100, 0xCC00,
00054 0x00CC, 0x0033, 0x3300, 0x0FF0, 0x6666, 0x00F0, 0x0F00, 0x2222,
00055 0x4444, 0xF600, 0x8CC8, 0x006F, 0x1331, 0x318C, 0xC813, 0x33CC,
00056 0x6600, 0x0CC0, 0x0066, 0x0330, 0xF900, 0xC88C, 0x009F, 0x3113,
00057 0x6000, 0x0880, 0x0006, 0x0110, 0xCC88, 0xFC00, 0x00CF, 0x88CC,
00058 0x003F, 0x1133, 0x3311, 0xF300, 0x6FF6, 0x0603, 0x08C6, 0x8C63,
00059 0xC631, 0x6310, 0xC060, 0x0136, 0x136C, 0x36C8, 0x6C80, 0x324C
00060 };
00061
00062 static void vb_decode_palette(VBDecContext *c, int data_size)
00063 {
00064 int start, size, i;
00065
00066 start = bytestream2_get_byte(&c->stream);
00067 size = (bytestream2_get_byte(&c->stream) - 1) & 0xFF;
00068 if(start + size > 255){
00069 av_log(c->avctx, AV_LOG_ERROR, "Palette change runs beyond entry 256\n");
00070 return;
00071 }
00072 if(size*3+2 > data_size){
00073 av_log(c->avctx, AV_LOG_ERROR, "Palette data runs beyond chunk size\n");
00074 return;
00075 }
00076 for(i = start; i <= start + size; i++)
00077 c->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&c->stream);
00078 }
00079
00080 static inline int check_pixel(uint8_t *buf, uint8_t *start, uint8_t *end)
00081 {
00082 return buf >= start && buf < end;
00083 }
00084
00085 static inline int check_line(uint8_t *buf, uint8_t *start, uint8_t *end)
00086 {
00087 return buf >= start && (buf + 4) <= end;
00088 }
00089
00090 static int vb_decode_framedata(VBDecContext *c, int offset)
00091 {
00092 GetByteContext g;
00093 uint8_t *prev, *cur;
00094 int blk, blocks, t, blk2;
00095 int blocktypes = 0;
00096 int x, y, a, b;
00097 int pattype, pattern;
00098 const int width = c->avctx->width;
00099 uint8_t *pstart = c->prev_frame;
00100 uint8_t *pend = c->prev_frame + width*c->avctx->height;
00101
00102 g = c->stream;
00103
00104 prev = c->prev_frame + offset;
00105 cur = c->frame;
00106
00107 blocks = (c->avctx->width >> 2) * (c->avctx->height >> 2);
00108 blk2 = 0;
00109 for(blk = 0; blk < blocks; blk++){
00110 if(!(blk & 3)) {
00111 blocktypes = bytestream2_get_byte(&g);
00112 }
00113 switch(blocktypes & 0xC0){
00114 case 0x00:
00115 for(y = 0; y < 4; y++)
00116 if(check_line(prev + y*width, pstart, pend))
00117 memcpy(cur + y*width, prev + y*width, 4);
00118 else
00119 memset(cur + y*width, 0, 4);
00120 break;
00121 case 0x40:
00122 t = bytestream2_get_byte(&g);
00123 if(!t){
00124 if (bytestream2_get_bytes_left(&g) < 16) {
00125 av_log(c->avctx, AV_LOG_ERROR, "Insufficient data\n");
00126 return -1;
00127 }
00128 for(y = 0; y < 4; y++)
00129 bytestream2_get_buffer(&g, cur + y * width, 4);
00130 }else{
00131 x = ((t & 0xF)^8) - 8;
00132 y = ((t >> 4) ^8) - 8;
00133 t = x + y*width;
00134 for(y = 0; y < 4; y++)
00135 if(check_line(prev + t + y*width, pstart, pend))
00136 memcpy(cur + y*width, prev + t + y*width, 4);
00137 else
00138 memset(cur + y*width, 0, 4);
00139 }
00140 break;
00141 case 0x80:
00142 t = bytestream2_get_byte(&g);
00143 for(y = 0; y < 4; y++)
00144 memset(cur + y*width, t, 4);
00145 break;
00146 case 0xC0:
00147 t = bytestream2_get_byte(&g);
00148 pattype = t >> 6;
00149 pattern = vb_patterns[t & 0x3F];
00150 switch(pattype){
00151 case 0:
00152 a = bytestream2_get_byte(&g);
00153 b = bytestream2_get_byte(&g);
00154 for(y = 0; y < 4; y++)
00155 for(x = 0; x < 4; x++, pattern >>= 1)
00156 cur[x + y*width] = (pattern & 1) ? b : a;
00157 break;
00158 case 1:
00159 pattern = ~pattern;
00160 case 2:
00161 a = bytestream2_get_byte(&g);
00162 for(y = 0; y < 4; y++)
00163 for(x = 0; x < 4; x++, pattern >>= 1)
00164 if(pattern & 1 && check_pixel(prev + x + y*width, pstart, pend))
00165 cur[x + y*width] = prev[x + y*width];
00166 else
00167 cur[x + y*width] = a;
00168 break;
00169 case 3:
00170 av_log(c->avctx, AV_LOG_ERROR, "Invalid opcode seen @%d\n",blk);
00171 return -1;
00172 }
00173 break;
00174 }
00175 blocktypes <<= 2;
00176 cur += 4;
00177 prev += 4;
00178 blk2++;
00179 if(blk2 == (width >> 2)){
00180 blk2 = 0;
00181 cur += width * 3;
00182 prev += width * 3;
00183 }
00184 }
00185 return 0;
00186 }
00187
00188 static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
00189 AVPacket *avpkt)
00190 {
00191 VBDecContext * const c = avctx->priv_data;
00192 uint8_t *outptr, *srcptr;
00193 int i, j;
00194 int flags;
00195 uint32_t size;
00196 int offset = 0;
00197
00198 bytestream2_init(&c->stream, avpkt->data, avpkt->size);
00199
00200 if(c->pic.data[0])
00201 avctx->release_buffer(avctx, &c->pic);
00202 c->pic.reference = 3;
00203 if(ff_get_buffer(avctx, &c->pic) < 0){
00204 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00205 return -1;
00206 }
00207
00208 flags = bytestream2_get_le16(&c->stream);
00209
00210 if(flags & VB_HAS_GMC){
00211 i = (int16_t)bytestream2_get_le16(&c->stream);
00212 j = (int16_t)bytestream2_get_le16(&c->stream);
00213 offset = i + j * avctx->width;
00214 }
00215 if(flags & VB_HAS_VIDEO){
00216 size = bytestream2_get_le32(&c->stream);
00217 if(size > bytestream2_get_bytes_left(&c->stream)+4 || size<4){
00218 av_log(avctx, AV_LOG_ERROR, "Frame size invalid\n");
00219 return -1;
00220 }
00221 vb_decode_framedata(c, offset);
00222 bytestream2_skip(&c->stream, size - 4);
00223 }
00224 if(flags & VB_HAS_PALETTE){
00225 size = bytestream2_get_le32(&c->stream);
00226 vb_decode_palette(c, size);
00227 }
00228
00229 memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
00230 c->pic.palette_has_changed = flags & VB_HAS_PALETTE;
00231
00232 outptr = c->pic.data[0];
00233 srcptr = c->frame;
00234
00235 for(i = 0; i < avctx->height; i++){
00236 memcpy(outptr, srcptr, avctx->width);
00237 srcptr += avctx->width;
00238 outptr += c->pic.linesize[0];
00239 }
00240
00241 FFSWAP(uint8_t*, c->frame, c->prev_frame);
00242
00243 *got_frame = 1;
00244 *(AVFrame*)data = c->pic;
00245
00246
00247 return avpkt->size;
00248 }
00249
00250 static av_cold int decode_init(AVCodecContext *avctx)
00251 {
00252 VBDecContext * const c = avctx->priv_data;
00253
00254 c->avctx = avctx;
00255 avctx->pix_fmt = AV_PIX_FMT_PAL8;
00256 avcodec_get_frame_defaults(&c->pic);
00257
00258 c->frame = av_mallocz(avctx->width * avctx->height);
00259 c->prev_frame = av_mallocz(avctx->width * avctx->height);
00260
00261 return 0;
00262 }
00263
00264 static av_cold int decode_end(AVCodecContext *avctx)
00265 {
00266 VBDecContext *c = avctx->priv_data;
00267
00268 av_freep(&c->frame);
00269 av_freep(&c->prev_frame);
00270 if(c->pic.data[0])
00271 avctx->release_buffer(avctx, &c->pic);
00272
00273 return 0;
00274 }
00275
00276 AVCodec ff_vb_decoder = {
00277 .name = "vb",
00278 .type = AVMEDIA_TYPE_VIDEO,
00279 .id = AV_CODEC_ID_VB,
00280 .priv_data_size = sizeof(VBDecContext),
00281 .init = decode_init,
00282 .close = decode_end,
00283 .decode = decode_frame,
00284 .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00285 .capabilities = CODEC_CAP_DR1,
00286 };