yading@10: /* yading@10: * Copyright (C) 2007 Marco Gerards yading@10: * Copyright (C) 2009 David Conrad yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * Arithmetic decoder for Dirac yading@10: * @author Marco Gerards yading@10: */ yading@10: yading@10: #ifndef AVCODEC_DIRAC_ARITH_H yading@10: #define AVCODEC_DIRAC_ARITH_H yading@10: yading@10: #include "bytestream.h" yading@10: #include "get_bits.h" yading@10: yading@10: enum dirac_arith_contexts { yading@10: CTX_ZPZN_F1, yading@10: CTX_ZPNN_F1, yading@10: CTX_NPZN_F1, yading@10: CTX_NPNN_F1, yading@10: CTX_ZP_F2, yading@10: CTX_ZP_F3, yading@10: CTX_ZP_F4, yading@10: CTX_ZP_F5, yading@10: CTX_ZP_F6, yading@10: CTX_NP_F2, yading@10: CTX_NP_F3, yading@10: CTX_NP_F4, yading@10: CTX_NP_F5, yading@10: CTX_NP_F6, yading@10: CTX_COEFF_DATA, yading@10: CTX_SIGN_NEG, yading@10: CTX_SIGN_ZERO, yading@10: CTX_SIGN_POS, yading@10: CTX_ZERO_BLOCK, yading@10: CTX_DELTA_Q_F, yading@10: CTX_DELTA_Q_DATA, yading@10: CTX_DELTA_Q_SIGN, yading@10: yading@10: DIRAC_CTX_COUNT yading@10: }; yading@10: yading@10: // Dirac resets the arith decoder between decoding various types of data, yading@10: // so many contexts are never used simultaneously. Thus, we can reduce yading@10: // the number of contexts needed by reusing them. yading@10: #define CTX_SB_F1 CTX_ZP_F5 yading@10: #define CTX_SB_DATA 0 yading@10: #define CTX_PMODE_REF1 0 yading@10: #define CTX_PMODE_REF2 1 yading@10: #define CTX_GLOBAL_BLOCK 2 yading@10: #define CTX_MV_F1 CTX_ZP_F2 yading@10: #define CTX_MV_DATA 0 yading@10: #define CTX_DC_F1 CTX_ZP_F5 yading@10: #define CTX_DC_DATA 0 yading@10: yading@10: typedef struct { yading@10: unsigned low; yading@10: uint16_t range; yading@10: int16_t counter; yading@10: yading@10: const uint8_t *bytestream; yading@10: const uint8_t *bytestream_end; yading@10: yading@10: uint16_t contexts[DIRAC_CTX_COUNT]; yading@10: } DiracArith; yading@10: yading@10: extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT]; yading@10: extern const uint16_t ff_dirac_prob[256]; yading@10: extern int16_t ff_dirac_prob_branchless[256][2]; yading@10: yading@10: static inline void renorm(DiracArith *c) yading@10: { yading@10: #if HAVE_FAST_CLZ yading@10: int shift = 14 - av_log2_16bit(c->range-1) + ((c->range-1)>>15); yading@10: yading@10: c->low <<= shift; yading@10: c->range <<= shift; yading@10: c->counter += shift; yading@10: #else yading@10: while (c->range <= 0x4000) { yading@10: c->low <<= 1; yading@10: c->range <<= 1; yading@10: c->counter++; yading@10: } yading@10: #endif yading@10: } yading@10: yading@10: static inline void refill(DiracArith *c) yading@10: { yading@10: int counter = c->counter; yading@10: yading@10: if (counter >= 0) { yading@10: int new = bytestream_get_be16(&c->bytestream); yading@10: yading@10: // the spec defines overread bits to be 1, and streams rely on this yading@10: if (c->bytestream > c->bytestream_end) { yading@10: new |= 0xff; yading@10: if (c->bytestream > c->bytestream_end+1) yading@10: new |= 0xff00; yading@10: yading@10: c->bytestream = c->bytestream_end; yading@10: } yading@10: yading@10: c->low += new << counter; yading@10: counter -= 16; yading@10: } yading@10: c->counter = counter; yading@10: } yading@10: yading@10: static inline int dirac_get_arith_bit(DiracArith *c, int ctx) yading@10: { yading@10: int prob_zero = c->contexts[ctx]; yading@10: int range_times_prob, bit; yading@10: unsigned low = c->low; yading@10: int range = c->range; yading@10: yading@10: range_times_prob = (c->range * prob_zero) >> 16; yading@10: yading@10: #if HAVE_FAST_CMOV && HAVE_INLINE_ASM yading@10: low -= range_times_prob << 16; yading@10: range -= range_times_prob; yading@10: bit = 0; yading@10: __asm__( yading@10: "cmpl %5, %4 \n\t" yading@10: "setae %b0 \n\t" yading@10: "cmovb %3, %2 \n\t" yading@10: "cmovb %5, %1 \n\t" yading@10: : "+q"(bit), "+r"(range), "+r"(low) yading@10: : "r"(c->low), "r"(c->low>>16), yading@10: "r"(range_times_prob) yading@10: ); yading@10: #else yading@10: bit = (low >> 16) >= range_times_prob; yading@10: if (bit) { yading@10: low -= range_times_prob << 16; yading@10: range -= range_times_prob; yading@10: } else { yading@10: range = range_times_prob; yading@10: } yading@10: #endif yading@10: yading@10: c->contexts[ctx] += ff_dirac_prob_branchless[prob_zero>>8][bit]; yading@10: c->low = low; yading@10: c->range = range; yading@10: yading@10: renorm(c); yading@10: refill(c); yading@10: return bit; yading@10: } yading@10: yading@10: static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_ctx) yading@10: { yading@10: int ret = 1; yading@10: while (!dirac_get_arith_bit(c, follow_ctx)) { yading@10: ret <<= 1; yading@10: ret += dirac_get_arith_bit(c, data_ctx); yading@10: follow_ctx = ff_dirac_next_ctx[follow_ctx]; yading@10: } yading@10: return ret-1; yading@10: } yading@10: yading@10: static inline int dirac_get_arith_int(DiracArith *c, int follow_ctx, int data_ctx) yading@10: { yading@10: int ret = dirac_get_arith_uint(c, follow_ctx, data_ctx); yading@10: if (ret && dirac_get_arith_bit(c, data_ctx+1)) yading@10: ret = -ret; yading@10: return ret; yading@10: } yading@10: yading@10: void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length); yading@10: yading@10: #endif /* AVCODEC_DIRAC_ARITH_H */