• 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[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: //skip
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){ //raw block
00115                 for(y = 0; y < 4; y++)
00116                     memcpy(cur + y*width, buf + y*4, 4);
00117                 buf += 16;
00118             }else{ // motion compensation
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: // fill
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: // pattern fill
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     /* always report that the buffer was completely consumed */
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 

Generated on Tue Nov 4 2014 12:59:23 for ffmpeg by  doxygen 1.7.1