On Fri, Jul 27, 2012 at 07:21:44PM -0400, Derek Buitenhuis wrote:
> At the moment it only does BGR24, but I plan to add the rest after.
> 
> Signed-off-by: Derek Buitenhuis <[email protected]>
> ---
>  Changelog              |    1 +
>  doc/general.texi       |    1 +
>  libavcodec/Makefile    |    1 +
>  libavcodec/allcodecs.c |    1 +
>  libavcodec/avcodec.h   |    1 +
>  libavcodec/cllc.c      |  276 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/version.h   |    2 +-
>  libavformat/riff.c     |    1 +
>  8 files changed, 283 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/cllc.c
> 
> diff --git a/Changelog b/Changelog
> index ea2c353..64c23d3 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -41,6 +41,7 @@ version <next>:
>  - G.723.1 demuxer and decoder
>  - RTMPE protocol support
>  - RTMPTE protocol support
> +- Canopus Lossless Codec decoder
>  
>  
>  version 0.8:
> diff --git a/doc/general.texi b/doc/general.texi
> index 0585554..a14e888 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -468,6 +468,7 @@ following image formats are supported:
>  @item Delphine Software International CIN video  @tab     @tab  X
>      @tab Codec used in Delphine Software International games.
>  @item Discworld II BMV Video @tab     @tab  X
> +@item Canopus Lossless Codec @tab     @tab  X
>  @item Cinepak                @tab     @tab  X
>  @item Cirrus Logic AccuPak   @tab  X  @tab  X
>      @tab fourcc: CLJR
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 3a74338..d10072f 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -116,6 +116,7 @@ OBJS-$(CONFIG_CDXL_DECODER)            += cdxl.o
>  OBJS-$(CONFIG_CINEPAK_DECODER)         += cinepak.o
>  OBJS-$(CONFIG_CLJR_DECODER)            += cljr.o
>  OBJS-$(CONFIG_CLJR_ENCODER)            += cljr.o
> +OBJS-$(CONFIG_CLLC_DECODER)            += cllc.o
>  OBJS-$(CONFIG_COOK_DECODER)            += cook.o
>  OBJS-$(CONFIG_CSCD_DECODER)            += cscd.o
>  OBJS-$(CONFIG_CYUV_DECODER)            += cyuv.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 7e7cee6..f85892b 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -89,6 +89,7 @@ void avcodec_register_all(void)
>      REGISTER_DECODER (CDXL, cdxl);
>      REGISTER_DECODER (CINEPAK, cinepak);
>      REGISTER_ENCDEC  (CLJR, cljr);
> +    REGISTER_DECODER (CLLC, cllc);
>      REGISTER_DECODER (CSCD, cscd);
>      REGISTER_DECODER (CYUV, cyuv);
>      REGISTER_DECODER (DFA, dfa);
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 71f2e70..450a9ca 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -259,6 +259,7 @@ enum CodecID {
>      CODEC_ID_MSA1,
>      CODEC_ID_TSCC2,
>      CODEC_ID_MTS2,
> +    CODEC_ID_CLLC,
>  
>      /* various PCM "codecs" */
>      CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the 
> start of audio codecs
> diff --git a/libavcodec/cllc.c b/libavcodec/cllc.c
> new file mode 100644
> index 0000000..03e6937
> --- /dev/null
> +++ b/libavcodec/cllc.c
> @@ -0,0 +1,276 @@
> +/*
> + * Canopus Lossless Codec decoder
> + *
> + * Copyright (c) 2012 Derek Buitenhuis
> + *
> + * This file is part of Libav.
> + *
> + * Libav 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.
> + *
> + * Libav 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 Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +#include "libavutil/intreadwrite.h"
> +#include "dsputil.h"
> +#include "get_bits.h"
> +#include "avcodec.h"
> +
> +typedef struct CLLCContext {
> +    DSPContext dsp;
> +    AVCodecContext *avctx;
> +
> +    uint8_t *swapped_buf;
> +    int8_t  *code_table[3];
> +} CLLCContext;
> +
> +static int read_code_table(GetBitContext *gb, int8_t *code_table)
> +{
> +    int num_lens, num_lens_orig;
> +    int num_codes;
> +    int prefix, symbol;
> +    int sym_shift;
> +    int i, j, k;
> +
> +    sym_shift = 13;
> +    prefix    = 0;
> +
> +    num_lens = num_lens_orig = get_bits(gb, 5);
> +
> +    for (i = 0; i < num_lens; i++) {
> +        num_codes = get_bits(gb, 9);
> +
> +        for (j = num_codes; j > 0; j--) {
> +            symbol = get_bits(gb, 8);
> +
> +            for (k = prefix << sym_shift; k < prefix + 1 << sym_shift; k++) {
> +                code_table[2 * k]     = symbol;
> +                code_table[2 * k + 1] = i + 1;
> +            }

In theory you could collect (symbol, i+1, prefix) values and use them to
initialise our VLC structure instead of making LUT yourself (exactly like
binary does ;)

> +
> +            prefix++;
> +        }
> +
> +        if (num_codes)
> +            num_lens = num_lens_orig;

not needed (num_codes is not modified) - RE leftover?

> +
> +        sym_shift--;
> +        prefix <<= 1;
> +    }
> +
> +    return num_lens;
> +}
> +
> +static int read_line(CLLCContext *ctx, GetBitContext *gb, int *top_left,
> +                     int8_t *code_table, uint8_t *outbuf)
> +{
> +    uint8_t *dst;
> +    int pred, skip;
> +    int i;
> +
> +    dst = outbuf;
> +
> +    /* Stash the first pixel */
> +    pred = *top_left = *top_left + code_table[2 * show_bits(gb, 14)];

ahem, someone forgot to _skip_ bits here

> +
> +    /* Simultaniously read and restore the line */
> +    for (i = 0; i < ctx->avctx->width; i++) {
> +        pred += code_table[2 * show_bits(gb, 14)];
> +        skip  = code_table[2 * show_bits(gb, 14) + 1];
> +
> +        skip_bits(gb, skip);
> +
> +        dst[0] = pred;
> +        dst   += 3;
> +    }
> +
> +    return 0;
> +}
> +
> +static int decode_bgr24_frame(CLLCContext *ctx, GetBitContext *gb, AVFrame 
> *pic)
> +{
> +    AVCodecContext *avctx = ctx->avctx;
> +    uint8_t *dst;
> +    int pred[3];
> +    int ret;
> +    int i, j;
> +
> +    pred[0] =   128;
> +    pred[1] =   128;
> +    pred[2] =  -128;

perchance, they are all 0x80 ?

> +
> +    dst = pic->data[0] + 5;
> +
> +    skip_bits(gb, 16);
> +
> +    /* Read in code table for each plane */
> +    for (i = 0; i < 3; i++) {
> +        ret = read_code_table(gb, ctx->code_table[i]);
> +        if (ret <= 0) {
> +            av_log(ctx->avctx, AV_LOG_ERROR,
> +                   "Could not read code table %d.\n", i);
> +            return ret;
> +        }
> +    }
> +
> +    /* Read in and restore every lie */
> +    for (i = avctx->height; i > 0; i--) {
> +        for (j = 0; j < 3; j++)
> +            read_line(ctx, gb, &pred[j], ctx->code_table[j], dst - j);
> +
> +        dst += pic->linesize[0];
> +    }
> +
> +    return 0;
> +}
> +
> +static int cllc_decode_frame(AVCodecContext *avctx, void *data,
> +                             int *data_size, AVPacket *avpkt)
> +{
> +    CLLCContext *ctx = avctx->priv_data;
> +    AVFrame *pic = avctx->coded_frame;
> +    uint8_t *src = avpkt->data;
> +    uint32_t info_tag, info_offset, coding_type;
> +    GetBitContext gb;
> +    int ret;
> +
> +    if (pic->data[0])
> +        avctx->release_buffer(avctx, pic);
> +
> +    pic->reference = 0;
> +
> +    /* Skip the INFO header if present */
> +    info_offset = 0;
> +    info_tag    = AV_RL32(src);
> +    if (info_tag == MKTAG('I', 'N', 'F', 'O')) {
> +        info_offset = AV_RL32(src + 4) + 8;
> +        src        += info_offset;

check that you skip reasonable number of bytes

> +
> +        av_log(avctx, AV_LOG_DEBUG, "Skipping INFO chunk.\n");
> +    }
> +
> +    /* bswap16 the buffer since CLLC's bitreader works in 16-bit WORDS */
> +    ctx->dsp.bswap16_buf((uint16_t *) ctx->swapped_buf, (uint16_t *) src,
> +                         (avpkt->size - info_offset) / 2);
> +
> +    init_get_bits(&gb, ctx->swapped_buf, (avpkt->size - info_offset) * 8);
> +
> +    /*
> +     * Read in coding type. The types are as follows:
> +     *
> +     * 0 - YUY2
> +     * 1 - BGR24 (Triples)
> +     * 2 - BGR24 (Quads)
> +     * 3 - BGRA
> +     */
> +    coding_type = (AV_RL32(src) >> 8) & 0xFF;
> +    av_log(avctx, AV_LOG_DEBUG, "Frame coding type: %d\n", coding_type);
> +
> +    switch(coding_type) {
> +    case 1:
> +        avctx->pix_fmt             = PIX_FMT_BGR24;
> +        avctx->bits_per_raw_sample = 8;
> +
> +        if (avctx->get_buffer(avctx, pic) < 0) {
> +            av_log(avctx, AV_LOG_ERROR, "Could not allocate buffer.\n");
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        ret = decode_bgr24_frame(ctx, &gb, pic);
> +        if (ret < 0)
> +            return ret;
> +
> +        break;
> +    default:
> +        av_log(avctx, AV_LOG_ERROR, "Unknown coding type: %d\n.", 
> coding_type);
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    pic->key_frame = 1;
> +    pic->pict_type = AV_PICTURE_TYPE_I;
> +
> +    *data_size       = sizeof(AVFrame);
> +    *(AVFrame *)data = *pic;
> +
> +    return avpkt->size;
> +}
> +
> +static av_cold int cllc_decode_close(AVCodecContext *avctx)
> +{
> +    CLLCContext *ctx = avctx->priv_data;
> +    int i;
> +
> +    if (avctx->coded_frame->data[0])
> +        avctx->release_buffer(avctx, avctx->coded_frame);
> +
> +    if (avctx->coded_frame)
> +        av_freep(&avctx->coded_frame);
> +
> +    if (ctx->swapped_buf)
> +        av_freep(&ctx->swapped_buf);
> +
> +    for (i = 0; i < 3; i++)
> +        if (ctx->code_table[i])
> +            av_freep(&ctx->code_table[i]);
> +
> +    return 0;
> +}
> +
> +static av_cold int cllc_decode_init(AVCodecContext *avctx)
> +{
> +    CLLCContext *ctx = avctx->priv_data;
> +    int i;
> +
> +    /* Stash for later use */
> +    ctx->avctx = avctx;
> +
> +    ff_dsputil_init(&ctx->dsp, avctx);
> +
> +    avctx->coded_frame = avcodec_alloc_frame();
> +    if (!avctx->coded_frame) {
> +        av_log(avctx, AV_LOG_ERROR, "Could not allocate frame.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    ctx->swapped_buf = av_malloc(avctx->width * avctx->height * 3);

Are you sure it's always enough? Max code length is 14 bits and some space is
needed for code descriptions. It's better to be pessimistic here than crash on
too big input frame later.

> +    if (!ctx->swapped_buf) {
> +        cllc_decode_close(avctx);
> +        av_log(avctx, AV_LOG_ERROR,
> +               "Could not allocate swapped buffer frame.\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    /* Allocate space for our code tables */
> +    for (i = 0; i < 3; i++) {
> +        ctx->code_table[i] = av_malloc(32768);

You can just move them to context instead of allocating dynamically.

> +        if (!ctx->code_table[i]) {
> +            cllc_decode_close(avctx);
> +            av_log(avctx, AV_LOG_ERROR,
> +                   "Could not allocate code table buffer %d.\n", i);
> +            return AVERROR(ENOMEM);
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +AVCodec ff_cllc_decoder = {
> +    .name           = "cllc",
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = CODEC_ID_CLLC,
> +    .priv_data_size = sizeof(CLLCContext),
> +    .init           = cllc_decode_init,
> +    .decode         = cllc_decode_frame,
> +    .close          = cllc_decode_close,
> +    .capabilities   = CODEC_CAP_DR1,
> +    .long_name      = NULL_IF_CONFIG_SMALL("Canopus Lossless Codec"),
> +};
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index acad4d4..a74b0ad 100644
> --- a/libavcodec/version.h
> +++ b/libavcodec/version.h
> @@ -27,7 +27,7 @@
>   */
>  
>  #define LIBAVCODEC_VERSION_MAJOR 54
> -#define LIBAVCODEC_VERSION_MINOR 23
> +#define LIBAVCODEC_VERSION_MINOR 24
>  #define LIBAVCODEC_VERSION_MICRO  1
>  
>  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> diff --git a/libavformat/riff.c b/libavformat/riff.c
> index 7b036dd..5e70ab8 100644
> --- a/libavformat/riff.c
> +++ b/libavformat/riff.c
> @@ -288,6 +288,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
>      { CODEC_ID_MSA1,         MKTAG('M', 'S', 'A', '1') },
>      { CODEC_ID_TSCC2,        MKTAG('T', 'S', 'C', '2') },
>      { CODEC_ID_MTS2,         MKTAG('M', 'T', 'S', '2') },
> +    { CODEC_ID_CLLC,         MKTAG('C', 'L', 'L', 'C') },
>      { CODEC_ID_NONE,         0 }
>  };
>  
> -- 
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to