📄 msmpeg4.c
字号:
/* * MSMPEG4 backend for ffmpeg encoder and decoder * Copyright (c) 2001 Fabrice Bellard. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * msmpeg4v1 & v2 stuff by Michael Niedermayer <michaelni@gmx.at> *//** * @file msmpeg4.c * MSMPEG4 backend for ffmpeg encoder and decoder. */#include "avcodec.h"#include "dsputil.h"#include "mpegvideo.h"/* * You can also call this codec : MPEG4 with a twist ! * * TODO: * - (encoding) select best mv table (two choices) * - (encoding) select best vlc/dc table *///#define DEBUG#define DC_VLC_BITS 9#define CBPY_VLC_BITS 6#define INTER_INTRA_VLC_BITS 3#define V1_INTRA_CBPC_VLC_BITS 6#define V1_INTER_CBPC_VLC_BITS 6#define V2_INTRA_CBPC_VLC_BITS 3#define V2_MB_TYPE_VLC_BITS 7#define MV_VLC_BITS 9#define V2_MV_VLC_BITS 9#define TEX_VLC_BITS 9#define MB_NON_INTRA_VLC_BITS 9#define MB_INTRA_VLC_BITS 9#define II_BITRATE 128*1024#define MBAC_BITRATE 50*1024#define DEFAULT_INTER_INDEX 3static uint32_t v2_dc_lum_table[512][2];static uint32_t v2_dc_chroma_table[512][2];static inline void msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n);static inline int msmpeg4_decode_block(MpegEncContext * s, DCTELEM * block, int n, int coded, const uint8_t *scantable);static int msmpeg4_decode_dc(MpegEncContext * s, int n, int *dir_ptr);static int msmpeg4_decode_motion(MpegEncContext * s, int *mx_ptr, int *my_ptr);static void msmpeg4v2_encode_motion(MpegEncContext * s, int val);static void init_h263_dc_for_msmpeg4(void);static inline void msmpeg4_memsetw(short *tab, int val, int n);#ifdef CONFIG_ENCODERSstatic int get_size_of_code(MpegEncContext * s, RLTable *rl, int last, int run, int level, int intra);#endif //CONFIG_ENCODERSstatic int msmpeg4v12_decode_mb(MpegEncContext *s, DCTELEM block[6][64]);static int msmpeg4v34_decode_mb(MpegEncContext *s, DCTELEM block[6][64]);static int wmv2_decode_mb(MpegEncContext *s, DCTELEM block[6][64]);#ifdef DEBUGint intra_count = 0;int frame_count = 0;#endif#include "msmpeg4data.h"#ifdef CONFIG_ENCODERS //strangely gcc includes this even if its not referencesstatic uint8_t rl_length[NB_RL_TABLES][MAX_LEVEL+1][MAX_RUN+1][2];#endif //CONFIG_ENCODERS#ifdef STATSconst char *st_names[ST_NB] = { "unknown", "dc", "intra_ac", "inter_ac", "intra_mb", "inter_mb", "mv",};int st_current_index = 0;unsigned int st_bit_counts[ST_NB];unsigned int st_out_bit_counts[ST_NB];#define set_stat(var) st_current_index = var;void print_stats(void){ unsigned int total; int i; printf("Input:\n"); total = 0; for(i=0;i<ST_NB;i++) total += st_bit_counts[i]; if (total == 0) total = 1; for(i=0;i<ST_NB;i++) { printf("%-10s : %10.1f %5.1f%%\n", st_names[i], (double)st_bit_counts[i] / 8.0, (double)st_bit_counts[i] * 100.0 / total); } printf("%-10s : %10.1f %5.1f%%\n", "total", (double)total / 8.0, 100.0); printf("Output:\n"); total = 0; for(i=0;i<ST_NB;i++) total += st_out_bit_counts[i]; if (total == 0) total = 1; for(i=0;i<ST_NB;i++) { printf("%-10s : %10.1f %5.1f%%\n", st_names[i], (double)st_out_bit_counts[i] / 8.0, (double)st_out_bit_counts[i] * 100.0 / total); } printf("%-10s : %10.1f %5.1f%%\n", "total", (double)total / 8.0, 100.0);}#else#define set_stat(var)#endifstatic void common_init(MpegEncContext * s){ static int inited=0; switch(s->msmpeg4_version){ case 1: case 2: s->y_dc_scale_table= s->c_dc_scale_table= ff_mpeg1_dc_scale_table; break; case 3: if(s->workaround_bugs){ s->y_dc_scale_table= old_ff_y_dc_scale_table; s->c_dc_scale_table= old_ff_c_dc_scale_table; } else{ s->y_dc_scale_table= ff_mpeg4_y_dc_scale_table; s->c_dc_scale_table= ff_mpeg4_c_dc_scale_table; } break; case 4: case 5: s->y_dc_scale_table= wmv1_y_dc_scale_table; s->c_dc_scale_table= wmv1_c_dc_scale_table; break; } if(s->msmpeg4_version>=4){ ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable , wmv1_scantable[1]); ff_init_scantable(s->dsp.idct_permutation, &s->intra_h_scantable, wmv1_scantable[2]); ff_init_scantable(s->dsp.idct_permutation, &s->intra_v_scantable, wmv1_scantable[3]); ff_init_scantable(s->dsp.idct_permutation, &s->inter_scantable , wmv1_scantable[0]); } //Note the default tables are set in common_init in mpegvideo.c if(!inited){ inited=1; init_h263_dc_for_msmpeg4(); }}#ifdef CONFIG_ENCODERS/* build the table which associate a (x,y) motion vector to a vlc */static void init_mv_table(MVTable *tab){ int i, x, y; tab->table_mv_index = av_malloc(sizeof(uint16_t) * 4096); /* mark all entries as not used */ for(i=0;i<4096;i++) tab->table_mv_index[i] = tab->n; for(i=0;i<tab->n;i++) { x = tab->table_mvx[i]; y = tab->table_mvy[i]; tab->table_mv_index[(x << 6) | y] = i; }}static void code012(PutBitContext *pb, int n){ if (n == 0) { put_bits(pb, 1, 0); } else { put_bits(pb, 1, 1); put_bits(pb, 1, (n >= 2)); }}void ff_msmpeg4_encode_init(MpegEncContext *s){ static int init_done=0; int i; common_init(s); if(s->msmpeg4_version>=4){ s->min_qcoeff= -255; s->max_qcoeff= 255; } if (!init_done) { /* init various encoding tables */ init_done = 1; init_mv_table(&mv_tables[0]); init_mv_table(&mv_tables[1]); for(i=0;i<NB_RL_TABLES;i++) init_rl(&rl_table[i]); for(i=0; i<NB_RL_TABLES; i++){ int level; for(level=0; level<=MAX_LEVEL; level++){ int run; for(run=0; run<=MAX_RUN; run++){ int last; for(last=0; last<2; last++){ rl_length[i][level][run][last]= get_size_of_code(s, &rl_table[ i], last, run, level, 0); } } } } }}static int get_size_of_code(MpegEncContext * s, RLTable *rl, int last, int run, int level, int intra){ int size=0; int code; int run_diff= intra ? 0 : 1; code = get_rl_index(rl, last, run, level); size+= rl->table_vlc[code][1]; if (code == rl->n) { int level1, run1; level1 = level - rl->max_level[last][run]; if (level1 < 1) goto esc2; code = get_rl_index(rl, last, run, level1); if (code == rl->n) { esc2: size++; if (level > MAX_LEVEL) goto esc3; run1 = run - rl->max_run[last][level] - run_diff; if (run1 < 0) goto esc3; code = get_rl_index(rl, last, run1, level); if (code == rl->n) { esc3: /* third escape */ size+=1+1+6+8; } else { /* second escape */ size+= 1+1+ rl->table_vlc[code][1]; } } else { /* first escape */ size+= 1+1+ rl->table_vlc[code][1]; } } else { size++; } return size;}static void find_best_tables(MpegEncContext * s){ int i; int best =-1, best_size =9999999; int chroma_best=-1, best_chroma_size=9999999; for(i=0; i<3; i++){ int level; int chroma_size=0; int size=0; if(i>0){// ;) size++; chroma_size++; } for(level=0; level<=MAX_LEVEL; level++){ int run; for(run=0; run<=MAX_RUN; run++){ int last; const int last_size= size + chroma_size; for(last=0; last<2; last++){ int inter_count = s->ac_stats[0][0][level][run][last] + s->ac_stats[0][1][level][run][last]; int intra_luma_count = s->ac_stats[1][0][level][run][last]; int intra_chroma_count= s->ac_stats[1][1][level][run][last]; if(s->pict_type==I_TYPE){ size += intra_luma_count *rl_length[i ][level][run][last]; chroma_size+= intra_chroma_count*rl_length[i+3][level][run][last]; }else{ size+= intra_luma_count *rl_length[i ][level][run][last] +intra_chroma_count*rl_length[i+3][level][run][last] +inter_count *rl_length[i+3][level][run][last]; } } if(last_size == size+chroma_size) break; } } if(size<best_size){ best_size= size; best= i; } if(chroma_size<best_chroma_size){ best_chroma_size= chroma_size; chroma_best= i; } }// printf("type:%d, best:%d, qp:%d, var:%d, mcvar:%d, size:%d //\n", // s->pict_type, best, s->qscale, s->mb_var_sum, s->mc_mb_var_sum, best_size); if(s->pict_type==P_TYPE) chroma_best= best; memset(s->ac_stats, 0, sizeof(int)*(MAX_LEVEL+1)*(MAX_RUN+1)*2*2*2); s->rl_table_index = best; s->rl_chroma_table_index= chroma_best; if(s->pict_type != s->last_non_b_pict_type){ s->rl_table_index= 2; if(s->pict_type==I_TYPE) s->rl_chroma_table_index= 1; else s->rl_chroma_table_index= 2; }}/* write MSMPEG4 compatible frame header */void msmpeg4_encode_picture_header(MpegEncContext * s, int picture_number){ find_best_tables(s); align_put_bits(&s->pb); put_bits(&s->pb, 2, s->pict_type - 1); put_bits(&s->pb, 5, s->qscale); if(s->msmpeg4_version<=2){ s->rl_table_index = 2; s->rl_chroma_table_index = 2; } s->dc_table_index = 1; s->mv_table_index = 1; /* only if P frame */ s->use_skip_mb_code = 1; /* only if P frame */ s->per_mb_rl_table = 0; if(s->msmpeg4_version==4) s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE && s->pict_type==P_TYPE);//printf("%d %d %d %d %d\n", s->pict_type, s->bit_rate, s->inter_intra_pred, s->width, s->height); if (s->pict_type == I_TYPE) { s->slice_height= s->mb_height/1; put_bits(&s->pb, 5, 0x16 + s->mb_height/s->slice_height); if(s->msmpeg4_version==4){ msmpeg4_encode_ext_header(s); if(s->bit_rate>MBAC_BITRATE) put_bits(&s->pb, 1, s->per_mb_rl_table); } if(s->msmpeg4_version>2){ if(!s->per_mb_rl_table){ code012(&s->pb, s->rl_chroma_table_index); code012(&s->pb, s->rl_table_index); } put_bits(&s->pb, 1, s->dc_table_index); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -