[FFmpeg-devel] [PATCH] Common code for Indeo interactive
Michael Niedermayer
michaelni
Mon Mar 23 20:40:23 CET 2009
On Thu, Mar 19, 2009 at 11:12:40PM +0100, Maxim wrote:
> Hello guys,
>
> here is the 1st part of my patch making FFmpeg decode Indeo interactive
> (indeo4/indeo5) streams. Both codecs are very similar but use abit
> different bitstream formats, so I decided myself to put all common
> functions and tables together and submit them as a separate patch.
> The 2nd part will be the long-awaited indeo5 decoder...
> Please review!
your attached files are not unified diffs
[...]
> /**
> * @file ivi_common.c
> * This file contains functions and data shared by both Indeo4 and Indeo5 decoders.
> */
>
> #define ALT_BITSTREAM_READER_LE
> #include "avcodec.h"
> #include "bitstream.h"
> #include "ivi_common.h"
>
>
> /**
> * inverse "nbits" bits of the value "val" and return the result right-justified
> */
> static uint16_t ivi_inv_bits (uint16_t val, const int nbits)
> {
> uint16_t res = 0;
> int i;
>
> for (i = 0; i < nbits; i++) {
> res |= (val & 1) << (nbits-i-1);
> val >>= 1;
> }
> return res;
> }
we already have code to reverse bits and its table based and more efficient
also the ivi_ prefix seems unneeded
>
>
> /**
> * generates a huffman codebook from the given descriptor and convert it into the ffmpeg vlc table
> *
> * @param cb [in] pointer to codebook descriptor
> * @param pOut [out] where to place the generated VLC table
> * @param flag [in] flag: INIT_VLC_USE_STATIC or 0
> * @return result code: 0 - OK, -1 = error (invalid codebook descriptor)
> */
> int ivi_create_huff_from_desc (const IVIHuffDesc *cb, VLC *pOut, const int flag)
non static functions need a ff prefix
> {
> int result, pos, i, j, codes_per_row, prefix, last_row;
> uint16_t codewords[256]; /* FIXME: move this temporal storage out here? */
> uint8_t bits[256];
>
> pos = 0; /* current position = 0 */
>
> for (i = 0; i < cb->num_rows; i++) {
> codes_per_row = 1 << cb->xbits[i];
> last_row = (i - cb->num_rows + 1) != 0; /* = 0 for the last row */
> prefix = ((1 << i) - 1) << (cb->xbits[i] + last_row);
>
> for (j = 0; j < codes_per_row; j++) {
> if(pos >= 256) /* some indeo5 codebooks can have more as 256 elements */
> break; /* but only 256 codes are allowed! */
>
> bits[pos] = i + cb->xbits[i] + last_row;
> if (bits[pos] > IVI_VLC_BITS)
> return -1; /* invalid descriptor */
>
> codewords[pos] = ivi_inv_bits((prefix | j), bits[pos]);
> if (bits[pos] == 0)
> bits[pos] = 1;
>
> pos++;
> }//for j
> }//for i
>
> /* number of codewords = pos */
> result = init_vlc(pOut, IVI_VLC_BITS, pos, &bits[0], 1, 1, &codewords[0], 2, 2, (flag & INIT_VLC_USE_STATIC) | INIT_VLC_LE);
#define INIT_VLC_USE_STATIC 1 ///< VERY strongly deprecated and forbidden
[...]
> /**
> * compare two huffman codebook descriptors
> *
> * @param desc1 [in] ptr to the 1st descriptor to compare
> * @param desc2 [in] ptr to the 2nd descriptor to compare
> * @return comparison result: 0 - equal, 1 - not equal
> */
> int ivi_huff_desc_cmp (const IVIHuffDesc *desc1, const IVIHuffDesc *desc2)
> {
> int i;
>
> if (desc1->num_rows != desc2->num_rows)
> return 1;
>
> for (i = 0; i < desc1->num_rows; i++) {
> if (desc1->xbits[i] != desc2->xbits[i])
> return 1;
> }
> return 0;
> }
memcmp
>
>
> /**
> * copy huffman codebook descriptors
> *
> * @param dst [out] ptr to the destination descriptor
> * @param src [in] ptr to the source descriptor
> */
> void ivi_huff_desc_copy (IVIHuffDesc *dst, const IVIHuffDesc *src)
> {
> int i;
>
> dst->num_rows = src->num_rows;
>
> for (i = 0; i < src->num_rows; i++)
> dst->xbits[i] = src->xbits[i];
> }
memcpy
>
>
> /**
> * initialize planes (prepare descriptors, allocate buffers etc.)
> *
> * @param planes [in,out] pointer to the array of the plane descriptors
> * @param cfg [in] pointer to the ivi_pic_config structure describing picture layout
> * @return result code: 0 - OK
> */
> int ivi_init_planes (IVIPlaneDesc *planes, const IVIPicConfig *cfg)
> {
> int p;
> uint32_t width_aligned, height_aligned, buf_size;
>
> /* fill in the descriptor of the luminance plane */
> planes[0].width = cfg->pic_width;
> planes[0].height = cfg->pic_height;
> planes[0].num_bands = cfg->luma_bands;
vertical align
>
> /* allocate luma buffers (aligned on 16x16 for simplicity) */
> if (planes[0].buf1)
> av_free(planes[0].buf1);
teh if is redundant
[...]
> planes[1].buf1 = av_malloc(buf_size);
> if (planes[1].buf1 == NULL)
> return AVERROR(ENOMEM);
> planes[2].buf1 = av_malloc(buf_size);
> if (planes[2].buf1 == NULL)
> return AVERROR(ENOMEM);
> planes[1].buf2 = av_malloc(buf_size);
> if (planes[1].buf2 == NULL)
> return AVERROR(ENOMEM);
> planes[2].buf2 = av_malloc(buf_size);
> if (planes[2].buf2 == NULL)
> return AVERROR(ENOMEM);
loop
>
> if (planes[0].bands)
> av_free(planes[0].bands);
> planes[0].bands = av_mallocz(cfg->luma_bands * sizeof(IVIBandDesc));
> if (planes[0].bands == NULL)
> return AVERROR(ENOMEM);
>
> if (planes[1].bands)
> av_free(planes[1].bands);
> planes[1].bands = av_mallocz(cfg->chroma_bands * sizeof(IVIBandDesc));
> if (planes[1].bands == NULL)
> return AVERROR(ENOMEM);
>
> if (planes[2].bands)
> av_free(planes[2].bands);
> planes[2].bands = av_mallocz(cfg->chroma_bands * sizeof(IVIBandDesc));
> if (planes[2].bands == NULL)
> return AVERROR(ENOMEM);
loop
[...]
>
> /**
> * decode size of the tile data
> * it's stored as a variable-length field having the following format:
> * if (tile_data_size < 255) than this field is only one byte long
> * if (tile_data_size >= 255) than this field four is byte long: 0xFF X1 X2 X3
> * where X1-X3 is size of the tile data
> *
> * @param cb [in] pointer to codebook descriptor
> * @param gb [in,out] the GetBit context
> * @return size of the tile data in bytes
> */
> int ivi_dec_tile_data_size (GetBitContext *gb)
> {
> int len;
>
> if (get_bits1(gb)) {
> len = get_bits(gb, 8);
> if (len == 255)
> len = get_bits_long(gb, 24);
> }
> else
belong on the same line in K&R style
> len = 0;
>
> /* align the bitstream reader on the byte boundary */
> align_get_bits(gb);
>
> return (len);
useless ()
> }
>
>
> /* butterfly operation for the inverse slant transform */
> #define IVI_SLANT_BFLY(x,y) t1 = x-y; x+=y; y = t1;
>
> /* The following is a reflection using a,b = 1/2, 5/4 for the inverse slant transform */
> #define IVI_IREFLECT(s1,s2) {\
> t1 = ((s1*5) + (s2*2) + 2) >> 2;\
t1 = s1 + ((s1 + s2*2 + 2) >> 2);\
and similar simplifications are possible for the others
[...]
> IVI_INV_SLANT8(src[0], src[8], src[16], src[24], src[32], src[40], src[48], src[56], /* input operands*/
> dst[0], dst[8], dst[16], dst[24], dst[32], dst[40], dst[48], dst[56] /* output operands*/);
its known what src & dst are, the comments are redundant
[...]
> /**
> * this is a speed-up version of the inverse 2D slant transforms
> * for the case if there is a non-zero DC coeff and all AC coeffs are zero.
> * Performing the inverse slant transform in this case is equivalent to
> * spreading (DC_coeff + 1)/2 over the whole block.
> * It works much faster than performing the slant transform on a vector of zeroes.
> *
> * @param in [in] pointer to the dc coefficient
> * @param out [out] pointer to the output buffer (frame)
> * @param pitch [in] pitch to move to the next y line
> * @param blk_size [in] transform block size
> */
> void ivi_dc_slant_2d (int32_t *in, int16_t *out, uint32_t pitch, int blk_size)
> {
> int x, y;
> int16_t dc_coeff;
>
> dc_coeff = (*in + 1) >> 1;
>
> for (y = 0; y < blk_size; out += pitch, y++) {
> for (x = 0; x < blk_size; x++)
> out[x] = dc_coeff;
> }
> }
each row/col should be likely checked, not just all or none 0
>
>
> /**
> * 8x8 block motion compensation with adding delta
> *
> * @param buf [in,out] pointer to the block in the current frame buffer containing delta
> * @param ref_buf [in] pointer to the corresponding block in the reference frame
> * @param pitch [in] pitch for moving to the next y line
> * @param mc_type [in] interpolation type
> */
> static void ivi_mc_8x8_delta (int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type)
> {
> int i, r1, r2, r3, r4;
> int16_t *wptr;
>
> switch(mc_type) {
> case 0: /* fullpel (no interpolation) */
> for (i = 0; i < 8; i++) {
> buf[0] += ref_buf[0];
> buf[1] += ref_buf[1];
> buf[2] += ref_buf[2];
> buf[3] += ref_buf[3];
> buf[4] += ref_buf[4];
> buf[5] += ref_buf[5];
> buf[6] += ref_buf[6];
> buf[7] += ref_buf[7];
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 1: /* horizontal halfpel interpolation */
> for (i = 0; i < 8; i++) {
> r2 = ref_buf[1];
> r3 = ref_buf[2];
> r4 = ref_buf[3];
> buf[0] += (ref_buf[0] + r2) >> 1;
> buf[1] += (r2 + r3) >> 1;
> buf[2] += (r3 + r4) >> 1;
> r1 = ref_buf[4];
> buf[3] += (r4 + r1) >> 1;
> r2 = ref_buf[5];
> buf[4] += (r1 + r2) >> 1;
> r3 = ref_buf[6];
> buf[5] += (r2 + r3) >> 1;
> r4 = ref_buf[7];
> buf[6] += (r3 + r4) >> 1;
> r1 = ref_buf[8];
> buf[7] += (r4 + r1) >> 1;
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 2: /* vertical halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 8; i++) {
> buf[0] += (ref_buf[0] + wptr[0]) >> 1;
> buf[1] += (ref_buf[1] + wptr[1]) >> 1;
> buf[2] += (ref_buf[2] + wptr[2]) >> 1;
> buf[3] += (ref_buf[3] + wptr[3]) >> 1;
> buf[4] += (ref_buf[4] + wptr[4]) >> 1;
> buf[5] += (ref_buf[5] + wptr[5]) >> 1;
> buf[6] += (ref_buf[6] + wptr[6]) >> 1;
> buf[7] += (ref_buf[7] + wptr[7]) >> 1;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> case 3: /* vertical and horizontal halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 8; i++) {
> r1 = ref_buf[1];
> r2 = wptr[1];
> buf[0] += (ref_buf[0] + r1 + wptr[0] + r2) >> 2;
> r3 = ref_buf[2];
> r4 = wptr[2];
> buf[1] += (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[3];
> r2 = wptr[3];
> buf[2] += (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[4];
> r4 = wptr[4];
> buf[3] += (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[5];
> r2 = wptr[5];
> buf[4] += (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[6];
> r4 = wptr[6];
> buf[5] += (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[7];
> r2 = wptr[7];
> buf[6] += (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[8];
> r4 = wptr[8];
> buf[7] += (r1 + r3 + r2 + r4) >> 2;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> }
> }
this can be simplified alot
>
>
> /**
> * 4x4 block motion compensation with adding delta
> *
> * @param buf [in,out] pointer to the block in the current frame buffer containing delta
> * @param ref_buf [in] pointer to the corresponding block in the reference frame
> * @param pitch [in] pitch for moving to the next y line
> * @param mc_type [in] interpolation type
> */
> static void ivi_mc_4x4_delta (int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type)
> {
> int i, r1, r2, r3, r4;
> int16_t *wptr;
>
> switch(mc_type) {
> case 0: /* fullpel (no interpolation) */
> for (i = 0; i < 4; i++) {
> buf[0] += ref_buf[0];
> buf[1] += ref_buf[1];
> buf[2] += ref_buf[2];
> buf[3] += ref_buf[3];
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 1: /* horizontal halfpel interpolation */
> for (i = 0; i < 4; i++) {
> r2 = ref_buf[1];
> r3 = ref_buf[2];
> r4 = ref_buf[3];
> buf[0] += (ref_buf[0] + r2) >> 1;
> buf[1] += (r2 + r3) >> 1;
> buf[2] += (r3 + r4) >> 1;
> r1 = ref_buf[4];
> buf[3] += (r4 + r1) >> 1;
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 2: /* vertical halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 4; i++) {
> buf[0] += (ref_buf[0] + wptr[0]) >> 1;
> buf[1] += (ref_buf[1] + wptr[1]) >> 1;
> buf[2] += (ref_buf[2] + wptr[2]) >> 1;
> buf[3] += (ref_buf[3] + wptr[3]) >> 1;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> case 3: /* vertical and horizontal halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 4; i++) {
> r1 = ref_buf[1];
> r2 = wptr[1];
> buf[0] += (ref_buf[0] + r1 + wptr[0] + r2) >> 2;
> r3 = ref_buf[2];
> r4 = wptr[2];
> buf[1] += (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[3];
> r2 = wptr[3];
> buf[2] += (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[4];
> r4 = wptr[4];
> buf[3] += (r1 + r3 + r2 + r4) >> 2;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> }
> }
>
>
> /**
> * motion compensation without adding delta
> *
> * @param buf [in,out] pointer to the block in the current frame receiving the result
> * @param ref_buf [in] pointer to the corresponding block in the reference frame
> * @param pitch [in] pitch for moving to the next y line
> * @param mc_type [in] interpolation type
> */
> static void ivi_mc_8x8_no_delta (int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type)
> {
> int i, r1, r2, r3, r4;
> int16_t *wptr;
>
> switch(mc_type) {
> case 0: /* fullpel (no interpolation, just copy) */
> for (i = 0; i < 8; i++) {
> buf[0] = ref_buf[0];
> buf[1] = ref_buf[1];
> buf[2] = ref_buf[2];
> buf[3] = ref_buf[3];
> buf[4] = ref_buf[4];
> buf[5] = ref_buf[5];
> buf[6] = ref_buf[6];
> buf[7] = ref_buf[7];
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 1: /* horizontal halfpel interpolation */
> for (i = 0; i < 8; i++) {
> r2 = ref_buf[1];
> r3 = ref_buf[2];
> r4 = ref_buf[3];
> buf[0] = (ref_buf[0] + r2) >> 1;
> buf[1] = (r2 + r3) >> 1;
> buf[2] = (r3 + r4) >> 1;
> r1 = ref_buf[4];
> buf[3] = (r4 + r1) >> 1;
> r2 = ref_buf[5];
> buf[4] = (r1 + r2) >> 1;
> r3 = ref_buf[6];
> buf[5] = (r2 + r3) >> 1;
> r4 = ref_buf[7];
> buf[6] = (r3 + r4) >> 1;
> r1 = ref_buf[8];
> buf[7] = (r4 + r1) >> 1;
> buf += pitch;
> ref_buf += pitch;
> }
> break;
> case 2: /* vertical halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 8; i++) {
> buf[0] = (ref_buf[0] + wptr[0]) >> 1;
> buf[1] = (ref_buf[1] + wptr[1]) >> 1;
> buf[2] = (ref_buf[2] + wptr[2]) >> 1;
> buf[3] = (ref_buf[3] + wptr[3]) >> 1;
> buf[4] = (ref_buf[4] + wptr[4]) >> 1;
> buf[5] = (ref_buf[5] + wptr[5]) >> 1;
> buf[6] = (ref_buf[6] + wptr[6]) >> 1;
> buf[7] = (ref_buf[7] + wptr[7]) >> 1;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> case 3: /* vertical and horizontal halfpel interpolation */
> wptr = ref_buf + pitch;
> for (i = 0; i < 8; i++) {
> r1 = ref_buf[1];
> r2 = wptr[1];
> buf[0] = (ref_buf[0] + r1 + wptr[0] + r2) >> 2;
> r3 = ref_buf[2];
> r4 = wptr[2];
> buf[1] = (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[3];
> r2 = wptr[3];
> buf[2] = (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[4];
> r4 = wptr[4];
> buf[3] = (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[5];
> r2 = wptr[5];
> buf[4] = (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[6];
> r4 = wptr[6];
> buf[5] = (r1 + r3 + r2 + r4) >> 2;
> r1 = ref_buf[7];
> r2 = wptr[7];
> buf[6] = (r3 + r1 + r4 + r2) >> 2;
> r3 = ref_buf[8];
> r4 = wptr[8];
> buf[7] = (r1 + r3 + r2 + r4) >> 2;
> buf += pitch;
> wptr += pitch;
> ref_buf += pitch;
> }
> break;
> }
> }
>
>
> /**
> * 4x4 block motion compensation without adding delta
> *
> * @param buf [in,out] pointer to the block in the current frame receiving the result
> * @param ref_buf [in] pointer to the corresponding block in the reference frame
> * @param pitch [in] pitch for moving to the next y line
> * @param mc_type [in] interpolation type
> */
> static void ivi_mc_4x4_no_delta (int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type)
> {
> int i, r1, r2, r3, r4;
> int16_t *wptr;
theres lots of factorization possible here
[...]
> /**
> * decode block data:
> * extract huffman-coded transform coefficients from the bitstream, dequantize them,
> * apply inverse transform and motion compensation in order to reconstruct picture
> *
> * @param gb [in,out] the GetBit context
> * @param band [in] pointer to the band descriptor
> * @param tile [in] pointer to the tile descriptor
> * @return result code: 0 - OK, -1 = error (corrupted blocks data)
> */
> int ivi_decode_blocks (GetBitContext *gb, IVIBandDesc *band, IVITile *tile)
> {
> int mbn, blk, num_blocks, num_coeffs, blk_size, scan_pos, run, val, pos, is_intra, mc_type, mv_x, mv_y;
> int32_t prev_dc, trvec[64];
> uint32_t cbp, sym, lo, hi, quant, buf_offs;
> uint16_t *dequant_tab, q;
> IVIMbInfo *mb;
> RVMapDesc *rvmap = band->rv_map;
> void (*mc_with_delta_func)(int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type);
> void (*mc_no_delta_func)(int16_t *buf, int16_t *ref_buf, uint32_t pitch, int mc_type);
>
> prev_dc = 0; /* init intra prediction for the DC coefficient */
>
> blk_size = band->blk_size;
> num_blocks = (band->mb_size != blk_size) ? 4 : 1; /* number of blocks per mb */
> num_coeffs = 16 << ((blk_size >> 2) & 2); /* 64 - for 8x8 block, 16 - for 4x4 */
> if (blk_size == 8) {
> mc_with_delta_func = ivi_mc_8x8_delta;
> mc_no_delta_func = ivi_mc_8x8_no_delta;
> }
> else {
> mc_with_delta_func = ivi_mc_4x4_delta;
> mc_no_delta_func = ivi_mc_4x4_no_delta;
> }
>
> for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) {
> is_intra = mb->type == 0;
> cbp = mb->cbp;
> quant = av_clip(band->glob_quant + mb->q_delta, 0, 23);
> dequant_tab = (is_intra) ? band->dequant_intra : band->dequant_inter;
> dequant_tab += quant * num_coeffs;
> buf_offs = mb->buf_offs;
>
> if (!is_intra) {
> mv_x = mb->mv_x;
> mv_y = mb->mv_y;
> if (!band->mc_resolution)
> mc_type = 0; /* we have only fullpel vectors */
> else {
> mc_type = ((mv_y & 1) << 1) | (mv_x & 1);
> mv_x >>= 1;
> mv_y >>= 1; /* convert halfpel vectors into fullpel ones */
> }
> }
>
> for (blk = 0; blk < num_blocks; blk++) {
> /* adjust block position in the buffer according with its number */
> if (blk & 1)
> buf_offs += blk_size;
> else if (blk == 2) {
> buf_offs -= blk_size;
> buf_offs += blk_size * band->pitch;
> }
>
> if (cbp & 1) { /* block coded ? */
> scan_pos = -1;
> memset(trvec,0,num_coeffs*sizeof(int32_t)); /* zero transform vector */
>
> while(scan_pos <= num_coeffs) {
> sym = get_vlc2(gb, band->blk_vlc->table, IVI_VLC_BITS, 1);
> if (sym == rvmap->eob_sym)
> break; /* End of block */
>
> if (sym == rvmap->esc_sym) { /* Escape - run/val explicitly coded using 3 vlc codes */
> run = get_vlc2(gb, band->blk_vlc->table, IVI_VLC_BITS, 1) + 1;
> lo = get_vlc2(gb, band->blk_vlc->table, IVI_VLC_BITS, 1);
> hi = get_vlc2(gb, band->blk_vlc->table, IVI_VLC_BITS, 1);
> val = IVI_TOSIGNED((hi << 6) | lo); /* merge them and convert into signed val */
> }
> else {
> run = rvmap->runtab[sym];
> val = rvmap->valtab[sym];
> }
>
> /* de-zigzag and dequantize */
> scan_pos += run;
> pos = band->scan[scan_pos];
looks exploitable but cant say for sure as this patch is incomplete
>
> q = dequant_tab[pos]; /* get scalefactor */
> if (q != 1 && val != 0) {
> if (val > 0)
> val = (val * q) + (q >> 1) - (q & 1);
> else
> val = (val * q) - (q >> 1) + (q & 1);
> }
duplicate <0 check
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
The misfortune of the wise is better than the prosperity of the fool.
-- Epicurus
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/attachments/20090323/675be3e8/attachment.pgp>
More information about the ffmpeg-devel
mailing list