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

libavcodec/mimic.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005  Ole André Vadla Ravnås <oleavr@gmail.com>
00003  * Copyright (C) 2008  Ramiro Polla <ramiro@lisha.ufsc.br>
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 
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <stdint.h>
00025 
00026 #include "avcodec.h"
00027 #include "get_bits.h"
00028 #include "bytestream.h"
00029 #include "dsputil.h"
00030 
00031 #define MIMIC_HEADER_SIZE   20
00032 
00033 typedef struct {
00034     AVCodecContext *avctx;
00035 
00036     int             num_vblocks[3];
00037     int             num_hblocks[3];
00038 
00039     void           *swap_buf;
00040     int             swap_buf_size;
00041 
00042     int             cur_index;
00043     int             prev_index;
00044 
00045     AVFrame         buf_ptrs    [16];
00046     AVPicture       flipped_ptrs[16];
00047 
00048     DECLARE_ALIGNED(16, DCTELEM, dct_block)[64];
00049 
00050     GetBitContext   gb;
00051     ScanTable       scantable;
00052     DSPContext      dsp;
00053     VLC             vlc;
00054 } MimicContext;
00055 
00056 static const uint32_t huffcodes[] = {
00057     0x0000000a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
00058     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
00059     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000b,
00060     0x0000001b, 0x00000038, 0x00000078, 0x00000079, 0x0000007a, 0x000000f9,
00061     0x000000fa, 0x000003fb, 0x000007f8, 0x000007f9, 0x000007fa, 0x000007fb,
00062     0x00000ff8, 0x00000ff9, 0x00000001, 0x00000039, 0x0000007b, 0x000000fb,
00063     0x000001f8, 0x000001f9, 0x00000ffa, 0x00000ffb, 0x00001ff8, 0x00001ff9,
00064     0x00001ffa, 0x00001ffb, 0x00003ff8, 0x00003ff9, 0x00003ffa, 0x00000000,
00065     0x00000004, 0x0000003a, 0x000001fa, 0x00003ffb, 0x00007ff8, 0x00007ff9,
00066     0x00007ffa, 0x00007ffb, 0x0000fff8, 0x0000fff9, 0x0000fffa, 0x0000fffb,
00067     0x0001fff8, 0x0001fff9, 0x0001fffa, 0x00000000, 0x0000000c, 0x000000f8,
00068     0x000001fb, 0x0001fffb, 0x0003fff8, 0x0003fff9, 0x0003fffa, 0x0003fffb,
00069     0x0007fff8, 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9,
00070     0x000ffffa, 0x00000000, 0x0000001a, 0x000003f8, 0x000ffffb, 0x001ffff8,
00071     0x001ffff9, 0x001ffffa, 0x001ffffb, 0x003ffff8, 0x003ffff9, 0x003ffffa,
00072     0x003ffffb, 0x007ffff8, 0x007ffff9, 0x007ffffa, 0x007ffffb, 0x00000000,
00073     0x0000003b, 0x000003f9, 0x00fffff8, 0x00fffff9, 0x00fffffa, 0x00fffffb,
00074     0x01fffff8, 0x01fffff9, 0x01fffffa, 0x01fffffb, 0x03fffff8, 0x03fffff9,
00075     0x03fffffa, 0x03fffffb, 0x07fffff8, 0x00000000, 0x000003fa, 0x07fffff9,
00076     0x07fffffa, 0x07fffffb, 0x0ffffff8, 0x0ffffff9, 0x0ffffffa, 0x0ffffffb,
00077     0x1ffffff8, 0x1ffffff9, 0x1ffffffa, 0x1ffffffb, 0x3ffffff8, 0x3ffffff9,
00078     0x3ffffffa,
00079 };
00080 
00081 static const uint8_t huffbits[] = {
00082      4,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
00083      0,  0,  0,  0,  2,  4,  5,  6,  7,  7,  7,  8,
00084      8, 10, 11, 11, 11, 11, 12, 12,  2,  6,  7,  8,
00085      9,  9, 12, 12, 13, 13, 13, 13, 14, 14, 14,  0,
00086      3,  6,  9, 14, 15, 15, 15, 15, 16, 16, 16, 16,
00087     17, 17, 17,  0,  4,  8,  9, 17, 18, 18, 18, 18,
00088     19, 19, 19, 19, 20, 20, 20,  0,  5, 10, 20, 21,
00089     21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,  0,
00090      6, 10, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26,
00091     26, 26, 27,  0, 10, 27, 27, 27, 28, 28, 28, 28,
00092     29, 29, 29, 29, 30, 30, 30,
00093 };
00094 
00095 static const uint8_t col_zag[64] = {
00096      0,  8,  1,  2,  9, 16, 24, 17,
00097     10,  3,  4, 11, 18, 25, 32, 40,
00098     33, 26, 19, 12,  5,  6, 13, 20,
00099     27, 34, 41, 48, 56, 49, 42, 35,
00100     28, 21, 14,  7, 15, 22, 29, 36,
00101     43, 50, 57, 58, 51, 44, 37, 30,
00102     23, 31, 38, 45, 52, 59, 39, 46,
00103     53, 60, 61, 54, 47, 55, 62, 63,
00104 };
00105 
00106 static av_cold int mimic_decode_init(AVCodecContext *avctx)
00107 {
00108     MimicContext *ctx = avctx->priv_data;
00109 
00110     ctx->prev_index = 0;
00111     ctx->cur_index = 15;
00112 
00113     if(init_vlc(&ctx->vlc, 11, FF_ARRAY_ELEMS(huffbits),
00114                  huffbits, 1, 1, huffcodes, 4, 4, 0)) {
00115         av_log(avctx, AV_LOG_ERROR, "error initializing vlc table\n");
00116         return -1;
00117     }
00118     dsputil_init(&ctx->dsp, avctx);
00119     ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, col_zag);
00120 
00121     return 0;
00122 }
00123 
00124 static const int8_t vlcdec_lookup[9][64] = {
00125     {    0, },
00126     {   -1,   1, },
00127     {   -3,   3,   -2,   2, },
00128     {   -7,   7,   -6,   6,   -5,   5,   -4,   4, },
00129     {  -15,  15,  -14,  14,  -13,  13,  -12,  12,
00130        -11,  11,  -10,  10,   -9,   9,   -8,   8, },
00131     {  -31,  31,  -30,  30,  -29,  29,  -28,  28,
00132        -27,  27,  -26,  26,  -25,  25,  -24,  24,
00133        -23,  23,  -22,  22,  -21,  21,  -20,  20,
00134        -19,  19,  -18,  18,  -17,  17,  -16,  16, },
00135     {  -63,  63,  -62,  62,  -61,  61,  -60,  60,
00136        -59,  59,  -58,  58,  -57,  57,  -56,  56,
00137        -55,  55,  -54,  54,  -53,  53,  -52,  52,
00138        -51,  51,  -50,  50,  -49,  49,  -48,  48,
00139        -47,  47,  -46,  46,  -45,  45,  -44,  44,
00140        -43,  43,  -42,  42,  -41,  41,  -40,  40,
00141        -39,  39,  -38,  38,  -37,  37,  -36,  36,
00142        -35,  35,  -34,  34,  -33,  33,  -32,  32, },
00143     { -127, 127, -126, 126, -125, 125, -124, 124,
00144       -123, 123, -122, 122, -121, 121, -120, 120,
00145       -119, 119, -118, 118, -117, 117, -116, 116,
00146       -115, 115, -114, 114, -113, 113, -112, 112,
00147       -111, 111, -110, 110, -109, 109, -108, 108,
00148       -107, 107, -106, 106, -105, 105, -104, 104,
00149       -103, 103, -102, 102, -101, 101, -100, 100,
00150        -99,  99,  -98,  98,  -97,  97,  -96,  96, },
00151     {  -95,  95,  -94,  94,  -93,  93,  -92,  92,
00152        -91,  91,  -90,  90,  -89,  89,  -88,  88,
00153        -87,  87,  -86,  86,  -85,  85,  -84,  84,
00154        -83,  83,  -82,  82,  -81,  81,  -80,  80,
00155        -79,  79,  -78,  78,  -77,  77,  -76,  76,
00156        -75,  75,  -74,  74,  -73,  73,  -72,  72,
00157        -71,  71,  -70,  70,  -69,  69,  -68,  68,
00158        -67,  67,  -66,  66,  -65,  65,  -64,  64, },
00159 };
00160 
00161 static int vlc_decode_block(MimicContext *ctx, int num_coeffs, int qscale)
00162 {
00163     DCTELEM *block = ctx->dct_block;
00164     unsigned int pos;
00165 
00166     ctx->dsp.clear_block(block);
00167 
00168     block[0] = get_bits(&ctx->gb, 8) << 3;
00169 
00170     for(pos = 1; pos < num_coeffs; pos++) {
00171         uint32_t vlc, num_bits;
00172         int value;
00173         int coeff;
00174 
00175         vlc = get_vlc2(&ctx->gb, ctx->vlc.table, ctx->vlc.bits, 3);
00176         if(!vlc) /* end-of-block code */
00177             return 1;
00178         if(vlc == -1)
00179             return 0;
00180 
00181         /* pos_add and num_bits are coded in the vlc code */
00182         pos +=     vlc&15; // pos_add
00183         num_bits = vlc>>4; // num_bits
00184 
00185         if(pos >= 64)
00186             return 0;
00187 
00188         value = get_bits(&ctx->gb, num_bits);
00189 
00190         /* FFmpeg's IDCT behaves somewhat different from the original code, so
00191          * a factor of 4 was added to the input */
00192 
00193         coeff = vlcdec_lookup[num_bits][value];
00194         if(pos<3)
00195             coeff <<= 4;
00196         else /* TODO Use >> 10 instead of / 1001 */
00197             coeff = (coeff * qscale) / 1001;
00198 
00199         block[ctx->scantable.permutated[pos]] = coeff;
00200     }
00201 
00202     return 1;
00203 }
00204 
00205 static int decode(MimicContext *ctx, int quality, int num_coeffs,
00206                   int is_iframe)
00207 {
00208     int y, x, plane;
00209 
00210     for(plane = 0; plane < 3; plane++) {
00211         const int is_chroma = !!plane;
00212         const int qscale = av_clip(10000-quality,is_chroma?1000:2000,10000)<<2;
00213         const int stride = ctx->flipped_ptrs[ctx->cur_index].linesize[plane];
00214         const uint8_t *src = ctx->flipped_ptrs[ctx->prev_index].data[plane];
00215         uint8_t       *dst = ctx->flipped_ptrs[ctx->cur_index ].data[plane];
00216 
00217         for(y = 0; y < ctx->num_vblocks[plane]; y++) {
00218             for(x = 0; x < ctx->num_hblocks[plane]; x++) {
00219 
00220                 /* Check for a change condition in the current block.
00221                  * - iframes always change.
00222                  * - Luma plane changes on get_bits1 == 0
00223                  * - Chroma planes change on get_bits1 == 1 */
00224                 if(is_iframe || get_bits1(&ctx->gb) == is_chroma) {
00225 
00226                     /* Luma planes may use a backreference from the 15 last
00227                      * frames preceding the previous. (get_bits1 == 1)
00228                      * Chroma planes don't use backreferences. */
00229                     if(is_chroma || is_iframe || !get_bits1(&ctx->gb)) {
00230 
00231                         if(!vlc_decode_block(ctx, num_coeffs, qscale))
00232                             return 0;
00233                         ctx->dsp.idct_put(dst, stride, ctx->dct_block);
00234                     } else {
00235                         unsigned int backref = get_bits(&ctx->gb, 4);
00236                         int index = (ctx->cur_index+backref)&15;
00237                         uint8_t *p = ctx->flipped_ptrs[index].data[0];
00238 
00239                         if(p) {
00240                             p += src -
00241                                 ctx->flipped_ptrs[ctx->prev_index].data[plane];
00242                             ctx->dsp.put_pixels_tab[1][0](dst, p, stride, 8);
00243                         } else {
00244                             av_log(ctx->avctx, AV_LOG_ERROR,
00245                                      "No such backreference! Buggy sample.\n");
00246                         }
00247                     }
00248                 } else {
00249                     ctx->dsp.put_pixels_tab[1][0](dst, src, stride, 8);
00250                 }
00251                 src += 8;
00252                 dst += 8;
00253             }
00254             src += (stride - ctx->num_hblocks[plane])<<3;
00255             dst += (stride - ctx->num_hblocks[plane])<<3;
00256         }
00257     }
00258 
00259     return 1;
00260 }
00261 
00266 static void prepare_avpic(MimicContext *ctx, AVPicture *dst, AVPicture *src)
00267 {
00268     int i;
00269     dst->data[0] = src->data[0]+( ctx->avctx->height    -1)*src->linesize[0];
00270     dst->data[1] = src->data[2]+((ctx->avctx->height>>1)-1)*src->linesize[2];
00271     dst->data[2] = src->data[1]+((ctx->avctx->height>>1)-1)*src->linesize[1];
00272     for(i = 0; i < 3; i++)
00273         dst->linesize[i] = -src->linesize[i];
00274 }
00275 
00276 static int mimic_decode_frame(AVCodecContext *avctx, void *data,
00277                               int *data_size, AVPacket *avpkt)
00278 {
00279     const uint8_t *buf = avpkt->data;
00280     int buf_size = avpkt->size;
00281     MimicContext *ctx = avctx->priv_data;
00282     int is_pframe;
00283     int width, height;
00284     int quality, num_coeffs;
00285     int swap_buf_size = buf_size - MIMIC_HEADER_SIZE;
00286 
00287     if(buf_size < MIMIC_HEADER_SIZE) {
00288         av_log(avctx, AV_LOG_ERROR, "insufficient data\n");
00289         return -1;
00290     }
00291 
00292     buf       += 2; /* some constant (always 256) */
00293     quality    = bytestream_get_le16(&buf);
00294     width      = bytestream_get_le16(&buf);
00295     height     = bytestream_get_le16(&buf);
00296     buf       += 4; /* some constant */
00297     is_pframe  = bytestream_get_le32(&buf);
00298     num_coeffs = bytestream_get_byte(&buf);
00299     buf       += 3; /* some constant */
00300 
00301     if(!ctx->avctx) {
00302         int i;
00303 
00304         if(!(width == 160 && height == 120) &&
00305            !(width == 320 && height == 240)) {
00306             av_log(avctx, AV_LOG_ERROR, "invalid width/height!\n");
00307             return -1;
00308         }
00309 
00310         ctx->avctx     = avctx;
00311         avctx->width   = width;
00312         avctx->height  = height;
00313         avctx->pix_fmt = PIX_FMT_YUV420P;
00314         for(i = 0; i < 3; i++) {
00315             ctx->num_vblocks[i] = -((-height) >> (3 + !!i));
00316             ctx->num_hblocks[i] =     width   >> (3 + !!i) ;
00317         }
00318     } else if(width != ctx->avctx->width || height != ctx->avctx->height) {
00319         av_log(avctx, AV_LOG_ERROR, "resolution changing is not supported\n");
00320         return -1;
00321     }
00322 
00323     if(is_pframe && !ctx->buf_ptrs[ctx->prev_index].data[0]) {
00324         av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n");
00325         return -1;
00326     }
00327 
00328     ctx->buf_ptrs[ctx->cur_index].reference = 1;
00329     if(avctx->get_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index])) {
00330         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00331         return -1;
00332     }
00333 
00334     prepare_avpic(ctx, &ctx->flipped_ptrs[ctx->cur_index],
00335                   (AVPicture*) &ctx->buf_ptrs[ctx->cur_index]);
00336 
00337     av_fast_malloc(&ctx->swap_buf, &ctx->swap_buf_size,
00338                                  swap_buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
00339     if(!ctx->swap_buf)
00340         return AVERROR(ENOMEM);
00341 
00342     ctx->dsp.bswap_buf(ctx->swap_buf,
00343                         (const uint32_t*) buf,
00344                         swap_buf_size>>2);
00345     init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3);
00346 
00347     if(!decode(ctx, quality, num_coeffs, !is_pframe)) {
00348         avctx->release_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index]);
00349         return -1;
00350     }
00351 
00352     ctx->buf_ptrs[ctx->cur_index].pict_type = is_pframe ? FF_P_TYPE:FF_I_TYPE;
00353     *(AVFrame*)data = ctx->buf_ptrs[ctx->cur_index];
00354     *data_size = sizeof(AVFrame);
00355 
00356     ctx->prev_index = ctx->cur_index;
00357     ctx->cur_index--;
00358     ctx->cur_index &= 15;
00359 
00360     /* Only release frames that aren't used for backreferences anymore */
00361     if(ctx->buf_ptrs[ctx->cur_index].data[0])
00362         avctx->release_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index]);
00363 
00364     return buf_size;
00365 }
00366 
00367 static av_cold int mimic_decode_end(AVCodecContext *avctx)
00368 {
00369     MimicContext *ctx = avctx->priv_data;
00370     int i;
00371 
00372     av_free(ctx->swap_buf);
00373     for(i = 0; i < 16; i++)
00374         if(ctx->buf_ptrs[i].data[0])
00375             avctx->release_buffer(avctx, &ctx->buf_ptrs[i]);
00376     free_vlc(&ctx->vlc);
00377 
00378     return 0;
00379 }
00380 
00381 AVCodec mimic_decoder = {
00382     "mimic",
00383     AVMEDIA_TYPE_VIDEO,
00384     CODEC_ID_MIMIC,
00385     sizeof(MimicContext),
00386     mimic_decode_init,
00387     NULL,
00388     mimic_decode_end,
00389     mimic_decode_frame,
00390     CODEC_CAP_DR1,
00391     .long_name = NULL_IF_CONFIG_SMALL("Mimic"),
00392 };

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