[FFmpeg-devel] A64 encoder

Michael Niedermayer michaelni
Sat Jun 19 01:10:46 CEST 2010


On Tue, Jun 15, 2010 at 04:32:39PM +0200, Tobias Bindhammer wrote:
>>> + at item A64 multicolor         @tab  X  @tab
>>> +    @tab Creates video suitable to be played on a commodore 64 
>>> (multicolor mode).
>>>  @item 4X Movie               @tab     @tab  X
>>>      @tab Used in certain computer games.
>>>  @item 8088flex TMV           @tab     @tab  X
>> Didn't you add three different things?
>
> Yes, there are a few other formats available, but the consenus was, that
> we wanted to start with that one first to be added.
> Attached you'll find an updated diff with the suggested changes.
>
> regards,
>
> Toby
>
> -- 
> Dipl. Ing. Tobias Bindhammer
> Institut f?r Verteilte Systeme
> Oberer Eselsberg          Phone: + 49 731/502-4235
> Universit?t Ulm           Fax  : + 49 731/502-4142
> D-89069 Ulm               mailto:tobias.bindhammer at uni-ulm.de
> http://www-vs.informatik.uni-ulm.de/~bindhammer/
>

>  doc/general.texi         |    2 
>  libavcodec/Makefile      |    2 
>  libavcodec/a64enc.h      |   50 +++++++++
>  libavcodec/a64multienc.c |  244 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/a64tables.h   |   92 +++++++++++++++++
>  libavcodec/allcodecs.c   |    2 
>  libavcodec/avcodec.h     |    2 
>  libavformat/Makefile     |    1 
>  libavformat/a64.c        |   73 ++++++++++++++
>  libavformat/allformats.c |    1 

please split muxer and codec into seperate patches so patches are smaller


[...]
> Index: libavcodec/avcodec.h
> ===================================================================
> --- libavcodec/avcodec.h	(Revision 23561)
> +++ libavcodec/avcodec.h	(Arbeitskopie)
> @@ -192,6 +192,8 @@
>      CODEC_ID_MOTIONPIXELS,
>      CODEC_ID_TGV,
>      CODEC_ID_TGQ,
> +    CODEC_ID_A64_MULTI,
> +    CODEC_ID_A64_MULTI5,
>      CODEC_ID_TQI,
>      CODEC_ID_AURA,
>      CODEC_ID_AURA2,

breaks ABI


[..]
> +#include "a64enc.h"
> +#include "a64tables.h"
> +#include "elbg.h"
> +
> +#define DITHERSTEPS 8
> +

> +/* own methods */

i think this is not the correct terminology for C


> +static void to_meta_with_crop(AVCodecContext *avctx, AVFrame *p, int *dest)
> +{
> +    int blockx, blocky, x, y;
> +    int luma = 0;
> +    int height = FFMIN(avctx->height,C64YRES);
> +    int width  = FFMIN(avctx->width ,C64XRES);
> +    uint8_t *src = p->data[0];
> +
> +    for (blocky = 0; blocky<height; blocky += 8) {
> +        for (blockx = 0; blockx<C64XRES; blockx += 8) {
> +            for (y = blocky; y < blocky+8 && y<height; y++) {
> +                for (x = blockx; x < blockx+8 && x<C64XRES; x += 2) {
> +                    if(x<width) {
> +                        /* build average over 2 pixels */

> +                        luma = (src[(x + 0 + y * p->linesize[0])] +
> +                                src[(x + 1 + y * p->linesize[0])]) / 2;

>>1


> +                        /* write blocks as linear data now so they are suitable for elbg */
> +                        dest[0] = luma;
> +                    }
> +                    dest++;
> +                }
> +            }
> +        }
> +    }
> +}
> +
> +static void render_charset(AVCodecContext *avctx, uint8_t *charset, uint8_t *colrammap)
> +{
> +    A64Context *c = avctx->priv_data;
> +    uint8_t row1;
> +    int charpos, x, y;
> +    int pix;
> +    int dither;
> +    int index1, index2;
> +    int lowdiff, highdiff;
> +    int maxindex = c->mc_use_5col + 3;
> +    int maxsteps = DITHERSTEPS * maxindex + 1;
> +    int *best_cb = c->mc_best_cb;
> +
> +    /* now reduce colors first */
> +    for (x = 0; x < 256 * 32; x++) best_cb[x] = best_cb[x] * maxsteps / 255;
> +
> +    /* and render charset */
> +    for (charpos = 0; charpos < 256; charpos++) {
> +        lowdiff  = 0;
> +        highdiff = 0;
> +        for (y = 0; y < 8; y++) {
> +            row1 = 0;
> +            for (x = 0; x < 4; x++) {
> +                pix = best_cb[y * 4 + x];
> +                dither = pix % DITHERSTEPS;
> +                index1 = pix / DITHERSTEPS;
> +                index2 = FFMIN(index1 + 1, maxindex);
> +
> +                if (pix > 3 * DITHERSTEPS)
> +                    highdiff += pix - 3 * DITHERSTEPS;
> +                if (pix < DITHERSTEPS)
> +                    lowdiff += DITHERSTEPS - pix;
> +
> +                row1 <<= 2;
> +                if (prep_dither_patterns[dither][y & 3][x & 3])
> +                    row1 |= 3-(index2 & 3);
> +                else
> +                    row1 |= 3-(index1 & 3);
> +            }
> +            charset[y] = row1;
> +        }
> +
> +        /* are we in 5col mode and need to adjust pixels? */
> +        if (c->mc_use_5col && highdiff > 0 && lowdiff > 0) {
> +            if (lowdiff > highdiff) {
> +                for (x = 0; x < 32; x++)
> +                    best_cb[x] = FFMIN(3 * DITHERSTEPS, best_cb[x]);
> +            } else {
> +                for (x = 0; x < 32; x++)
> +                    best_cb[x] = FFMAX(DITHERSTEPS, best_cb[x]);
> +            }
> +            charpos--;          /* redo char */
> +        } else {
> +            /* advance pointers */
> +            best_cb += 32;
> +            charset += 8;
> +
> +            if (highdiff > 0)
> +                colrammap[charpos] = 0x9;
> +            else
> +                colrammap[charpos] = 0x8;
> +        }
> +    }

this heuristic is simply poor
if you had no success in implemening some error diffusion dither that considers
neighboring blocks and previous frames than i would suggest you at least try
some kind of a refinement pass after above


[...]

> +}
> +
> +/* encoder methods */
> +static av_cold int a64multi_close_encoder(AVCodecContext *avctx)
> +{
> +    A64Context *c = avctx->priv_data;
> +    av_free(c->mc_meta_charset);
> +    av_free(c->mc_best_cb);
> +    av_free(c->mc_charmap);
> +    return 0;
> +}
> +
> +static av_cold int a64multi_init_encoder(AVCodecContext *avctx)
> +{
> +    A64Context *c = avctx->priv_data;
> +    av_lfg_init(&c->randctx, 1);
> +

> +    if (avctx->global_quality < 1)
> +        c->mc_lifetime = 4;
> +    else

{} also try patcheck please


[...]
> +typedef struct A64Context {
> +    /* general variables */
> +    AVFrame picture;
> +
> +    /* variables for multicolor modes */
> +    AVLFG randctx;
> +    int mc_lifetime;
> +    int mc_use_5col;
> +    int mc_frame_counter;
> +    int *mc_meta_charset;
> +    int *mc_charmap;
> +    int *mc_best_cb;
> +} A64Context;

the encoders private struct belongs in the .c file unless the encoder is
split accross several files


[...]
> +
> +static int a64_write_header(struct AVFormatContext *s)
> +{
> +    AVCodecContext *avctx=s->streams[0]->codec;

> +    A64Context *c = avctx->priv_data;

the encoders private context is off limits for the muxer
it breaks stream copy but thats not the only reason


> +    uint8_t header[5] = {
> +        0x00, //load
> +        0x40, //address
> +        0x00, //mode
> +        0x00, //charset_lifetime (multi only)
> +        0x00  //fps in 50/fps;
> +    };
> +    switch (avctx->codec->id) {
> +    case CODEC_ID_A64_MULTI:
> +        header[2]=0x00;
> +        header[3]=c->mc_lifetime;
> +        header[4]=2;
> +        break;
> +    case CODEC_ID_A64_MULTI5:
> +        header[2]=0x01;
> +        header[3]=c->mc_lifetime;
> +        header[4]=3;
> +        break;
> +    default:
> +        return -1;
> +        break;
> +    }
> +    put_buffer(s->pb, header, 2);

a bunch of put_byte() seems simpler


[...]
-- 
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/20100619/b0796168/attachment.pgp>



More information about the ffmpeg-devel mailing list