📄 decoder.c
字号:
/***************************************************************************** * * XVID MPEG-4 VIDEO CODEC * - Decoder Module - * * Copyright(C) 2002 MinChen <chenm001@163.com> * 2002-2004 Peter Ross <pross@xvid.org> * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ * ****************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef BFRAMES_DEC_DEBUG #define BFRAMES_DEC#endif#include "xvid.h"#include "portab.h"#include "global.h"#include "decoder.h"#include "bitstream/bitstream.h"#include "bitstream/mbcoding.h"#include "quant/quant.h"#include "quant/quant_matrix.h"#include "dct/idct.h"#include "dct/fdct.h"#include "utils/mem_transfer.h"#include "image/interpolate8x8.h"#include "image/font.h"#include "image/qpel.h"#include "bitstream/mbcoding.h"#include "prediction/mbprediction.h"#include "utils/timer.h"#include "utils/emms.h"#include "motion/motion.h"#include "motion/gmc.h"#include "image/image.h"#include "image/colorspace.h"#include "image/postprocessing.h"#include "utils/mem_align.h"static intdecoder_resize(DECODER * dec){ /* free existing */ image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); image_destroy(&dec->qtmp, dec->edged_width, dec->edged_height); image_destroy(&dec->gmc, dec->edged_width, dec->edged_height); if (dec->last_mbs) xvid_free(dec->last_mbs); if (dec->mbs) xvid_free(dec->mbs); if (dec->qscale) xvid_free(dec->qscale); /* realloc */ dec->mb_width = (dec->width + 15) / 16; dec->mb_height = (dec->height + 15) / 16; dec->edged_width = 16 * dec->mb_width + 2 * EDGE_SIZE; dec->edged_height = 16 * dec->mb_height + 2 * EDGE_SIZE; if (image_create(&dec->cur, dec->edged_width, dec->edged_height)) { xvid_free(dec); return XVID_ERR_MEMORY; } if (image_create(&dec->refn[0], dec->edged_width, dec->edged_height)) { image_destroy(&dec->cur, dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } /* Support B-frame to reference last 2 frame */ if (image_create(&dec->refn[1], dec->edged_width, dec->edged_height)) { image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } if (image_create(&dec->tmp, dec->edged_width, dec->edged_height)) { image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } if (image_create(&dec->qtmp, dec->edged_width, dec->edged_height)) { image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } if (image_create(&dec->gmc, dec->edged_width, dec->edged_height)) { image_destroy(&dec->qtmp, dec->edged_width, dec->edged_height); image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } dec->mbs = xvid_malloc(sizeof(MACROBLOCK) * dec->mb_width * dec->mb_height, CACHE_LINE); if (dec->mbs == NULL) { image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); image_destroy(&dec->qtmp, dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } memset(dec->mbs, 0, sizeof(MACROBLOCK) * dec->mb_width * dec->mb_height); /* For skip MB flag */ dec->last_mbs = xvid_malloc(sizeof(MACROBLOCK) * dec->mb_width * dec->mb_height, CACHE_LINE); if (dec->last_mbs == NULL) { xvid_free(dec->mbs); image_destroy(&dec->cur, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); image_destroy(&dec->qtmp, dec->edged_width, dec->edged_height); xvid_free(dec); return XVID_ERR_MEMORY; } memset(dec->last_mbs, 0, sizeof(MACROBLOCK) * dec->mb_width * dec->mb_height); /* nothing happens if that fails */ dec->qscale = xvid_malloc(sizeof(int) * dec->mb_width * dec->mb_height, CACHE_LINE); if (dec->qscale) memset(dec->qscale, 0, sizeof(int) * dec->mb_width * dec->mb_height); return 0;}intdecoder_create(xvid_dec_create_t * create){ DECODER *dec; if (XVID_VERSION_MAJOR(create->version) != 1) /* v1.x.x */ return XVID_ERR_VERSION; dec = xvid_malloc(sizeof(DECODER), CACHE_LINE); if (dec == NULL) { return XVID_ERR_MEMORY; } memset(dec, 0, sizeof(DECODER)); dec->mpeg_quant_matrices = xvid_malloc(sizeof(uint16_t) * 64 * 8, CACHE_LINE); if (dec->mpeg_quant_matrices == NULL) { xvid_free(dec); return XVID_ERR_MEMORY; } create->handle = dec; dec->width = create->width; dec->height = create->height; image_null(&dec->cur); image_null(&dec->refn[0]); image_null(&dec->refn[1]); image_null(&dec->tmp); image_null(&dec->qtmp); /* image based GMC */ image_null(&dec->gmc); dec->mbs = NULL; dec->last_mbs = NULL; dec->qscale = NULL; init_timer(); init_postproc(&dec->postproc); init_mpeg_matrix(dec->mpeg_quant_matrices); /* For B-frame support (used to save reference frame's time */ dec->frames = 0; dec->time = dec->time_base = dec->last_time_base = 0; dec->low_delay = 0; dec->packed_mode = 0; dec->time_inc_resolution = 1; /* until VOL header says otherwise */ dec->fixed_dimensions = (dec->width > 0 && dec->height > 0); if (dec->fixed_dimensions) return decoder_resize(dec); else return 0;}intdecoder_destroy(DECODER * dec){ xvid_free(dec->last_mbs); xvid_free(dec->mbs); xvid_free(dec->qscale); /* image based GMC */ image_destroy(&dec->gmc, dec->edged_width, dec->edged_height); image_destroy(&dec->refn[0], dec->edged_width, dec->edged_height); image_destroy(&dec->refn[1], dec->edged_width, dec->edged_height); image_destroy(&dec->tmp, dec->edged_width, dec->edged_height); image_destroy(&dec->qtmp, dec->edged_width, dec->edged_height); image_destroy(&dec->cur, dec->edged_width, dec->edged_height); xvid_free(dec->mpeg_quant_matrices); xvid_free(dec); write_timer(); return 0;}static const int32_t dquant_table[4] = { -1, -2, 1, 2};/* decode an intra macroblock */static voiddecoder_mbintra(DECODER * dec, MACROBLOCK * pMB, const uint32_t x_pos, const uint32_t y_pos, const uint32_t acpred_flag, const uint32_t cbp, Bitstream * bs, const uint32_t quant, const uint32_t intra_dc_threshold, const unsigned int bound){ DECLARE_ALIGNED_MATRIX(block, 6, 64, int16_t, CACHE_LINE); DECLARE_ALIGNED_MATRIX(data, 6, 64, int16_t, CACHE_LINE); uint32_t stride = dec->edged_width; uint32_t stride2 = stride / 2; uint32_t next_block = stride * 8; uint32_t i; uint32_t iQuant = pMB->quant; uint8_t *pY_Cur, *pU_Cur, *pV_Cur; pY_Cur = dec->cur.y + (y_pos << 4) * stride + (x_pos << 4); pU_Cur = dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3); pV_Cur = dec->cur.v + (y_pos << 3) * stride2 + (x_pos << 3); memset(block, 0, 6 * 64 * sizeof(int16_t)); /* clear */ for (i = 0; i < 6; i++) { uint32_t iDcScaler = get_dc_scaler(iQuant, i < 4); int16_t predictors[8]; int start_coeff; start_timer(); predict_acdc(dec->mbs, x_pos, y_pos, dec->mb_width, i, &block[i * 64], iQuant, iDcScaler, predictors, bound); if (!acpred_flag) { pMB->acpred_directions[i] = 0; } stop_prediction_timer(); if (quant < intra_dc_threshold) { int dc_size; int dc_dif; dc_size = i < 4 ? get_dc_size_lum(bs) : get_dc_size_chrom(bs); dc_dif = dc_size ? get_dc_dif(bs, dc_size) : 0; if (dc_size > 8) { BitstreamSkip(bs, 1); /* marker */ } block[i * 64 + 0] = dc_dif; start_coeff = 1; DPRINTF(XVID_DEBUG_COEFF,"block[0] %i\n", dc_dif); } else { start_coeff = 0; } start_timer(); if (cbp & (1 << (5 - i))) /* coded */ { int direction = dec->alternate_vertical_scan ? 2 : pMB->acpred_directions[i]; get_intra_block(bs, &block[i * 64], direction, start_coeff); } stop_coding_timer(); start_timer(); add_acdc(pMB, i, &block[i * 64], iDcScaler, predictors, dec->bs_version); stop_prediction_timer(); start_timer(); if (dec->quant_type == 0) { dequant_h263_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler, dec->mpeg_quant_matrices); } else { dequant_mpeg_intra(&data[i * 64], &block[i * 64], iQuant, iDcScaler, dec->mpeg_quant_matrices); } stop_iquant_timer(); start_timer(); idct(&data[i * 64]); stop_idct_timer(); } if (dec->interlacing && pMB->field_dct) { next_block = stride; stride *= 2; } start_timer(); transfer_16to8copy(pY_Cur, &data[0 * 64], stride); transfer_16to8copy(pY_Cur + 8, &data[1 * 64], stride); transfer_16to8copy(pY_Cur + next_block, &data[2 * 64], stride); transfer_16to8copy(pY_Cur + 8 + next_block, &data[3 * 64], stride); transfer_16to8copy(pU_Cur, &data[4 * 64], stride2); transfer_16to8copy(pV_Cur, &data[5 * 64], stride2); stop_transfer_timer();}static voiddecoder_mb_decode(DECODER * dec, const uint32_t cbp, Bitstream * bs, uint8_t * pY_Cur, uint8_t * pU_Cur, uint8_t * pV_Cur, const MACROBLOCK * pMB){ DECLARE_ALIGNED_MATRIX(data, 1, 64, int16_t, CACHE_LINE); int stride = dec->edged_width; int next_block = stride * 8; int i; const uint32_t iQuant = pMB->quant; const int direction = dec->alternate_vertical_scan ? 2 : 0; typedef void (*get_inter_block_function_t)( Bitstream * bs, int16_t * block, int direction, const int quant, const uint16_t *matrix); typedef void (*add_residual_function_t)( uint8_t *predicted_block, const int16_t *residual, int stride); const get_inter_block_function_t get_inter_block = (dec->quant_type == 0) ? (get_inter_block_function_t)get_inter_block_h263 : (get_inter_block_function_t)get_inter_block_mpeg; uint8_t *dst[6]; int strides[6]; if (dec->interlacing && pMB->field_dct) { next_block = stride; stride *= 2; } dst[0] = pY_Cur; dst[2] = pY_Cur + next_block; dst[1] = dst[0] + 8; dst[3] = dst[2] + 8; dst[4] = pU_Cur; dst[5] = pV_Cur; strides[0] = strides[1] = strides[2] = strides[3] = stride; strides[4] = stride/2; strides[5] = stride/2; for (i = 0; i < 6; i++) { /* Process only coded blocks */ if (cbp & (1 << (5 - i))) { /* Clear the block */ memset(&data[0], 0, 64*sizeof(int16_t)); /* Decode coeffs and dequantize on the fly */ start_timer(); get_inter_block(bs, &data[0], direction, iQuant, get_inter_matrix(dec->mpeg_quant_matrices)); stop_coding_timer(); /* iDCT */ start_timer(); idct(&data[0]); stop_idct_timer(); /* Add this residual to the predicted block */ start_timer(); transfer_16to8add(dst[i], &data[0], strides[i]); stop_transfer_timer(); } }}static void __inlinevalidate_vector(VECTOR * mv, unsigned int x_pos, unsigned int y_pos, const DECODER * dec){ /* clip a vector to valid range prevents crashes if bitstream is broken */ int shift = 5 + dec->quarterpel; int xborder_high = (int)(dec->mb_width - x_pos) << shift; int xborder_low = (-(int)x_pos-1) << shift; int yborder_high = (int)(dec->mb_height - y_pos) << shift; int yborder_low = (-(int)y_pos-1) << shift;#define CHECK_MV(mv) \ do { \ if ((mv).x > xborder_high) { \ DPRINTF(XVID_DEBUG_MV, "mv.x > max -- %d > %d, MB %d, %d", (mv).x, xborder_high, x_pos, y_pos); \ (mv).x = xborder_high; \ } else if ((mv).x < xborder_low) { \ DPRINTF(XVID_DEBUG_MV, "mv.x < min -- %d < %d, MB %d, %d", (mv).x, xborder_low, x_pos, y_pos); \ (mv).x = xborder_low; \ } \ if ((mv).y > yborder_high) { \ DPRINTF(XVID_DEBUG_MV, "mv.y > max -- %d > %d, MB %d, %d", (mv).y, yborder_high, x_pos, y_pos); \ (mv).y = yborder_high; \ } else if ((mv).y < yborder_low) { \ DPRINTF(XVID_DEBUG_MV, "mv.y < min -- %d < %d, MB %d, %d", (mv).y, yborder_low, x_pos, y_pos); \ (mv).y = yborder_low; \ } \ } while (0) CHECK_MV(mv[0]); CHECK_MV(mv[1]); CHECK_MV(mv[2]); CHECK_MV(mv[3]);}/* decode an inter macroblock */static voiddecoder_mbinter(DECODER * dec, const MACROBLOCK * pMB, const uint32_t x_pos, const uint32_t y_pos, const uint32_t cbp, Bitstream * bs, const uint32_t rounding, const int ref){ uint32_t stride = dec->edged_width; uint32_t stride2 = stride / 2; uint32_t i; uint8_t *pY_Cur, *pU_Cur, *pV_Cur; int uv_dx, uv_dy; VECTOR mv[4]; /* local copy of mvs */ pY_Cur = dec->cur.y + (y_pos << 4) * stride + (x_pos << 4); pU_Cur = dec->cur.u + (y_pos << 3) * stride2 + (x_pos << 3); pV_Cur = dec->cur.v + (y_pos << 3) * stride2 + (x_pos << 3); for (i = 0; i < 4; i++) mv[i] = pMB->mvs[i]; validate_vector(mv, x_pos, y_pos, dec); start_timer(); if (pMB->mode != MODE_INTER4V) { /* INTER, INTER_Q, NOT_CODED, FORWARD, BACKWARD */ uv_dx = mv[0].x; uv_dy = mv[0].y; if (dec->quarterpel) { uv_dx /= 2; uv_dy /= 2; } uv_dx = (uv_dx >> 1) + roundtab_79[uv_dx & 0x3];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -