⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smacker.c

📁 ffmpeg源码分析
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Smacker decoder * Copyright (c) 2006 Konstantin Shishkov * * This library 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 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *//** * @file smacker.c * Smacker decoder *//* * Based on http://wiki.multimedia.cx/index.php?title=Smacker */#include <stdio.h>#include <stdlib.h>#include "common.h"#include "avcodec.h"#define ALT_BITSTREAM_READER_LE#include "bitstream.h"#define SMKTREE_BITS 9#define SMK_NODE 0x80000000/* * Decoder context */typedef struct SmackVContext {    AVCodecContext *avctx;    AVFrame pic;    int *mmap_tbl, *mclr_tbl, *full_tbl, *type_tbl;    int mmap_last[3], mclr_last[3], full_last[3], type_last[3];} SmackVContext;/** * Context used for code reconstructing */typedef struct HuffContext {    int length;    int maxlength;    int current;    uint32_t *bits;    int *lengths;    int *values;} HuffContext;/* common parameters used for decode_bigtree */typedef struct DBCtx {    VLC *v1, *v2;    int *recode1, *recode2;    int escapes[3];    int *last;    int lcur;} DBCtx;/* possible runs of blocks */static const int block_runs[64] = {      1,    2,    3,    4,    5,    6,    7,    8,      9,   10,   11,   12,   13,   14,   15,   16,     17,   18,   19,   20,   21,   22,   23,   24,     25,   26,   27,   28,   29,   30,   31,   32,     33,   34,   35,   36,   37,   38,   39,   40,     41,   42,   43,   44,   45,   46,   47,   48,     49,   50,   51,   52,   53,   54,   55,   56,     57,   58,   59,  128,  256,  512, 1024, 2048 };enum SmkBlockTypes {    SMK_BLK_MONO = 0,    SMK_BLK_FULL = 1,    SMK_BLK_SKIP = 2,    SMK_BLK_FILL = 3 };/** * Decode local frame tree */static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length){    if(!get_bits1(gb)){ //Leaf        if(hc->current >= 256){            av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");            return -1;        }        if(length){            hc->bits[hc->current] = prefix;            hc->lengths[hc->current] = length;        } else {            hc->bits[hc->current] = 0;            hc->lengths[hc->current] = 0;        }        hc->values[hc->current] = get_bits(gb, 8);        hc->current++;        if(hc->maxlength < length)            hc->maxlength = length;        return 0;    } else { //Node        int r;        length++;        r = smacker_decode_tree(gb, hc, prefix, length);        if(r)            return r;        return smacker_decode_tree(gb, hc, prefix | (1 << (length - 1)), length);    }}/** * Decode header tree */static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx){    if(!get_bits1(gb)){ //Leaf        int val, i1, i2, b1, b2;        if(hc->current >= hc->length){            av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n");            return -1;        }        b1 = get_bits_count(gb);        i1 = get_vlc2(gb, ctx->v1->table, SMKTREE_BITS, 3);        b1 = get_bits_count(gb) - b1;        b2 = get_bits_count(gb);        i2 = get_vlc2(gb, ctx->v2->table, SMKTREE_BITS, 3);        b2 = get_bits_count(gb) - b2;        val = ctx->recode1[i1] | (ctx->recode2[i2] << 8);        if(val == ctx->escapes[0]) {            ctx->last[0] = hc->current;            val = 0;        } else if(val == ctx->escapes[1]) {            ctx->last[1] = hc->current;            val = 0;        } else if(val == ctx->escapes[2]) {            ctx->last[2] = hc->current;            val = 0;        }        hc->values[hc->current++] = val;        return 1;    } else { //Node        int r = 0, t;        t = hc->current++;        r = smacker_decode_bigtree(gb, hc, ctx);        if(r < 0)            return r;        hc->values[t] = SMK_NODE | r;        r++;        r += smacker_decode_bigtree(gb, hc, ctx);        return r;    }}/** * Store large tree as FFmpeg's vlc codes */static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int **recodes, int *last, int size){    int res;    HuffContext huff;    HuffContext tmp1, tmp2;    VLC vlc[2];    int escapes[3];    DBCtx ctx;    tmp1.length = 256;    tmp1.maxlength = 0;    tmp1.current = 0;    tmp1.bits = av_mallocz(256 * 4);    tmp1.lengths = av_mallocz(256 * sizeof(int));    tmp1.values = av_mallocz(256 * sizeof(int));    tmp2.length = 256;    tmp2.maxlength = 0;    tmp2.current = 0;    tmp2.bits = av_mallocz(256 * 4);    tmp2.lengths = av_mallocz(256 * sizeof(int));    tmp2.values = av_mallocz(256 * sizeof(int));    memset(&vlc[0], 0, sizeof(VLC));    memset(&vlc[1], 0, sizeof(VLC));    if(get_bits1(gb)) {        smacker_decode_tree(gb, &tmp1, 0, 0);        get_bits1(gb);        res = init_vlc(&vlc[0], SMKTREE_BITS, tmp1.length,                    tmp1.lengths, sizeof(int), sizeof(int),                    tmp1.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);        if(res < 0) {            av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");            return -1;        }    } else {        av_log(smk->avctx, AV_LOG_ERROR, "Skipping low bytes tree\n");    }    if(get_bits1(gb)){        smacker_decode_tree(gb, &tmp2, 0, 0);        get_bits1(gb);        res = init_vlc(&vlc[1], SMKTREE_BITS, tmp2.length,                    tmp2.lengths, sizeof(int), sizeof(int),                    tmp2.bits, sizeof(uint32_t), sizeof(uint32_t), INIT_VLC_LE);        if(res < 0) {            av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");            return -1;        }    } else {        av_log(smk->avctx, AV_LOG_ERROR, "Skipping high bytes tree\n");    }    escapes[0]  = get_bits(gb, 8);    escapes[0] |= get_bits(gb, 8) << 8;    escapes[1]  = get_bits(gb, 8);    escapes[1] |= get_bits(gb, 8) << 8;    escapes[2]  = get_bits(gb, 8);    escapes[2] |= get_bits(gb, 8) << 8;    last[0] = last[1] = last[2] = -1;    ctx.escapes[0] = escapes[0];    ctx.escapes[1] = escapes[1];    ctx.escapes[2] = escapes[2];    ctx.v1 = &vlc[0];    ctx.v2 = &vlc[1];    ctx.recode1 = tmp1.values;    ctx.recode2 = tmp2.values;    ctx.last = last;    huff.length = ((size + 3) >> 2) + 3;    huff.maxlength = 0;    huff.current = 0;    huff.values = av_mallocz(huff.length * sizeof(int));    smacker_decode_bigtree(gb, &huff, &ctx);    get_bits1(gb);    if(ctx.last[0] == -1) ctx.last[0] = huff.current++;    if(ctx.last[1] == -1) ctx.last[1] = huff.current++;    if(ctx.last[2] == -1) ctx.last[2] = huff.current++;    *recodes = huff.values;    if(vlc[0].table)        free_vlc(&vlc[0]);    if(vlc[1].table)        free_vlc(&vlc[1]);    av_free(tmp1.bits);    av_free(tmp1.lengths);    av_free(tmp1.values);    av_free(tmp2.bits);    av_free(tmp2.lengths);    av_free(tmp2.values);    return 0;}static int decode_header_trees(SmackVContext *smk) {    GetBitContext gb;    int mmap_size, mclr_size, full_size, type_size;    mmap_size = LE_32(smk->avctx->extradata);    mclr_size = LE_32(smk->avctx->extradata + 4);    full_size = LE_32(smk->avctx->extradata + 8);    type_size = LE_32(smk->avctx->extradata + 12);    init_get_bits(&gb, smk->avctx->extradata + 16, (smk->avctx->extradata_size - 16) * 8);    if(!get_bits1(&gb)) {        av_log(smk->avctx, AV_LOG_INFO, "Skipping MMAP tree\n");        smk->mmap_tbl = av_malloc(sizeof(int) * 2);        smk->mmap_tbl[0] = 0;        smk->mmap_last[0] = smk->mmap_last[1] = smk->mmap_last[2] = 1;    } else {        smacker_decode_header_tree(smk, &gb, &smk->mmap_tbl, smk->mmap_last, mmap_size);    }    if(!get_bits(&gb, 1)) {        av_log(smk->avctx, AV_LOG_INFO, "Skipping MCLR tree\n");        smk->mclr_tbl = av_malloc(sizeof(int) * 2);        smk->mclr_tbl[0] = 0;        smk->mclr_last[0] = smk->mclr_last[1] = smk->mclr_last[2] = 1;    } else {        smacker_decode_header_tree(smk, &gb, &smk->mclr_tbl, smk->mclr_last, mclr_size);    }    if(!get_bits(&gb, 1)) {        av_log(smk->avctx, AV_LOG_INFO, "Skipping FULL tree\n");        smk->full_tbl = av_malloc(sizeof(int) * 2);        smk->full_tbl[0] = 0;        smk->full_last[0] = smk->full_last[1] = smk->full_last[2] = 1;    } else {        smacker_decode_header_tree(smk, &gb, &smk->full_tbl, smk->full_last, full_size);    }    if(!get_bits(&gb, 1)) {        av_log(smk->avctx, AV_LOG_INFO, "Skipping TYPE tree\n");        smk->type_tbl = av_malloc(sizeof(int) * 2);        smk->type_tbl[0] = 0;        smk->type_last[0] = smk->type_last[1] = smk->type_last[2] = 1;    } else {        smacker_decode_header_tree(smk, &gb, &smk->type_tbl, smk->type_last, type_size);    }    return 0;}static always_inline void last_reset(int *recode, int *last) {    recode[last[0]] = recode[last[1]] = recode[last[2]] = 0;}/* get code and update history */static always_inline int smk_get_code(GetBitContext *gb, int *recode, int *last) {    register int *table = recode;    int v, b;    b = get_bits_count(gb);    while(*table & SMK_NODE) {        if(get_bits1(gb))            table += (*table) & (~SMK_NODE);        table++;    }    v = *table;    b = get_bits_count(gb) - b;    if(v != recode[last[0]]) {        recode[last[2]] = recode[last[1]];        recode[last[1]] = recode[last[0]];        recode[last[0]] = v;    }    return v;}static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size){    SmackVContext * const smk = (SmackVContext *)avctx->priv_data;    uint8_t *out;    uint32_t *pal;    GetBitContext gb;    int blocks, blk, bw, bh;    int i;    int stride;    if(buf_size == 769)        return 0;    if(smk->pic.data[0])            avctx->release_buffer(avctx, &smk->pic);    smk->pic.reference = 1;    smk->pic.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;    if(avctx->reget_buffer(avctx, &smk->pic) < 0){        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");        return -1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -