view lzwenc.c @ 12530:63edd10ad4bc libavcodec tip

Try to fix crashes introduced by r25218 r25218 made assumptions about the existence of past reference frames that weren't necessarily true.
author darkshikari
date Tue, 28 Sep 2010 09:06:22 +0000
parents 7dd2a45249a9
children
line wrap: on
line source

/*
 * LZW encoder
 * Copyright (c) 2007 Bartlomiej Wolowiec
 *
 * 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
 */

/**
 * LZW encoder
 * @file
 * @author Bartlomiej Wolowiec
 */

#include "avcodec.h"
#include "put_bits.h"
#include "lzw.h"

#define LZW_MAXBITS 12
#define LZW_SIZTABLE (1<<LZW_MAXBITS)
#define LZW_HASH_SIZE 16411
#define LZW_HASH_SHIFT 6

#define LZW_PREFIX_EMPTY -1
#define LZW_PREFIX_FREE -2

/** One code in hash table */
typedef struct Code{
    /// Hash code of prefix, LZW_PREFIX_EMPTY if empty prefix, or LZW_PREFIX_FREE if no code
    int hash_prefix;
    int code;               ///< LZW code
    uint8_t suffix;         ///< Last character in code block
}Code;

/** LZW encode state */
typedef struct LZWEncodeState {
    int clear_code;          ///< Value of clear code
    int end_code;            ///< Value of end code
    Code tab[LZW_HASH_SIZE]; ///< Hash table
    int tabsize;             ///< Number of values in hash table
    int bits;                ///< Actual bits code
    int bufsize;             ///< Size of output buffer
    PutBitContext pb;        ///< Put bit context for output
    int maxbits;             ///< Max bits code
    int maxcode;             ///< Max value of code
    int output_bytes;        ///< Number of written bytes
    int last_code;           ///< Value of last output code or LZW_PREFIX_EMPTY
    enum FF_LZW_MODES mode;  ///< TIFF or GIF
    void (*put_bits)(PutBitContext *, int, unsigned); ///< GIF is LE while TIFF is BE
}LZWEncodeState;


const int ff_lzw_encode_state_size = sizeof(LZWEncodeState);

/**
 * Hash function adding character
 * @param head LZW code for prefix
 * @param add Character to add
 * @return New hash value
 */
static inline int hash(int head, const int add)
{
    head ^= (add << LZW_HASH_SHIFT);
    if (head >= LZW_HASH_SIZE)
        head -= LZW_HASH_SIZE;
    assert(head >= 0 && head < LZW_HASH_SIZE);
    return head;
}

/**
 * Hash function calculates next hash value
 * @param head Actual hash code
 * @param offset Offset calculated by hashOffset
 * @return New hash value
 */
static inline int hashNext(int head, const int offset)
{
    head -= offset;
    if(head < 0)
        head += LZW_HASH_SIZE;
    return head;
}

/**
 * Hash function calculates hash offset
 * @param head Actual hash code
 * @return Hash offset
 */
static inline int hashOffset(const int head)
{
    return head ? LZW_HASH_SIZE - head : 1;
}

/**
 * Write one code to stream
 * @param s LZW state
 * @param c code to write
 */
static inline void writeCode(LZWEncodeState * s, int c)
{
    assert(0 <= c && c < 1 << s->bits);
    s->put_bits(&s->pb, s->bits, c);
}


/**
 * Find LZW code for block
 * @param s LZW state
 * @param c Last character in block
 * @param hash_prefix LZW code for prefix
 * @return LZW code for block or -1 if not found in table
 */
static inline int findCode(LZWEncodeState * s, uint8_t c, int hash_prefix)
{
    int h = hash(FFMAX(hash_prefix, 0), c);
    int hash_offset = hashOffset(h);

    while (s->tab[h].hash_prefix != LZW_PREFIX_FREE) {
        if ((s->tab[h].suffix == c)
            && (s->tab[h].hash_prefix == hash_prefix))
            return h;
        h = hashNext(h, hash_offset);
    }

    return h;
}

/**
 * Add block to LZW code table
 * @param s LZW state
 * @param c Last character in block
 * @param hash_prefix LZW code for prefix
 * @param hash_code LZW code for bytes block
 */
static inline void addCode(LZWEncodeState * s, uint8_t c, int hash_prefix, int hash_code)
{
    s->tab[hash_code].code = s->tabsize;
    s->tab[hash_code].suffix = c;
    s->tab[hash_code].hash_prefix = hash_prefix;

    s->tabsize++;

    if (s->tabsize >= (1 << s->bits) + (s->mode == FF_LZW_GIF))
        s->bits++;
}

/**
 * Clear LZW code table
 * @param s LZW state
 */
static void clearTable(LZWEncodeState * s)
{
    int i, h;

    writeCode(s, s->clear_code);
    s->bits = 9;
    for (i = 0; i < LZW_HASH_SIZE; i++) {
        s->tab[i].hash_prefix = LZW_PREFIX_FREE;
    }
    for (i = 0; i < 256; i++) {
        h = hash(0, i);
        s->tab[h].code = i;
        s->tab[h].suffix = i;
        s->tab[h].hash_prefix = LZW_PREFIX_EMPTY;
    }
    s->tabsize = 258;
}

/**
 * Calculate number of bytes written
 * @param s LZW encode state
 * @return Number of bytes written
 */
static int writtenBytes(LZWEncodeState *s){
    int ret = put_bits_count(&s->pb) >> 3;
    ret -= s->output_bytes;
    s->output_bytes += ret;
    return ret;
}

/**
 * Initialize LZW encoder. Please set s->clear_code, s->end_code and s->maxbits before run.
 * @param s LZW state
 * @param outbuf Output buffer
 * @param outsize Size of output buffer
 * @param maxbits Maximum length of code
 */
void ff_lzw_encode_init(LZWEncodeState *s, uint8_t *outbuf, int outsize,
                        int maxbits, enum FF_LZW_MODES mode,
                        void (*lzw_put_bits)(PutBitContext *, int, unsigned))
{
    s->clear_code = 256;
    s->end_code = 257;
    s->maxbits = maxbits;
    init_put_bits(&s->pb, outbuf, outsize);
    s->bufsize = outsize;
    assert(s->maxbits >= 9 && s->maxbits <= LZW_MAXBITS);
    s->maxcode = 1 << s->maxbits;
    s->output_bytes = 0;
    s->last_code = LZW_PREFIX_EMPTY;
    s->bits = 9;
    s->mode = mode;
    s->put_bits = lzw_put_bits;
}

/**
 * LZW main compress function
 * @param s LZW state
 * @param inbuf Input buffer
 * @param insize Size of input buffer
 * @return Number of bytes written or -1 on error
 */
int ff_lzw_encode(LZWEncodeState * s, const uint8_t * inbuf, int insize)
{
    int i;

    if(insize * 3 > (s->bufsize - s->output_bytes) * 2){
        return -1;
    }

    if (s->last_code == LZW_PREFIX_EMPTY)
        clearTable(s);

    for (i = 0; i < insize; i++) {
        uint8_t c = *inbuf++;
        int code = findCode(s, c, s->last_code);
        if (s->tab[code].hash_prefix == LZW_PREFIX_FREE) {
            writeCode(s, s->last_code);
            addCode(s, c, s->last_code, code);
            code= hash(0, c);
        }
        s->last_code = s->tab[code].code;
        if (s->tabsize >= s->maxcode - 1) {
            clearTable(s);
        }
    }

    return writtenBytes(s);
}

/**
 * Write end code and flush bitstream
 * @param s LZW state
 * @return Number of bytes written or -1 on error
 */
int ff_lzw_encode_flush(LZWEncodeState *s,
                        void (*lzw_flush_put_bits)(PutBitContext *))
{
    if (s->last_code != -1)
        writeCode(s, s->last_code);
    writeCode(s, s->end_code);
    lzw_flush_put_bits(&s->pb);
    s->last_code = -1;

    return writtenBytes(s);
}