751 lines · 23.0 KB · C
RawDownload
/* * ClearVideo decoder * Copyright (c) 2012-2018 Konstantin Shishkov * * 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 */ /** * @file * ClearVideo decoder */ #include "libavutil/mem.h"#include "libavutil/mem_internal.h"#include "libavutil/thread.h" #include "avcodec.h"#include "bytestream.h"#include "codec_internal.h"#include "decode.h"#include "get_bits.h"#include "idctdsp.h"#include "mathops.h"#include "clearvideodata.h" #define CLV_VLC_BITS 9 typedef struct LevelCodes {    const VLCElem *flags_cb;    const VLCElem *mv_cb;    const VLCElem *bias_cb;} LevelCodes; typedef struct MV {    int16_t x, y;} MV; static const MV zero_mv = { 0 }; typedef struct MVInfo {    int mb_w;    int mb_h;    int mb_size;    int mb_stride;    int top;    MV  *mv;} MVInfo; typedef struct CLVContext {    AVCodecContext *avctx;    IDCTDSPContext idsp;    AVFrame        *pic;    AVFrame        *prev;    GetBitContext  gb;    int            mb_width, mb_height;    int            pmb_width, pmb_height;    MVInfo         mvi;    int            tile_size;    int            tile_shift;    int            luma_dc_quant, chroma_dc_quant, ac_quant;    DECLARE_ALIGNED(16, int16_t, block)[64];    int            top_dc[3], left_dc[4];} CLVContext; static VLCElem    dc_vlc[1104], ac_vlc[554];static LevelCodes lev[4 + 3 + 3]; // 0..3: Y, 4..6: U, 7..9: V static inline int decode_block(CLVContext *ctx, int16_t *blk, int has_ac,                               int ac_quant){    GetBitContext *gb = &ctx->gb;    int idx = 1, last = 0, val, skip;     memset(blk, 0, sizeof(*blk) * 64);    blk[0] = get_vlc2(gb, dc_vlc, CLV_VLC_BITS, 3);     if (!has_ac)        return 0;     while (idx < 64 && !last) {        val = get_vlc2(gb, ac_vlc, CLV_VLC_BITS, 2);        if (val < 0)            return AVERROR_INVALIDDATA;        if (val != 0x1BFF) {            last =  val >> 12;            skip = (val >> 4) & 0xFF;            val &= 0xF;            if (get_bits1(gb))                val = -val;        } else {            last = get_bits1(gb);            skip = get_bits(gb, 6);            val  = get_sbits(gb, 8);        }        if (val) {            int aval = FFABS(val), sign = val < 0;            val = ac_quant * (2 * aval + 1);            if (!(ac_quant & 1))                val--;            if (sign)                val = -val;        }        idx += skip;        if (idx >= 64)            return AVERROR_INVALIDDATA;        blk[ff_zigzag_direct[idx++]] = val;    }     return (idx <= 64 && last) ? 0 : -1;} #define DCT_TEMPLATE(blk, step, bias, shift, dshift, OP)                \    const int t0 = OP(2841 * blk[1 * step] +  565 * blk[7 * step]);     \    const int t1 = OP( 565 * blk[1 * step] - 2841 * blk[7 * step]);     \    const int t2 = OP(1609 * blk[5 * step] + 2408 * blk[3 * step]);     \    const int t3 = OP(2408 * blk[5 * step] - 1609 * blk[3 * step]);     \    const int t4 = OP(1108 * blk[2 * step] - 2676 * blk[6 * step]);     \    const int t5 = OP(2676 * blk[2 * step] + 1108 * blk[6 * step]);     \    const int t6 = ((blk[0 * step] + blk[4 * step]) * (1 << dshift)) + bias;  \    const int t7 = ((blk[0 * step] - blk[4 * step]) * (1 << dshift)) + bias;  \    const int t8 = t0 + t2;                                             \    const int t9 = t0 - t2;                                             \    const int tA = (int)(181U * (t9 + (t1 - t3)) + 0x80) >> 8;          \    const int tB = (int)(181U * (t9 - (t1 - t3)) + 0x80) >> 8;          \    const int tC = t1 + t3;                                             \                                                                        \    blk[0 * step] = (t6 + t5 + t8) >> shift;                            \    blk[1 * step] = (t7 + t4 + tA) >> shift;                            \    blk[2 * step] = (t7 - t4 + tB) >> shift;                            \    blk[3 * step] = (t6 - t5 + tC) >> shift;                            \    blk[4 * step] = (t6 - t5 - tC) >> shift;                            \    blk[5 * step] = (t7 - t4 - tB) >> shift;                            \    blk[6 * step] = (t7 + t4 - tA) >> shift;                            \    blk[7 * step] = (t6 + t5 - t8) >> shift;                            \ #define ROP(x) x#define COP(x) (((x) + 4) >> 3) static void clv_dct(int16_t *block){    int i;    int16_t *ptr;     ptr = block;    for (i = 0; i < 8; i++) {        DCT_TEMPLATE(ptr, 1, 0x80, 8, 11, ROP);        ptr += 8;    }     ptr = block;    for (i = 0; i < 8; i++) {        DCT_TEMPLATE(ptr, 8, 0x2000, 14, 8, COP);        ptr++;    }} static int decode_mb(CLVContext *c, int x, int y){    int i, has_ac[6], off;     for (i = 0; i < 6; i++)        has_ac[i] = get_bits1(&c->gb);     off = x * 16 + y * 16 * c->pic->linesize[0];    for (i = 0; i < 4; i++) {        if (decode_block(c, c->block, has_ac[i], c->ac_quant) < 0)            return AVERROR_INVALIDDATA;        if (!x && !(i & 1)) {            c->block[0] += c->top_dc[0];            c->top_dc[0] = c->block[0];        } else {            c->block[0] += c->left_dc[(i & 2) >> 1];        }        c->left_dc[(i & 2) >> 1] = c->block[0];        c->block[0]             *= c->luma_dc_quant;        clv_dct(c->block);        if (i == 2)            off += c->pic->linesize[0] * 8;        c->idsp.put_pixels_clamped(c->block,                                   c->pic->data[0] + off + (i & 1) * 8,                                   c->pic->linesize[0]);    }     off = x * 8 + y * 8 * c->pic->linesize[1];    for (i = 1; i < 3; i++) {        if (decode_block(c, c->block, has_ac[i + 3], c->ac_quant) < 0)            return AVERROR_INVALIDDATA;        if (!x) {            c->block[0] += c->top_dc[i];            c->top_dc[i] = c->block[0];        } else {            c->block[0] += c->left_dc[i + 1];        }        c->left_dc[i + 1] = c->block[0];        c->block[0]      *= c->chroma_dc_quant;        clv_dct(c->block);        c->idsp.put_pixels_clamped(c->block, c->pic->data[i] + off,                                   c->pic->linesize[i]);    }     return 0;} static int copy_block(AVCodecContext *avctx, AVFrame *dst, const AVFrame *src,                      int plane, int x, int y, int dx, int dy, int size){    int shift = plane > 0;    int sx = x + dx;    int sy = y + dy;    int sstride, dstride, soff, doff;    uint8_t *dbuf;    const uint8_t *sbuf;    int i;     if (x < 0 || sx < 0 || y < 0 || sy < 0 ||        x + size > avctx->coded_width >> shift ||        y + size > avctx->coded_height >> shift ||        sx + size > avctx->coded_width >> shift ||        sy + size > avctx->coded_height >> shift)        return AVERROR_INVALIDDATA;     sstride = src->linesize[plane];    dstride = dst->linesize[plane];    soff    = sx + sy * sstride;    sbuf    = src->data[plane];    doff    = x + y * dstride;    dbuf    = dst->data[plane];     for (i = 0; i < size; i++) {        uint8_t *dptr = &dbuf[doff];        const uint8_t *sptr = &sbuf[soff];         memcpy(dptr, sptr, size);        doff += dstride;        soff += sstride;    }     return 0;} static int copyadd_block(AVCodecContext *avctx, AVFrame *dst, const AVFrame *src,                         int plane, int x, int y, int dx, int dy, int size, int bias){    int shift = plane > 0;    int sx = x + dx;    int sy = y + dy;    int sstride   = src->linesize[plane];    int dstride   = dst->linesize[plane];    int soff      = sx + sy * sstride;    const uint8_t *sbuf = src->data[plane];    int doff      = x + y * dstride;    uint8_t *dbuf = dst->data[plane];    int i, j;     if (x < 0 || sx < 0 || y < 0 || sy < 0 ||        x + size > avctx->coded_width >> shift ||        y + size > avctx->coded_height >> shift ||        sx + size > avctx->coded_width >> shift ||        sy + size > avctx->coded_height >> shift)        return AVERROR_INVALIDDATA;     for (j = 0; j < size; j++) {        uint8_t *dptr = &dbuf[doff];        const uint8_t *sptr = &sbuf[soff];         for (i = 0; i < size; i++) {            int val = sptr[i] + bias;             dptr[i] = av_clip_uint8(val);        }         doff += dstride;        soff += sstride;    }     return 0;} static MV *mvi_predict(MVInfo *mvi, int mb_x, int mb_y){    MV res, pred_mv;    int left_mv, right_mv, top_mv, bot_mv;     if (mvi->top) {        if (mb_x > 0) {            pred_mv = mvi->mv[mvi->mb_stride + mb_x - 1];        } else {            pred_mv = zero_mv;        }    } else if ((mb_x == 0) || (mb_x == mvi->mb_w - 1)) {        pred_mv = mvi->mv[mb_x];    } else {        MV A = mvi->mv[mvi->mb_stride + mb_x - 1];        MV B = mvi->mv[                 mb_x    ];        MV C = mvi->mv[                 mb_x + 1];        pred_mv.x = mid_pred(A.x, B.x, C.x);        pred_mv.y = mid_pred(A.y, B.y, C.y);    }     res = pred_mv;     left_mv = -((mb_x * mvi->mb_size));    right_mv = ((mvi->mb_w - mb_x - 1) * mvi->mb_size);    if (res.x < left_mv) {        res.x = left_mv;    }    if (res.x > right_mv) {        res.x = right_mv;    }    top_mv = -((mb_y * mvi->mb_size));    bot_mv = ((mvi->mb_h - mb_y - 1) * mvi->mb_size);    if (res.y < top_mv) {        res.y = top_mv;    }    if (res.y > bot_mv) {        res.y = bot_mv;    }     mvi->mv[mvi->mb_stride + mb_x].x = res.x;    mvi->mv[mvi->mb_stride + mb_x].y = res.y;     return &mvi->mv[mvi->mb_stride + mb_x];} static void mvi_update_prediction(MV *mv, MV diff){    mv->x += diff.x;    mv->y += diff.y;} static void mvi_reset(MVInfo *mvi, int mb_w, int mb_h, int mb_size){    mvi->top       = 1;    mvi->mb_w      = mb_w;    mvi->mb_h      = mb_h;    mvi->mb_size   = mb_size;    mvi->mb_stride = mb_w;    memset(mvi->mv, 0, sizeof(MV) * mvi->mb_stride * 2);} static void mvi_update_row(MVInfo *mvi){    int i;     mvi->top = 0;    for (i = 0 ; i < mvi->mb_stride; i++) {        mvi->mv[i] = mvi->mv[mvi->mb_stride + i];    }} static int tile_do_block(AVCodecContext *avctx, AVFrame *dst, const AVFrame *src,                         int plane, int x, int y, int dx, int dy, int size, int bias){    int ret;     if (!bias) {        ret = copy_block(avctx, dst, src, plane, x, y, dx, dy, size);    } else {        ret = copyadd_block(avctx, dst, src, plane, x, y, dx, dy, size, bias);    }     return ret;} static int decode_tile(AVCodecContext *avctx, GetBitContext *gb,                       const LevelCodes *lc,                       AVFrame *dst, const AVFrame *src,                       int plane, int x, int y, int size,                       MV root_mv, MV *pred){    int i, flags = 0;    int16_t bias = 0;    MV mv = { 0 };    int err;     if (lc->flags_cb)        flags = get_vlc2(gb, lc->flags_cb, CLV_VLC_BITS, 2);     if (lc->mv_cb) {        uint16_t mv_code = get_vlc2(gb, lc->mv_cb, CLV_VLC_BITS, 2);         if (mv_code != MV_ESC) {            mv.x = (int8_t)(mv_code & 0xff);            mv.y = (int8_t)(mv_code >> 8);        } else {            mv.x = get_sbits(gb, 8);            mv.y = get_sbits(gb, 8);        }        if (pred)            mvi_update_prediction(pred, mv);    }    mv.x += root_mv.x;    mv.y += root_mv.y;     if (lc->bias_cb) {        uint16_t bias_val = get_vlc2(gb, lc->bias_cb, CLV_VLC_BITS, 2);         if (bias_val != BIAS_ESC) {            bias = (int16_t)(bias_val);        } else {            bias = get_sbits(gb, 16);        }    }     if (flags) {        int hsize = size >> 1;        for (i = 0; i < 4; i++) {            int xoff = (i & 2) == 0 ? 0 : hsize;            int yoff = (i & 1) == 0 ? 0 : hsize;             if (flags & (1 << i)) {                err = decode_tile(avctx, gb, lc + 1, dst, src, plane,                                  x + xoff, y + yoff, hsize, root_mv, NULL);            } else {                err = tile_do_block(avctx, dst, src, plane, x + xoff, y + yoff,                                    mv.x, mv.y, hsize, bias);            }            if (err < 0)                return err;        }    } else {        err = tile_do_block(avctx, dst, src, plane, x, y, mv.x, mv.y, size, bias);        if (err < 0)            return err;    }     return 0;} static void extend_edges(AVFrame *buf, int tile_size){    int comp, i, j;     for (comp = 0; comp < 3; comp++) {        int shift = comp > 0;        int w = buf->width  >> shift;        int h = buf->height >> shift;        int size = comp == 0 ? tile_size : tile_size >> 1;        int stride = buf->linesize[comp];        uint8_t *framebuf = buf->data[comp];         int right  = size - (w & (size - 1));        int bottom = size - (h & (size - 1));         if ((right == size) && (bottom == size)) {            return;        }        if (right != size) {            int off = w;            for (j = 0; j < h; j++) {                for (i = 0; i < right; i++) {                    framebuf[off + i] = 0x80;                }                off += stride;            }        }        if (bottom != size) {            int off = h * stride;            for (j = 0; j < bottom; j++) {                for (i = 0; i < stride; i++) {                    framebuf[off + i] = 0x80;                }                off += stride;            }        }    }} static int clv_decode_frame(AVCodecContext *avctx, AVFrame *rframe,                            int *got_frame, AVPacket *avpkt){    const uint8_t *buf = avpkt->data;    int buf_size = avpkt->size;    CLVContext *c = avctx->priv_data;    GetByteContext gb;    uint32_t frame_type;    int i, j, ret;    int mb_ret = 0;     bytestream2_init(&gb, buf, buf_size);    if (avctx->codec_tag == MKTAG('C', 'L', 'V', '1')) {        int skip = bytestream2_get_byte(&gb);        bytestream2_skip(&gb, (skip + 1) * 8);    }     frame_type = bytestream2_get_byte(&gb);

Lines 1–500 of 751.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t