• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • 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 Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; 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     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] = 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: //skip
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){ //raw block
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{ // motion compensation
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: // fill
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: // pattern fill
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 = 1;
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         vb_decode_framedata(c, offset);
00216         bytestream2_skip(&c->stream, size - 4);
00217     }
00218     if(flags & VB_HAS_PALETTE){
00219         size = bytestream2_get_le32(&c->stream);
00220         vb_decode_palette(c, size);
00221     }
00222 
00223     memcpy(c->pic.data[1], c->pal, AVPALETTE_SIZE);
00224     c->pic.palette_has_changed = flags & VB_HAS_PALETTE;
00225 
00226     outptr = c->pic.data[0];
00227     srcptr = c->frame;
00228 
00229     for(i = 0; i < avctx->height; i++){
00230         memcpy(outptr, srcptr, avctx->width);
00231         srcptr += avctx->width;
00232         outptr += c->pic.linesize[0];
00233     }
00234 
00235     FFSWAP(uint8_t*, c->frame, c->prev_frame);
00236 
00237     *data_size = sizeof(AVFrame);
00238     *(AVFrame*)data = c->pic;
00239 
00240     /* always report that the buffer was completely consumed */
00241     return avpkt->size;
00242 }
00243 
00244 static av_cold int decode_init(AVCodecContext *avctx)
00245 {
00246     VBDecContext * const c = avctx->priv_data;
00247 
00248     c->avctx = avctx;
00249     avctx->pix_fmt = PIX_FMT_PAL8;
00250 
00251     c->frame      = av_mallocz(avctx->width * avctx->height);
00252     c->prev_frame = av_mallocz(avctx->width * avctx->height);
00253 
00254     return 0;
00255 }
00256 
00257 static av_cold int decode_end(AVCodecContext *avctx)
00258 {
00259     VBDecContext *c = avctx->priv_data;
00260 
00261     av_freep(&c->frame);
00262     av_freep(&c->prev_frame);
00263     if(c->pic.data[0])
00264         avctx->release_buffer(avctx, &c->pic);
00265 
00266     return 0;
00267 }
00268 
00269 AVCodec ff_vb_decoder = {
00270     .name           = "vb",
00271     .type           = AVMEDIA_TYPE_VIDEO,
00272     .id             = CODEC_ID_VB,
00273     .priv_data_size = sizeof(VBDecContext),
00274     .init           = decode_init,
00275     .close          = decode_end,
00276     .decode         = decode_frame,
00277     .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"),
00278 };
00279 
Generated on Thu Jan 24 2013 17:08:54 for Libav by doxygen 1.7.1