[FFmpeg-devel] [WIP][TOY] X-Face image encoder and decoder

Michael Niedermayer michaelni at gmx.at
Wed Oct 10 01:43:01 CEST 2012


Hi

On Tue, Oct 09, 2012 at 05:10:05PM +0200, Stefano Sabatini wrote:
> On date Thursday 2012-07-26 23:54:50 +0200, Stefano Sabatini encoded:
> > Hi,
> > 
> > this is a yet unready version of an X-Face encoder and decoder I did
> > for fun. I tried to contact the libcompface author to see if he's OK
> > with the licensing port.
> 
> James Ashton (in CC:) replied telling that he's OK with LGPL
> relicensing.
> 
> > I post it here for backup purposes, and to see if there is some
> > interest for it (but I warn again that it is not yet ready for
> > inclusion, so don't review yet).
> > 
> > Todo:
> > - add documentation
> > - add missing buffer checks
> > 
> 
> > I also wonder if we could adapt our big integer implementation
> > (libavutil/integer.h) for it, and if someone can recommend fancy
> > options for creating a 48x48x1 image with ffmpeg in the best possible
> > way (dithering options, etc.).
> 
> Updated against the integer patch I posted recently.
> -- 
> FFmpeg = Fabulous and Fundamental Multimedia Philosophical Elastic Gem

[...]
>  libavcodec/Makefile     |    2 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/codec_desc.c |    7 +
>  libavcodec/xface.c      |  591 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/xface.h      |   56 +++++
>  libavcodec/xfacedec.c   |  225 ++++++++++++++++++
>  libavcodec/xfaceenc.c   |  244 +++++++++++++++++++
>  libavformat/img2.c      |    1 +
>  9 files changed, 1128 insertions(+), 0 deletions(-)
>  create mode 100644 libavcodec/xface.c
>  create mode 100644 libavcodec/xface.h
>  create mode 100644 libavcodec/xfacedec.c
>  create mode 100644 libavcodec/xfaceenc.c

the code looks fine, i could point to some possible tricks to
make it faster but its kind of silly for 48x48 images on modern hw
so some of the comments below should not be taken serious :)


[...]
> +static const uint8_t g_00[1<<12] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> +    0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> +    1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1,

these tables could be stored more compactly by using bits instead of
bytes


[...]
> +void ff_xface_generate_face(uint8_t *dst, uint8_t * const src)
> +{
> +    int m, l, k, j, i, h;
> +
> +    for (j = 0; j < XFACE_HEIGHT; j++) {
> +        for (i = 0; i < XFACE_WIDTH; i++) {
> +            h = i + j * XFACE_WIDTH;
> +            k = 0;
> +
> +            /*
> +               Compute k, encoding the bits *before* the current one, contained in the
> +               image buffer. That is, given the grid:
> +
> +                l      i
> +                |      |
> +                v      v
> +               +--+--+--+--+--+
> +          m -> | 1| 2| 3| 4| 5|
> +               +--+--+--+--+--+
> +               | 6| 7| 8| 9|10|
> +               +--+--+--+--+--+
> +          j -> |11|12| *|  |  |
> +               +--+--+--+--+--+
> +
> +               the value k for the pixel marked as "*" will contain the bit encoding of
> +               the values in the matrix marked from "1" to "12". In case the pixel is
> +               near the border of the grid, the number of values contained within the
> +               grid will be lesser than 12.
> +             */
> +
> +            for (l = i - 2; l <= i + 2; l++) {
> +                for (m = j - 2; m <= j; m++) {
> +                    if (l >= i && m == j)
> +                        continue;
> +                    if (l > 0 && l <= XFACE_WIDTH && m > 0)

> +                        k = *(src + l + m * XFACE_WIDTH) ? k * 2 + 1 : k * 2;

k = 2*k + src[src + l + m * XFACE_WIDTH];

also instead of reading 12 values you can reuse the k from the
left pixel, shift it by 1 bit and update just 3 values, but given the
small size its not worth the work


[...]
> +
> +/* define the face size - 48x48x1 */
> +#define XFACE_WIDTH  48
> +#define XFACE_HEIGHT 48
> +#define XFACE_PIXELS (XFACE_WIDTH * XFACE_HEIGHT)
> +
> +/* compressed output uses the full range of printable characters.
> + * in ASCII these are in a contiguous block so we just need to know
> + * the first and last.  The total number of printables is needed too */
> +#define XFACE_FIRSTPRINT '!'
> +#define XFACE_LASTPRINT '~'
> +#define XFACE_NUMPRINTS (XFACE_LASTPRINT - XFACE_FIRSTPRINT + 1)
> +
> +/* Each face is encoded using 9 octrees of 16x16 each.  Each level of the
> + * trees has varying probabilities of being white, grey or black.
> + * The table below is based on sampling many faces */
> +enum { BLACK = 0, GREY, WHITE };

some of these comments could/should be made to /** doxgen comments

also i suspect that several pop_integer() calls could be merged using
a large LUT to decode several symbols at a time and then adjust b
for all of them at once. Again not worth for 48x48 images

Thanks to james and stefano for writing and porting this codec !

[...]

-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I am the wisest man alive, for I know one thing, and that is that I know
nothing. -- Socrates
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20121010/8ae5a2f6/attachment.asc>


More information about the ffmpeg-devel mailing list