[FFmpeg-devel] [PATCH] Mimic decoder
Måns Rullgård
mans
Wed Mar 12 00:04:29 CET 2008
Ramiro Polla <ramiro at lisha.ufsc.br> writes:
> Hello,
>
> I have taken libmimic [0] and used it to implement a native Mimic [1]
> decoder for FFmpeg.
>
> The Mimic codec is used by MSN Messenger to transmit Webcam
> conversations (not Video Conversations). It is also supported by aMSN
> and Mercury Messenger. IIRC, those two programs allow to record the
> streamed data. There's also MSN Webcam Recorder [2] that can record
> those streams.
>
> I have the whole history in an SVN server [3] that goes all the way
> back to the first integration that had only minor changes from the
> original code (like glib's ints to C99).
>
> There's one big issue that we discussed some on IRC and I decided to
> take to the list. The original code does lots of deblocking as
> post-processing. Some people on IRC said libavcodec should not do pure
> post-processing (it's not in-loop), and that I should drop that
> code. But pretty much every user that will use this expects the output
> to be the same as in MSN Messenger (which does the deblocking). So, is
> there any chance the deblocking can be accepted in the codec? If so,
> I'd need to clean it up some more.
>
> Ramiro Polla
> [0] http://sourceforge.net/projects/farsight/
> [1] http://wiki.multimedia.cx/index.php?title=Mimic
> [2] http://ml20rc.msnfanatic.com
> [3] http://msnwcrec.googlecode.com
> /*
> * Copyright (C) 2005 Ole Andr? Vadla Ravn?s <oleavr at gmail.com>
> * Copyright (C) 2008 Ramiro Polla <ramiro at lisha.ufsc.br>
> *
> * This file is part of FFmpeg.
> *
> * FFmpeg is free software; you can redistribute it and/or
> * modify it under the terms of the GNU Lesser General Public
> * License as published by the Free Software Foundation; either
> * version 2.1 of the License, or (at your option) any later version.
> *
> * FFmpeg is distributed in the hope that it will be useful,
> * but WITHOUT ANY WARRANTY; without even the implied warranty of
> * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> * Lesser General Public License for more details.
> *
> * You should have received a copy of the GNU Lesser General Public
> * License along with FFmpeg; if not, write to the Free Software
> * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> */
>
> #include <stdlib.h>
> #include <string.h>
> #include <stdint.h>
>
> #include "avcodec.h"
> #include "bitstream.h"
> #include "dsputil.h"
>
> typedef struct {
> int width;
> int height;
> enum PixelFormat pix_fmt;
Why do you duplicate these here? They are already in AVCodecContext.
> int f[2];
>
> int num_vblocks_y;
> int num_hblocks_y;
>
> int num_vblocks_cbcr;
> int num_hblocks_cbcr;
>
> AVFrame prev_frame;
>
> uint8_t *swap_buf;
> int swap_buf_size;
>
> int8_t vlcdec_lookup[8][128];
>
> int ptr_index;
> AVFrame buf_ptrs[16];
>
> GetBitContext gb;
> ScanTable scantable;
> DSPContext dsp;
> VLC vlc1;
>
> AVFrame picture;
> } MimicContext;
>
> //#define MIMIC_POSTPROC
>
> #ifdef MIMIC_POSTPROC
> static void deblock_horizontal(uint8_t *blocks, unsigned int stride, unsigned int row_count);
> static void deblock_vertical(uint8_t *blocks, unsigned int stride, unsigned int row_count);
>
> static int deblock_h_consider_entire(uint8_t *blocks, unsigned int stride);
> static void deblock_h_do_entire(uint8_t *blocks, unsigned int stride);
> static void deblock_h_do_boundaries(uint8_t *blocks, unsigned int stride);
>
> static int deblock_v_consider_entire(uint8_t *blocks, unsigned int stride);
> static void deblock_v_do_entire(uint8_t *blocks, unsigned int stride);
> static void deblock_v_do_boundaries(uint8_t *blocks, unsigned int stride);
>
> static void deblock(uint8_t *blocks, unsigned int stride, unsigned int row_count);
> #endif
>
> static void bswap_buf(uint8_t *newbuf, const uint8_t *oldbuf, int bufsize)
> {
> int i;
> for(i = 0 ; i < (bufsize >> 2) ; i++)
> ((uint32_t*) newbuf)[i] = bswap_32(((const uint32_t*) oldbuf)[i]);
> }
Use DSPContext.bswap_buf().
> static const uint8_t magic_values[][2] = {
> { 0, 1 }, { 0, 2 }, { 0, 3 }, { 0, 0 }, { 1, 1 }, { 0, 4 },
> { 0, 5 }, { 2, 1 }, { 3, 1 }, { 1, 2 }, { 1, 3 }, { 0, 6 },
> { 4, 1 }, { 5, 1 }, { 6, 1 }, { 2, 2 }, { 1, 4 }, { 7, 1 },
> { 8, 1 }, { 3, 2 }, { 4, 2 }, { 5, 2 }, { 2, 3 }, { 2, 4 },
> { 1, 5 }, { 1, 6 }, { 0, 7 }, { 9, 1 }, { 10, 1 }, { 11, 1 },
> { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 }, { 6, 2 }, { 7, 2 },
> { 8, 2 }, { 9, 2 }, { 10, 2 }, { 11, 2 }, { 12, 2 }, { 13, 2 },
> { 14, 2 }, { 3, 3 }, { 4, 3 }, { 5, 3 }, { 6, 3 }, { 7, 3 },
> { 8, 3 }, { 9, 3 }, { 10, 3 }, { 11, 3 }, { 12, 3 }, { 13, 3 },
> { 14, 3 }, { 3, 4 }, { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 },
> { 8, 4 }, { 9, 4 }, { 10, 4 }, { 11, 4 }, { 12, 4 }, { 13, 4 },
> { 14, 4 }, { 2, 5 }, { 3, 5 }, { 4, 5 }, { 5, 5 }, { 6, 5 },
> { 7, 5 }, { 8, 5 }, { 9, 5 }, { 10, 5 }, { 11, 5 }, { 12, 5 },
> { 13, 5 }, { 14, 5 }, { 2, 6 }, { 3, 6 }, { 4, 6 }, { 5, 6 },
> { 6, 6 }, { 7, 6 }, { 8, 6 }, { 9, 6 }, { 10, 6 }, { 11, 6 },
> { 12, 6 }, { 13, 6 }, { 14, 6 }, { 1, 7 }, { 2, 7 }, { 3, 7 },
> { 4, 7 }, { 5, 7 }, { 6, 7 }, { 7, 7 }, { 8, 7 }, { 9, 7 },
> { 10, 7 }, { 11, 7 }, { 12, 7 }, { 13, 7 }, { 14, 7 },
> };
>
> /*
> * vlc_decode_block
> *
> * De-serialize (reconstruct) a variable length coded 8x8 block.
> */
> static int vlc_decode_block(MimicContext *ctx, DCTELEM *block, int num_coeffs)
> {
> unsigned int pos;
>
> memset(block, 0, 64 * sizeof(DCTELEM));
>
> /* The DC-value is read in as is. */
> block[0] = get_bits(&ctx->gb, 8);
>
> for(pos = 1; pos < num_coeffs; pos++) {
> uint32_t vlc, num_bits;
> int value;
>
> vlc = get_vlc2(&ctx->gb, ctx->vlc1.table, ctx->vlc1.bits, 4);
> if(vlc == -1)
> return 0;
> if(vlc == 3) /* end-of-block code */
> return 1;
>
> pos += magic_values[vlc][0];
> num_bits = magic_values[vlc][1];
>
> value = get_bits(&ctx->gb, num_bits);
>
> block[ctx->scantable.permutated[pos]] = ctx->vlcdec_lookup[num_bits][value];
> }
It would be nice if you could somehow avoid that memset(). Do you
have any idea how many coefficients are typically coded? Maybe it's
few enough that it doesn't matter.
> return 1;
> }
>
> static void dequant_block(MimicContext *ctx, DCTELEM *block, int is_chrom)
> {
> int i, f = ctx->f[is_chrom];
Why don't you make 'f' an argument to this function instead?
> /* FFmpeg's IDCT behaves somewhat different from the original code, so
> * a factor of 4 was added to the input */
>
> /* De-quantize. */
> block[0] <<= 3;
> block[1] <<= 4;
> block[8] <<= 4;
>
> for(i = 2; i < 64; i++) {
> if(i == 8)
> continue;
>
> /* TODO Use >> 10 instead of / 1001 */
> block[i] = (block[i] * f) / 1001;
> }
> }
I doubt this works properly with permuted blocks.
> /*
> * decode_main
> *
> * Main decoding loop.
> */
> static int decode(MimicContext *ctx, int quality, int num_coeffs, int is_pframe)
> {
> int y, x, i, chrom_ch, offset;
> DECLARE_ALIGNED_16(DCTELEM, dct_block[64]);
> uint8_t *src, *dst, *p;
> uint8_t *base_src, *base_dst;
> uint32_t bit;
> int y_stride = ctx->picture.linesize[0];
> int crcb_stride = ctx->picture.linesize[1];
> int crcb_size = ctx->picture.linesize[1] * (ctx->height>>1);
>
> /* Clear Cr and Cb planes. */
> memset(ctx->picture.data[1], 128, crcb_size);
> memset(ctx->picture.data[2], 128, crcb_size);
Why?
> ctx->f[0] = av_clip(10000-quality, 1000, 10000)<<2;
> ctx->f[1] = av_clip(10000-quality, 2000, 10000)<<2;
>
> /* Decode Y plane. */
> for(y = ctx->num_vblocks_y - 1; y >= 0 ; y--) {
What is it with Microsoft and inverted images?
> offset = (y_stride << 3) * y;
> src = ctx->prev_frame.data[0] + offset;
> dst = ctx->picture.data[0] + offset;
> for(x = 0; x < ctx->num_hblocks_y; x++) {
> /* Check for a change condition in the current block. */
> bit = is_pframe ? get_bits1(&ctx->gb) : 0;
> if(!bit) {
> /* Yes: Is the new content the same as it was in one of
> * the 15 last frames preceding the previous? */
> if(is_pframe)
> bit = get_bits1(&ctx->gb);
This looks like it could be a case for decode012(), not sure.
> if(!bit) {
> /* No: decode it. */
> if(!vlc_decode_block(ctx, dct_block, num_coeffs)) {
> /* Corruped frame, return. */
> return 0;
> }
> dequant_block(ctx, dct_block, 0);
> ctx->dsp.idct_put(dst+7*y_stride, -y_stride, dct_block);
> } else {
> uint32_t backref;
Make that a plain 'unsigned'. There is no need to force exactly 32 bits.
> /* Yes: read the backreference (4 bits) and copy. */
> backref = get_bits(&ctx->gb, 4);
> p = ctx->buf_ptrs[(ctx->ptr_index + backref) % 16].data[0];
Do you trust the compiler with the % operator? Better use & 15 instead.
> p += offset + (x << 3);
> for(i = 7; i >= 0; i--) {
> int new_offset = y_stride * i;
> memcpy(dst + new_offset, p + new_offset, 8);
> }
for (i = 0; i < 8; i++) {
memcpy(dst + offset, p + offset, 8);
offset += y_stride;
}
> }
> } else {
> /* No change no worries: just copy from the previous frame. */
> for(i = 7; i >= 0; i--) {
> int new_offset = y_stride * i;
> memcpy(dst + new_offset, src + new_offset, 8);
> }
Can you think of a nice way to combine those two identical for()
loops?
> }
> src += 8;
> dst += 8;
> }
> }
>
> /* Decode Cr and Cb planes. */
> for(chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
> base_src = (chrom_ch ? ctx->prev_frame.data[1] : ctx->prev_frame.data[2]);
> base_dst = (chrom_ch ? ctx->picture.data[1] : ctx->picture.data[2]);
for (chrom_ch = 1; chrom_ch <= 2; chrom_ch++) {
base_dst = ctx->prev_frame.data[3-chrom_ch];
...
> for(y = ctx->num_vblocks_cbcr - 1; y >= 0 ; y--) {
> unsigned int num_rows = 8;
> /* The last row of blocks in chrominance for 160x120 resolution
> * is half the normal height and must be accounted for. */
> if(y + 1 == ctx->num_vblocks_cbcr && ctx->height % 16)
> num_rows = 4;
How does this interact with 8x8 IDCT blocks?
And never use the % operator.
> offset = (crcb_stride << 3) * y;
> src = base_src + offset;
> dst = base_dst + offset;
> for(x = 0; x < ctx->num_hblocks_cbcr; x++) {
> /* Check for a change condition in the current block. */
> bit = is_pframe ? get_bits1(&ctx->gb) : 1;
> if(bit == 1) {
> /* Yes: decode it. */
> if(!vlc_decode_block(ctx, dct_block, num_coeffs)) {
> /* Corrupted frame: clear Cr and Cb planes and return. */
> memset(ctx->picture.data[1], 128, crcb_size);
> memset(ctx->picture.data[2], 128, crcb_size);
Why?
> return 0;
> }
> dequant_block(ctx, dct_block, 1);
> ctx->dsp.idct_put(dst+7*crcb_stride, -crcb_stride, dct_block);
> } else {
> /* No change no worries: just copy from the previous frame. */
> for(i = num_rows-1; i >= 0; i--) {
> int new_offset = crcb_stride * i;
> memcpy(dst + new_offset, src + new_offset, 8);
> }
> }
> src += 8;
> dst += 8;
> }
> }
> }
The chroma code is very similar to the luma code. No chance they
could be merged?
> /*
> * Make a copy of the current frame and store in
> * the circular pointer list of 16 entries.
> */
> ctx->prev_frame = ctx->buf_ptrs[ctx->ptr_index];
>
> av_picture_copy((AVPicture*)&ctx->prev_frame, (AVPicture*)&ctx->picture,
> ctx->pix_fmt, ctx->width, ctx->height);
>
> if(--ctx->ptr_index < 0)
> ctx->ptr_index = 15;
This isn't speed critical, but ctx->ptr_index--; ctx->ptr_index &= 15
is faster.
> #ifdef MIMIC_POSTPROC
> /* Perform deblocking on all planes. */
> deblock(ctx->picture.data[0], y_stride, ctx->height);
> deblock(ctx->picture.data[1], crcb_stride, ctx->height>>1);
> deblock(ctx->picture.data[2], crcb_stride, ctx->height>>1);
> #endif
>
> return 1;
> }
>
> #ifdef MIMIC_POSTPROC
[...]
Not commenting on this for now.
> #endif
>
> static const uint8_t col_zag[64] = {
> 0, 8, 1, 2, 9, 16, 24, 17,
> 10, 3, 4, 11, 18, 25, 32, 40,
> 33, 26, 19, 12, 5, 6, 13, 20,
> 27, 34, 41, 48, 56, 49, 42, 35,
> 28, 21, 14, 7, 15, 22, 29, 36,
> 43, 50, 57, 58, 51, 44, 37, 30,
> 23, 31, 38, 45, 52, 59, 39, 46,
> 53, 60, 61, 54, 47, 55, 62, 63
> };
>
> static const uint32_t huffcodes[] = {
> 0x00000000, 0x00000001, 0x00000004, 0x0000000a, 0x0000000b, 0x0000000c,
> 0x0000001a, 0x0000001b, 0x00000038, 0x00000039, 0x0000003a, 0x0000003b,
> 0x00000078, 0x00000079, 0x0000007a, 0x0000007b, 0x000000f8, 0x000000f9,
> 0x000000fa, 0x000000fb, 0x000001f8, 0x000001f9, 0x000001fa, 0x000001fb,
> 0x000003f8, 0x000003f9, 0x000003fa, 0x000003fb, 0x000007f8, 0x000007f9,
> 0x000007fa, 0x000007fb, 0x00000ff8, 0x00000ff9, 0x00000ffa, 0x00000ffb,
> 0x00001ff8, 0x00001ff9, 0x00001ffa, 0x00001ffb, 0x00003ff8, 0x00003ff9,
> 0x00003ffa, 0x00003ffb, 0x00007ff8, 0x00007ff9, 0x00007ffa, 0x00007ffb,
> 0x0000fff8, 0x0000fff9, 0x0000fffa, 0x0000fffb, 0x0001fff8, 0x0001fff9,
> 0x0001fffa, 0x0001fffb, 0x0003fff8, 0x0003fff9, 0x0003fffa, 0x0003fffb,
> 0x0007fff8, 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9,
> 0x000ffffa, 0x000ffffb, 0x001ffff8, 0x001ffff9, 0x001ffffa, 0x001ffffb,
> 0x003ffff8, 0x003ffff9, 0x003ffffa, 0x003ffffb, 0x007ffff8, 0x007ffff9,
> 0x007ffffa, 0x007ffffb, 0x00fffff8, 0x00fffff9, 0x00fffffa, 0x00fffffb,
> 0x01fffff8, 0x01fffff9, 0x01fffffa, 0x01fffffb, 0x03fffff8, 0x03fffff9,
> 0x03fffffa, 0x03fffffb, 0x07fffff8, 0x07fffff9, 0x07fffffa, 0x07fffffb,
> 0x0ffffff8, 0x0ffffff9, 0x0ffffffa, 0x0ffffffb, 0x1ffffff8, 0x1ffffff9,
> 0x1ffffffa, 0x1ffffffb, 0x3ffffff8, 0x3ffffff9, 0x3ffffffa,
> };
>
> static const uint8_t huffbits[] = {
> 2, 2, 3, 4, 4, 4, 5, 5, 6, 6, 6, 6,
> 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9,
> 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12,
> 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
> 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
> 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
> 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24,
> 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
> 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30,
> };
Those last two tables look like they could be computed by some simple
expressions (which I am too lazy to work out right now).
> /*
> * initialize_vlcdec_lookup
> *
> * Internal helper-function used to initialize
> * the lookup-table used by the VLC-decoder.
> */
> static void initialize_vlcdec_lookup(int8_t lookup_tbl[8][128])
> {
> int i, j;
>
> for(i = 1 ; i < 8 ; i++) {
> int first = (1<<i)-1;
> int last = 1<<(i-1);
> int cur = first;
>
> for(j = 0 ; cur >= last ; cur--) {
> lookup_tbl[i][j++] = -cur;
> lookup_tbl[i][j++] = cur;
> }
> }
> }
>
> static int mimic_decode_init(AVCodecContext *avctx)
> {
> MimicContext *ctx = avctx->priv_data;
> int width, height;
> int i;
>
> if(!avctx->extradata) {
> av_log(avctx, AV_LOG_ERROR, "extradata missing!\n");
> return -1;
> }
You should check the size of extradata too.
> width = AV_RL16(avctx->extradata + 4);
> height = AV_RL16(avctx->extradata + 6);
>
> if(!(width == 160 && height == 120) && !(width == 320 && height == 240)) {
> av_log(avctx, AV_LOG_ERROR, "invalid width/height!\n");
> return -1;
> }
>
> ctx->width = avctx->width = width ;
> ctx->height = avctx->height = height;
> ctx->pix_fmt = avctx->pix_fmt = PIX_FMT_YUV420P;
Why?
> ctx->num_vblocks_y = ctx->height >> 3;
> ctx->num_hblocks_y = ctx->width >> 3;
> ctx->num_vblocks_cbcr = ctx->height >> 4;
> ctx->num_hblocks_cbcr = ctx->width >> 4;
> if(ctx->height % 16)
> ctx->num_vblocks_cbcr++;
ctx->num_vblocks_cbcr += !!(ctx->height & 15), if you like a little
obfuscation. In a speed-critical place, it would probably be faster.
> ctx->ptr_index = 15;
>
> for(i = 0; i < 16; i++) {
> if(avctx->get_buffer(avctx, &ctx->buf_ptrs[i])) {
> av_log(avctx, AV_LOG_ERROR, "could not get buffer\n");
> return -1;
> }
> }
>
> initialize_vlcdec_lookup(ctx->vlcdec_lookup);
> if(init_vlc(&ctx->vlc1, 8, sizeof(huffbits)/sizeof(huffbits[0]),
> huffbits, 1, 1, huffcodes, 4, 4, 0)) {
> av_log(avctx, AV_LOG_ERROR, "error initializing vlc table\n");
> return -1;
> }
> dsputil_init(&ctx->dsp, avctx);
> ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, col_zag);
> ctx->picture.data[0] = NULL;
>
> return 0;
> }
>
> static int mimic_decode_frame(AVCodecContext *avctx, void *data,
> int *data_size, const uint8_t *buf, int buf_size)
> {
> MimicContext *ctx = avctx->priv_data;
> int is_pframe;
> int width, height;
> int quality, num_coeffs;
>
> if(ctx->picture.data[0]) {
> avctx->release_buffer(avctx, &ctx->picture);
> }
>
> if(avctx->get_buffer(avctx, &ctx->picture)) {
> av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
> return -1;
> }
>
> width = AV_RL16(buf + 4);
> height = AV_RL16(buf + 6);
>
> if(width != ctx->width || height != ctx->height) {
> av_log(avctx, AV_LOG_ERROR, "resolution changing is not supported\n");
> return -1;
> }
>
> quality = AV_RL16(buf + 2);
> is_pframe = AV_RL32(buf + 12);
> num_coeffs = buf[16];
You should check the buffer size before reading.
> if(!(is_pframe && !ctx->prev_frame.data[0])) {
> int swap_buf_size = buf_size - 20;
> ctx->swap_buf = av_fast_realloc(ctx->swap_buf, &ctx->swap_buf_size,
> swap_buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
> if(!ctx->swap_buf)
> return AVERROR_NOMEM;
>
> /* TODO find out why dsp.bswap_buf crashes */
Did you ask Valgrind?
> bswap_buf(ctx->swap_buf, buf + 20, swap_buf_size);
> init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3);
>
> if(!decode(ctx, quality, num_coeffs, is_pframe))
> return -1;
> } else {
> av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n");
> return -1;
> }
>
> ctx->picture.pict_type = is_pframe ? FF_P_TYPE : FF_I_TYPE;
> *(AVFrame*)data = ctx->picture;
> *data_size = sizeof(AVFrame);
>
> return buf_size;
> }
>
> static int mimic_decode_end(AVCodecContext *avctx)
> {
> MimicContext *ctx = avctx->priv_data;
> int i;
>
> if(ctx->swap_buf)
> av_free(ctx->swap_buf);
Useless if().
> for(i = 0; i < 16; i++)
> avctx->release_buffer(avctx, &ctx->buf_ptrs[i]);
> free_vlc(&ctx->vlc1);
> if(ctx->picture.data[0])
> avctx->release_buffer(avctx, &ctx->picture);
>
> return 0;
> }
>
> AVCodec mimic_decoder = {
> "mimic",
> CODEC_TYPE_VIDEO,
> CODEC_ID_MIMIC,
> sizeof(MimicContext),
> mimic_decode_init,
> NULL,
> mimic_decode_end,
> mimic_decode_frame
> };
> Index: libavcodec/Makefile
> ===================================================================
> --- libavcodec/Makefile (revision 12363)
> +++ libavcodec/Makefile (working copy)
> @@ -100,6 +100,7 @@
> OBJS-$(CONFIG_LOCO_DECODER) += loco.o golomb.o
> OBJS-$(CONFIG_MACE3_DECODER) += mace.o
> OBJS-$(CONFIG_MACE6_DECODER) += mace.o
> +OBJS-$(CONFIG_MIMIC_DECODER) += mimic.o
> OBJS-$(CONFIG_MJPEG_DECODER) += mjpegdec.o mjpeg.o
> OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpeg.o mpegvideo_enc.o motion_est.o ratecontrol.o mpeg12data.o mpegvideo.o
> OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o mjpegdec.o mjpeg.o
> Index: libavcodec/allcodecs.c
> ===================================================================
> --- libavcodec/allcodecs.c (revision 12363)
> +++ libavcodec/allcodecs.c (working copy)
> @@ -101,6 +101,7 @@
> REGISTER_ENCODER (LJPEG, ljpeg);
> REGISTER_DECODER (LOCO, loco);
> REGISTER_DECODER (MDEC, mdec);
> + REGISTER_DECODER (MIMIC, mimic);
> REGISTER_ENCDEC (MJPEG, mjpeg);
> REGISTER_DECODER (MJPEGB, mjpegb);
> REGISTER_DECODER (MMVIDEO, mmvideo);
> Index: libavcodec/avcodec.h
> ===================================================================
> --- libavcodec/avcodec.h (revision 12363)
> +++ libavcodec/avcodec.h (working copy)
> @@ -178,6 +178,7 @@
> CODEC_ID_SUNRAST,
> CODEC_ID_INDEO4,
> CODEC_ID_INDEO5,
> + CODEC_ID_MIMIC,
>
> /* various PCM "codecs" */
> CODEC_ID_PCM_S16LE= 0x10000,
Last 3 files OK.
--
M?ns Rullg?rd
mans at mansr.com
More information about the ffmpeg-devel
mailing list