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