• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/vb.c

Go to the documentation of this file.
00001 /*
00002  * Beam Software VB decoder
00003  * Copyright (c) 2007 Konstantin Shishkov
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * FFmpeg is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with FFmpeg; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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: //skip
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){ //raw block
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{ // motion compensation
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: // fill
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: // pattern fill
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     /* always report that the buffer was completely consumed */
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 
00272     c->frame      = av_mallocz(avctx->width * avctx->height);
00273     c->prev_frame = av_mallocz(avctx->width * avctx->height);
00274 
00275     return 0;
00276 }
00277 
00278 static av_cold int decode_end(AVCodecContext *avctx)
00279 {
00280     VBDecContext *c = avctx->priv_data;
00281 
00282     av_freep(&c->frame);
00283     av_freep(&c->prev_frame);
00284     if(c->pic.data[0])
00285         avctx->release_buffer(avctx, &c->pic);
00286 
00287     return 0;
00288 }
00289 
00290 AVCodec vb_decoder = {
00291     "vb",
00292     AVMEDIA_TYPE_VIDEO,
00293     CODEC_ID_VB,
00294     sizeof(VBDecContext),
00295     decode_init,
00296     NULL,
00297     decode_end,
00298     decode_frame,
00299     .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00300 };
00301 

Generated on Fri Sep 16 2011 17:17:45 for FFmpeg by  doxygen 1.7.1