[FFmpeg-soc] [soc]: r297 - rv40/rv40.c
kostya
subversion at mplayerhq.hu
Sun Jul 1 16:05:08 CEST 2007
Author: kostya
Date: Sun Jul 1 16:05:08 2007
New Revision: 297
Log:
Skeleton and some functions for RV40 decoder.
Added:
rv40/rv40.c
Added: rv40/rv40.c
==============================================================================
--- (empty file)
+++ rv40/rv40.c Sun Jul 1 16:05:08 2007
@@ -0,0 +1,568 @@
+/*
+ * RV40 decoder
+ * Copyright (c) 2007 Mike Melanson, 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 rv40.c
+ * RV40 decoder.
+ */
+
+#include "avcodec.h"
+#include "dsputil.h"
+#include "mpegvideo.h"
+
+#include "rv40vlc.h"
+#include "rv40data.h"
+
+//#define DEBUG
+
+/** Decoder context */
+typedef struct RV40DecContext{
+ MpegEncContext s;
+ int mb_bits; ///< bits needed to read MB offet in slice header
+}RV40DecContext;
+
+
+/**
+ * VLC tables used by decoder
+ *
+ * intra frame VLC sets do not contain some of those tables
+ */
+typedef struct RV40VLC{
+ VLC cbppattern[2]; ///< VLCs used for pattern of coded block patterns decoding
+ VLC cbp[2][4]; ///< VLCs used for coded block patterns decoding
+ VLC first_pattern[4]; ///< VLCs used for decoding coefficients in the first subblock
+ VLC second_pattern[2]; ///< VLCs used for decoding coefficients in the subblocks 2 and 3
+ VLC third_pattern[2]; ///< VLCs used for decoding coefficients in the last subblock
+ VLC coefficient; ///< VLCs used for decoding big coefficients
+}RV40VLC;
+
+static RV40VLC intra_vlcs[NUM_INTRA_TABLES], inter_vlcs[NUM_INTER_TABLES];
+
+/**
+ * @defgroup vlc RV40 VLC generating functions
+ * @{
+ */
+
+/**
+ * Generate VLC from codeword lengths
+ */
+static int rv40_gen_vlc(const uint8_t *bits2, int size, VLC *vlc)
+{
+ int i;
+ int counts[17], codes[17];
+ uint16_t *cw, *syms;
+ uint8_t *bits;
+ int maxbits = 0, realsize;
+ int ret;
+
+ memset(counts, 0, 16 * sizeof(int));
+
+ cw = av_mallocz(size * 2);
+ syms = av_malloc(size * 2);
+ bits = av_malloc(size);
+
+ realsize = 0;
+ for(i = 0; i < size; i++){
+ if(bits2[i]){
+ bits[realsize] = bits2[i];
+ syms[realsize] = i;
+ realsize++;
+ if(bits2[i] > maxbits)
+ maxbits = bits2[i];
+ }
+ }
+
+ size = realsize;
+ for(i = 0; i < size; i++)
+ counts[bits[i]]++;
+ codes[0] = 0;
+ for(i = 0; i < 16; i++)
+ codes[i+1] = (codes[i] + counts[i]) << 1;
+ for(i = 0; i < realsize; i++)
+ cw[i] = codes[bits[i]]++;
+
+ ret = init_vlc_sparse(vlc, FFMIN(maxbits, 9), size,
+ bits, 1, 1,
+ cw, 2, 2,
+ syms, 2, 2, INIT_VLC_USE_STATIC);
+ av_free(cw);
+ av_free(syms);
+ av_free(bits);
+ return ret;
+}
+
+/**
+ * Initialize all tables
+ */
+static void rv40_init_tables()
+{
+ int i, j, k;
+
+ for(i = 0; i < NUM_INTRA_TABLES; i++){
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_intra_cbppatvlc_pointers[i][j], CBPPAT_VLC_SIZE, &intra_vlcs[i].cbppattern[j]);
+ for(j = 0; j < 2; j++)
+ for(k = 0; k < 4; k++)
+ rv40_gen_vlc(rv40_intra_cbpvlc_pointers[i][j][k], CBP_VLC_SIZE, &intra_vlcs[i].cbp[j][k]);
+ for(j = 0; j < 4; j++)
+ rv40_gen_vlc(rv40_intra_firstpatvlc_pointers[i][j], FIRSTBLK_VLC_SIZE, &intra_vlcs[i].first_pattern[j]);
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_intra_secondpatvlc_pointers[i][j], OTHERBLK_VLC_SIZE, &intra_vlcs[i].second_pattern[j]);
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_intra_thirdpatvlc_pointers[i][j], OTHERBLK_VLC_SIZE, &intra_vlcs[i].third_pattern[j]);
+ rv40_gen_vlc(rv40_intra_coeffvlc_pointers[i], COEFF_VLC_SIZE, &intra_vlcs[i].coefficient);
+ }
+
+ for(i = 0; i < NUM_INTER_TABLES; i++){
+ rv40_gen_vlc(rv40_inter_cbppatvlc_pointers[i], CBPPAT_VLC_SIZE, &inter_vlcs[i].cbppattern[0]);
+ for(j = 0; j < 4; j++)
+ rv40_gen_vlc(rv40_inter_cbpvlc_pointers[i][j], CBP_VLC_SIZE, &inter_vlcs[i].cbp[0][j]);
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_inter_firstpatvlc_pointers[i][j], FIRSTBLK_VLC_SIZE, &inter_vlcs[i].first_pattern[j]);
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_inter_secondpatvlc_pointers[i][j], OTHERBLK_VLC_SIZE, &inter_vlcs[i].second_pattern[j]);
+ for(j = 0; j < 2; j++)
+ rv40_gen_vlc(rv40_inter_thirdpatvlc_pointers[i][j], OTHERBLK_VLC_SIZE, &inter_vlcs[i].third_pattern[j]);
+ rv40_gen_vlc(rv40_inter_coeffvlc_pointers[i], COEFF_VLC_SIZE, &inter_vlcs[i].coefficient);
+ }
+}
+
+/** @} */ // vlc group
+
+
+/**
+ * @defgroup transform RV40 inverse transform functions
+ * @{
+ */
+
+/**
+ * Real Video 4.0 inverse transform
+ * Code is almost the same as in SVQ3, only scaling is different
+ */
+static void rv40_intra_inv_transform(DCTELEM *block, const int offset){
+ int temp[16];
+ unsigned int i;
+
+ for(i=0; i<4; i++){
+ const int z0= 13*(block[offset+i+8*0] + block[offset+i+8*2]);
+ const int z1= 13*(block[offset+i+8*0] - block[offset+i+8*2]);
+ const int z2= 7* block[offset+i+8*1] - 17*block[offset+i+8*3];
+ const int z3= 17* block[offset+i+8*1] + 7*block[offset+i+8*3];
+
+ temp[4*i+0]= z0+z3;
+ temp[4*i+1]= z1+z2;
+ temp[4*i+2]= z1-z2;
+ temp[4*i+3]= z0-z3;
+ }
+
+ for(i=0; i<4; i++){
+ const int z0= 13*(temp[4*0+i] + temp[4*2+i]);
+ const int z1= 13*(temp[4*0+i] - temp[4*2+i]);
+ const int z2= 7* temp[4*1+i] - 17*temp[4*3+i];
+ const int z3= 17* temp[4*1+i] + 7*temp[4*3+i];
+
+ block[offset+i*8+0]= ((z0 + z3) + 0x200)>>10;
+ block[offset+i*8+1]= ((z1 + z2) + 0x200)>>10;
+ block[offset+i*8+2]= ((z1 - z2) + 0x200)>>10;
+ block[offset+i*8+3]= ((z0 - z3) + 0x200)>>10;
+ }
+
+}
+
+/**
+ * RealVideo 4.0 inverse transform - special version
+ *
+ * Code is almost the same but final coefficients are multiplied by 1.5
+ * and have no rounding
+ */
+static void rv40_intra_inv_transform_noround(DCTELEM *block, const int offset){
+ int temp[16];
+ unsigned int i;
+
+ for(i=0; i<4; i++){
+ const int z0= 13*(block[offset+i+8*0] + block[offset+i+8*2]);
+ const int z1= 13*(block[offset+i+8*0] - block[offset+i+8*2]);
+ const int z2= 7* block[offset+i+8*1] - 17*block[offset+i+8*3];
+ const int z3= 17* block[offset+i+8*1] + 7*block[offset+i+8*3];
+
+ temp[4*i+0]= z0+z3;
+ temp[4*i+1]= z1+z2;
+ temp[4*i+2]= z1-z2;
+ temp[4*i+3]= z0-z3;
+ }
+
+ for(i=0; i<4; i++){
+ const int z0= 13*(temp[4*0+i] + temp[4*2+i]);
+ const int z1= 13*(temp[4*0+i] - temp[4*2+i]);
+ const int z2= 7* temp[4*1+i] - 17*temp[4*3+i];
+ const int z3= 17* temp[4*1+i] + 7*temp[4*3+i];
+
+ block[offset+i*8+0]= ((z0 + z3)*3)>>11;
+ block[offset+i*8+1]= ((z1 + z2)*3)>>11;
+ block[offset+i*8+2]= ((z1 - z2)*3)>>11;
+ block[offset+i*8+3]= ((z0 - z3)*3)>>11;
+ }
+
+}
+
+/** @} */ // transform
+
+
+/**
+ * @defgroup block RV40 4x4 block decoding functions
+ * @{
+ */
+
+/**
+ * Decode coded block pattern
+ */
+static int rv40_decode_cbp(GetBitContext *gb, RV40VLC *vlc, int table)
+{
+ int pattern, code, cbp=0;
+ int table2;
+ static const int cbp_masks[4] = {0x000000, 0x100000, 0x010000, 0x110000};
+ int i, t, mask, shift;
+
+ code = get_vlc2(gb, vlc->cbppattern[table].table, 9, 2);
+ pattern = code & 0xF;
+ code >>= 4;
+
+ table2 = rv40_count_ones[pattern];
+
+ for(shift = 0, mask = 8; mask; mask >>= 1){
+ if(!(pattern & mask)) continue;
+ t = get_vlc2(gb, vlc->cbp[table][table2].table, vlc->cbp[table][table2].bits, 1);
+ cbp |= rv40_cbp_code[t] << shift;
+ shift += 2;
+ if(mask == 4) shift += 4;
+ }
+
+ for(i = 0; i < 4; i++){
+ t = modulo_three_table[code][i];
+ if(t == 1)
+ cbp |= cbp_masks[1+get_bits1(gb)] << i;
+ if(t == 2)
+ cbp |= cbp_masks[3] << i;
+ }
+ return cbp;
+}
+
+#define DECODE_COEFF(dst, dstidx, coef, esc, gb, vlc) \
+ if(coef){ \
+ if(coef == esc){ \
+ coef = get_vlc2(gb, vlc.table, 9, 2); \
+ if(coef > 23){ \
+ coef -= 23; \
+ coef = 22 + ((1 << coef) | get_bits(gb, coef)); \
+ } \
+ coef += esc; \
+ } \
+ if(get_bits1(gb)) \
+ coef = -coef; \
+ dst[dstidx] = coef; \
+ }
+
+#define DECODE_2x2_BLOCK(dst, dstoff, stride, coeffs, gb, vlc) \
+ DECODE_COEFF(dst, dstoff+0 , coeffs[0], 3, gb, vlc); \
+ DECODE_COEFF(dst, dstoff+1 , coeffs[1], 2, gb, vlc); \
+ DECODE_COEFF(dst, dstoff+0+stride, coeffs[2], 2, gb, vlc); \
+ DECODE_COEFF(dst, dstoff+1+stride, coeffs[3], 2, gb, vlc); \
+
+/**
+ * Decode coefficients for 4x4 block
+ *
+ * This is done by filling 2x2 subblocks with decoded coefficients
+ * in this order (the same for subblocks and subblock coefficients):
+ * o--o
+ * /
+ * /
+ * o--o
+ */
+
+static inline void rv40_decode_block(DCTELEM *dst, GetBitContext *gb, RV40VLC *rvlc, int fc, int sc)
+{
+ int code, pattern;
+ int coeffs[4];
+
+ code = get_vlc2(gb, rvlc->first_pattern[fc].table, 9, 2);
+
+ pattern = code & 0x7;
+
+ code >>= 3;
+ coeffs[0] = modulo_three_table[code][0];
+ coeffs[1] = modulo_three_table[code][1];
+ coeffs[2] = modulo_three_table[code][2];
+ coeffs[3] = modulo_three_table[code][3];
+ DECODE_2x2_BLOCK(dst, 0, 8, coeffs, gb, rvlc->coefficient);
+
+ if(pattern & 4){
+ code = get_vlc2(gb, rvlc->second_pattern[sc].table, 9, 2);
+ coeffs[0] = modulo_three_table[code][0];
+ coeffs[1] = modulo_three_table[code][1];
+ coeffs[2] = modulo_three_table[code][2];
+ coeffs[3] = modulo_three_table[code][3];
+ DECODE_2x2_BLOCK(dst, 2, 8, coeffs, gb, rvlc->coefficient);
+ }
+ if(pattern & 2){
+ code = get_vlc2(gb, rvlc->second_pattern[sc].table, 9, 2);
+ coeffs[0] = modulo_three_table[code][0];
+ coeffs[1] = modulo_three_table[code][1];
+ coeffs[2] = modulo_three_table[code][2];
+ coeffs[3] = modulo_three_table[code][3];
+ DECODE_2x2_BLOCK(dst, 8*2+0, 8, coeffs, gb, rvlc->coefficient);
+ }
+ if(pattern & 1){
+ code = get_vlc2(gb, rvlc->third_pattern[sc].table, 9, 2);
+ coeffs[0] = modulo_three_table[code][0];
+ coeffs[1] = modulo_three_table[code][1];
+ coeffs[2] = modulo_three_table[code][2];
+ coeffs[3] = modulo_three_table[code][3];
+ DECODE_2x2_BLOCK(dst, 8*2+2, 8, coeffs, gb, rvlc->coefficient);
+ }
+}
+
+/** @} */ //block functions
+
+
+/**
+ * @defgroup bitstream RV40 bitstream parsing
+ * @{
+ */
+
+/**
+ * Get encoded picture size - usually this is called from rv40_parse_slice_header
+ *
+ * If the width/height is the standard one then it's coded as 3-bit index.
+ * Otherwise it is coded as escaped 8-bit portions.
+ */
+static void rv40_parse_picture_size(GetBitContext *gb, int *w, int *h)
+{
+ int t;
+
+ *w = rv40_standard_widths[get_bits(gb, 3)];
+ if(!*w){
+ do{
+ t = get_bits(gb, 8);
+ *w += t << 2;
+ }while(t == 0xFF);
+ }
+ *h = rv40_standard_heights[get_bits(gb, 3)];
+ if(!*h)
+ *h = rv40_standard_heights2[(*h | get_bits1(gb)) & 3];
+ if(!*h){
+ do{
+ t = get_bits(gb, 8);
+ *h += t << 2;
+ }while(t == 0xFF);
+ }
+}
+
+static int rv40_parse_slice_header(RV40DecContext *r, GetBitContext *gb)
+{
+ int ptype, quant, w, h, mb_bits, mb_start;
+
+ if(get_bits1(gb))
+ return -1;
+ ptype = get_bits(gb, 2);
+ quant = get_bits(gb, 5);
+ if(get_bits(gb, 2))
+ return -1;
+ get_bits(gb, 2); /// ???
+ if(get_bits1(gb))
+ return -1;
+ get_bits(gb, 13); /// ???
+ rv40_parse_picture_size(gb, &w, &h);
+ mb_bits = av_log2(r->s.mb_width) + av_log2(r->s.mb_height);
+ mb_start = get_bits(gb, mb_bits);
+ return 0;
+}
+/** @} */ //block functions
+
+
+/**
+ * Initialize decoder
+ * @todo Maybe redone in some other way
+ */
+static int rv40_decode_init(AVCodecContext *avctx)
+{
+ RV40DecContext *r = avctx->priv_data;
+ MpegEncContext *s = &r->s;
+
+ static int tables_done = 0;
+
+ MPV_decode_defaults(s);
+ s->avctx= avctx;
+ s->out_format = FMT_H264;
+ s->codec_id= avctx->codec_id;
+
+ s->width = avctx->width;
+ s->height = avctx->height;
+
+ r->s.avctx = avctx;
+ avctx->flags |= CODEC_FLAG_EMU_EDGE;
+ r->s.flags |= CODEC_FLAG_EMU_EDGE;
+
+ if (MPV_common_init(s) < 0)
+ return -1;
+
+ if(!tables_done){
+ rv40_init_tables();
+ tables_done = 1;
+
+ if(0){
+ uint8_t bits[] = {0xD1, 0xB7, 0x37, 0x6A};
+ GetBitContext gb;
+ int r;
+
+ init_get_bits(&gb, bits, sizeof(bits)*8);
+ r = rv40_decode_cbp(&gb, &intra_vlcs[2], 0);
+ av_log(NULL,0,"CBP=%04X, %d bits\n",r,get_bits_count(&gb));
+ }
+ if(0){
+ uint8_t bits[] = {0x6A,0xBF,0xFF,0x87,0xDA,0xBE,0x74,0x94,0xE0,0x29,0x0A,0xAB,0x30,0x4B,0x35,0x80,0x8D };
+ GetBitContext gb;
+ DCTELEM block[64];
+ int i,j,k;
+
+ init_get_bits(&gb, bits, sizeof(bits)*8);
+ get_bits1(&gb);
+ for(k=0;k<11;k++){
+ memset(block,0,64*sizeof(DCTELEM));
+ rv40_decode_block(block,&gb,&intra_vlcs[2],k<8,0);
+
+ for(j=0;j<4;j++){
+ for(i=0;i<4;i++)av_log(NULL,0," %3d",block[i+j*8]);
+ av_log(NULL,0,"\n");
+ }
+ av_log(NULL,0,"Used %d bits\n",get_bits_count(&gb));
+ }
+ }
+ }
+ return 0;
+}
+
+
+static int rv40_decode_frame(AVCodecContext *avctx,
+ void *data, int *data_size,
+ uint8_t *buf, int buf_size)
+{
+ RV40DecContext *v = avctx->priv_data;
+ MpegEncContext *s = &v->s;
+ AVFrame *pict = data;
+
+return 0;
+ /* no supplementary picture */
+ if (buf_size == 0) {
+ /* special case for last picture */
+ if (s->low_delay==0 && s->next_picture_ptr) {
+ *pict= *(AVFrame*)s->next_picture_ptr;
+ s->next_picture_ptr= NULL;
+
+ *data_size = sizeof(AVFrame);
+ }
+
+ return 0;
+ }
+
+ /* We need to set current_picture_ptr before reading the header,
+ * otherwise we cannot store anything in there. */
+ if(s->current_picture_ptr==NULL || s->current_picture_ptr->data[0]){
+ int i= ff_find_unused_picture(s, 0);
+ s->current_picture_ptr= &s->picture[i];
+ }
+
+ init_get_bits(&s->gb, buf, buf_size*8);
+
+ // for hurry_up==5
+ s->current_picture.pict_type= s->pict_type;
+ s->current_picture.key_frame= s->pict_type == I_TYPE;
+
+ /* skip B-frames if we don't have reference frames */
+ if(s->last_picture_ptr==NULL && (s->pict_type==B_TYPE || s->dropable))
+ return -1;//buf_size;
+
+ /* skip b frames if we are in a hurry */
+ if(avctx->hurry_up && s->pict_type==B_TYPE) return -1;//buf_size;
+ if( (avctx->skip_frame >= AVDISCARD_NONREF && s->pict_type==B_TYPE)
+ || (avctx->skip_frame >= AVDISCARD_NONKEY && s->pict_type!=I_TYPE)
+ || avctx->skip_frame >= AVDISCARD_ALL)
+ return buf_size;
+
+ /* skip everything if we are in a hurry>=5 */
+ if(avctx->hurry_up>=5)
+ return -1;//buf_size;
+
+ if(s->next_p_frame_damaged){
+ if(s->pict_type==B_TYPE)
+ return buf_size;
+ else
+ s->next_p_frame_damaged=0;
+ }
+
+ if(MPV_frame_start(s, avctx) < 0)
+ return -1;
+
+ ff_er_frame_start(s);
+
+///XXX: do actual decoding of slices
+
+ ff_er_frame_end(s);
+
+ MPV_frame_end(s);
+
+assert(s->current_picture.pict_type == s->current_picture_ptr->pict_type);
+assert(s->current_picture.pict_type == s->pict_type);
+ if (s->pict_type == B_TYPE || s->low_delay) {
+ *pict= *(AVFrame*)s->current_picture_ptr;
+ } else if (s->last_picture_ptr != NULL) {
+ *pict= *(AVFrame*)s->last_picture_ptr;
+ }
+
+ if(s->last_picture_ptr || s->low_delay){
+ *data_size = sizeof(AVFrame);
+ ff_print_debug_info(s, pict);
+ }
+
+ /* Return the Picture timestamp as the frame number */
+ /* we substract 1 because it is added on utils.c */
+ avctx->frame_number = s->picture_number - 1;
+
+ return buf_size;
+}
+
+static int rv40_decode_end(AVCodecContext *avctx)
+{
+ RV40DecContext *r = avctx->priv_data;
+
+ MPV_common_end(&r->s);
+ return 0;
+}
+
+AVCodec rv40_decoder = {
+ "rv40",
+ CODEC_TYPE_VIDEO,
+ CODEC_ID_RV40,
+ sizeof(RV40DecContext),
+ rv40_decode_init,
+ NULL,
+ rv40_decode_end,
+ rv40_decode_frame,
+};
More information about the FFmpeg-soc
mailing list