*
* 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"
-//#define PRINT_MB
/*
* You can also call this codec : MPEG4 with a twist !
#define II_BITRATE 128*1024
#define MBAC_BITRATE 50*1024
-static UINT32 v2_dc_lum_table[512][2];
-static UINT32 v2_dc_chroma_table[512][2];
+#define DEFAULT_INTER_INDEX 3
+
+static 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);
+ 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_ENCODERS
static int get_size_of_code(MpegEncContext * s, RLTable *rl, int last, int run, int level, int intra);
-
-
-extern UINT32 inverse[256];
+#endif //CONFIG_ENCODERS
+static 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 DEBUG
#include "msmpeg4data.h"
-static int rl_length[2][NB_RL_TABLES][MAX_LEVEL+1][MAX_RUN+1][2];
+#ifdef CONFIG_ENCODERS //strangely gcc includes this even if its not references
+static uint8_t rl_length[NB_RL_TABLES][MAX_LEVEL+1][MAX_RUN+1][2];
+#endif //CONFIG_ENCODERS
#ifdef STATS
}
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){
- int i;
- ff_init_scantable(s, &s->intra_scantable , wmv1_scantable[1]);
- ff_init_scantable(s, &s->intra_h_scantable, wmv1_scantable[2]);
- ff_init_scantable(s, &s->intra_v_scantable, wmv1_scantable[3]);
- ff_init_scantable(s, &s->inter_scantable , wmv1_scantable[0]);
+ 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){
- int i;
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) * 4096);
+ 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(run=0; run<=MAX_RUN; run++){
int last;
for(last=0; last<2; last++){
- rl_length[0][i][level][run][last]= get_size_of_code(s, &rl_table[ i], last, run, level,0);
- rl_length[1][i][level][run][last]= get_size_of_code(s, &rl_table[ i], last, run, level,1);
+ rl_length[i][level][run][last]= get_size_of_code(s, &rl_table[ i], last, run, level, 0);
}
}
}
int intra_chroma_count= s->ac_stats[1][1][level][run][last];
if(s->pict_type==I_TYPE){
- size += intra_luma_count *rl_length[1][i ][level][run][last];
- chroma_size+= intra_chroma_count*rl_length[1][i+3][level][run][last];
+ 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[1][i ][level][run][last]
- +intra_chroma_count*rl_length[1][i+3][level][run][last]
- +inter_count *rl_length[0][i+3][level][run][last];
+ 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;
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;
- s->inter_intra_pred= (s->width*s->height < 320*240 && s->bit_rate<=II_BITRATE && s->pict_type==P_TYPE);
+ 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->no_rounding = 1;
s->slice_height= s->mb_height/1;
put_bits(&s->pb, 5, 0x16 + s->mb_height/s->slice_height);
put_bits(&s->pb, 1, s->mv_table_index);
}
-
- if(s->flipflop_rounding){
- s->no_rounding ^= 1;
- }else{
- s->no_rounding = 0;
- }
}
s->esc3_level_length= 0;
void msmpeg4_encode_ext_header(MpegEncContext * s)
{
- put_bits(&s->pb, 5, s->frame_rate / FRAME_RATE_BASE); //yes 29.97 -> 29
+ put_bits(&s->pb, 5, s->avctx->frame_rate / s->avctx->frame_rate_base); //yes 29.97 -> 29
- put_bits(&s->pb, 11, MIN(s->bit_rate/1024, 2047));
+ put_bits(&s->pb, 11, FFMIN(s->bit_rate/1024, 2047));
- if(s->msmpeg4_version<3)
- s->flipflop_rounding=0;
- else{
- s->flipflop_rounding=1;
+ if(s->msmpeg4_version>=3)
put_bits(&s->pb, 1, s->flipflop_rounding);
- }
+ else
+ assert(s->flipflop_rounding==0);
}
+#endif //CONFIG_ENCODERS
+
/* predict coded block */
-static inline int coded_block_pred(MpegEncContext * s, int n, UINT8 **coded_block_ptr)
+static inline int coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr)
{
int xy, wrap, pred, a, b, c;
return pred;
}
+#ifdef CONFIG_ENCODERS
+
static void msmpeg4_encode_motion(MpegEncContext * s,
int mx, int my)
{
static inline void handle_slices(MpegEncContext *s){
if (s->mb_x == 0) {
if (s->slice_height && (s->mb_y % s->slice_height) == 0) {
- if(s->msmpeg4_version != 4){
- int wrap;
- /* reset DC pred (set previous line to 1024) */
- wrap = 2 * s->mb_width + 2;
- msmpeg4_memsetw(&s->dc_val[0][(1) + (2 * s->mb_y) * wrap],
- 1024, 2 * s->mb_width);
- wrap = s->mb_width + 2;
- msmpeg4_memsetw(&s->dc_val[1][(1) + (s->mb_y) * wrap],
- 1024, s->mb_width);
- msmpeg4_memsetw(&s->dc_val[2][(1) + (s->mb_y) * wrap],
- 1024, s->mb_width);
-
- /* reset AC pred (set previous line to 0) */
- wrap = s->mb_width * 2 + 2;
- msmpeg4_memsetw(s->ac_val[0][0] + (1 + (2 * s->mb_y) * wrap)*16,
- 0, 2 * s->mb_width*16);
- wrap = s->mb_width + 2;
- msmpeg4_memsetw(s->ac_val[1][0] + (1 + (s->mb_y) * wrap)*16,
- 0, s->mb_width*16);
- msmpeg4_memsetw(s->ac_val[2][0] + (1 + (s->mb_y) * wrap)*16,
- 0, s->mb_width*16);
+ if(s->msmpeg4_version < 4){
+ ff_mpeg4_clean_buffers(s);
}
s->first_slice_line = 1;
} else {
{
int cbp, coded_cbp, i;
int pred_x, pred_y;
- UINT8 *coded_block;
+ uint8_t *coded_block;
handle_slices(s);
if (s->use_skip_mb_code && (cbp | motion_x | motion_y) == 0) {
/* skip macroblock */
put_bits(&s->pb, 1, 1);
+ s->last_bits++;
+ s->misc_bits++;
+ s->skip_count++;
+
return;
}
if (s->use_skip_mb_code)
put_bits(&s->pb,
cbpy_tab[coded_cbp>>2][1],
cbpy_tab[coded_cbp>>2][0]);
-
+
+ s->misc_bits += get_bits_diff(s);
+
h263_pred_motion(s, 0, &pred_x, &pred_y);
msmpeg4v2_encode_motion(s, motion_x - pred_x);
msmpeg4v2_encode_motion(s, motion_y - pred_y);
table_mb_non_intra[cbp + 64][1],
table_mb_non_intra[cbp + 64][0]);
+ s->misc_bits += get_bits_diff(s);
+
/* motion vector */
h263_pred_motion(s, 0, &pred_x, &pred_y);
msmpeg4_encode_motion(s, motion_x - pred_x,
motion_y - pred_y);
}
+
+ s->mv_bits += get_bits_diff(s);
+
+ for (i = 0; i < 6; i++) {
+ msmpeg4_encode_block(s, block[i], i);
+ }
+ s->p_tex_bits += get_bits_diff(s);
} else {
/* compute cbp */
cbp = 0;
put_bits(&s->pb, table_inter_intra[s->h263_aic_dir][1], table_inter_intra[s->h263_aic_dir][0]);
}
}
- }
+ s->misc_bits += get_bits_diff(s);
- for (i = 0; i < 6; i++) {
- msmpeg4_encode_block(s, block[i], i);
+ for (i = 0; i < 6; i++) {
+ msmpeg4_encode_block(s, block[i], i);
+ }
+ s->i_tex_bits += get_bits_diff(s);
+ s->i_count++;
}
}
+#endif //CONFIG_ENCODERS
+
/* old ffmpeg msmpeg4v3 mode */
-void ff_old_msmpeg4_dc_scale(MpegEncContext * s)
+static void ff_old_msmpeg4_dc_scale(MpegEncContext * s)
{
if (s->qscale < 5){
s->y_dc_scale = 8;
}
static inline int msmpeg4v1_pred_dc(MpegEncContext * s, int n,
- INT32 **dc_val_ptr)
+ int32_t **dc_val_ptr)
{
int i;
sum+=src[x + y*stride];
}
}
- return (sum + (scale>>1))/scale;
+ return FASTDIV((sum + (scale>>1)), scale);
}
/* dir = 0: left, dir = 1: top prediction */
static inline int msmpeg4_pred_dc(MpegEncContext * s, int n,
- UINT16 **dc_val_ptr, int *dir_ptr)
+ uint16_t **dc_val_ptr, int *dir_ptr)
{
int a, b, c, wrap, pred, scale;
- INT16 *dc_val;
+ int16_t *dc_val;
/* find prediction */
if (n < 4) {
a = dc_val[ - 1];
b = dc_val[ - 1 - wrap];
c = dc_val[ - wrap];
+
+ if(s->first_slice_line && (n&2)==0 && s->msmpeg4_version<4){
+ b=c=1024;
+ }
/* XXX: the following solution consumes divisions, but it does not
necessitate to modify mpegvideo.c. The problem comes from the
b = (b + (8 >> 1)) / 8;
c = (c + (8 >> 1)) / 8;
} else {
- a = (a + (scale >> 1)) / scale;
- b = (b + (scale >> 1)) / scale;
- c = (c + (scale >> 1)) / scale;
+ a = FASTDIV((a + (scale >> 1)), scale);
+ b = FASTDIV((b + (scale >> 1)), scale);
+ c = FASTDIV((c + (scale >> 1)), scale);
}
#endif
/* XXX: WARNING: they did not choose the same test as MPEG4. This
}else{
if(n<4){
wrap= s->linesize;
- dest= s->current_picture[0] + (((n>>1) + 2*s->mb_y) * 8* wrap ) + ((n&1) + 2*s->mb_x) * 8;
+ dest= s->current_picture.data[0] + (((n>>1) + 2*s->mb_y) * 8* wrap ) + ((n&1) + 2*s->mb_x) * 8;
}else{
wrap= s->uvlinesize;
- dest= s->current_picture[n-3] + (s->mb_y * 8 * wrap) + s->mb_x * 8;
+ dest= s->current_picture.data[n-3] + (s->mb_y * 8 * wrap) + s->mb_x * 8;
}
if(s->mb_x==0) a= (1024 + (scale>>1))/scale;
else a= get_dc(dest-8, wrap, scale*8);
int pred;
if(s->msmpeg4_version==1){
- INT32 *dc_val;
+ int32_t *dc_val;
pred = msmpeg4v1_pred_dc(s, n, &dc_val);
/* update predictor */
*dc_val= level;
}else{
- UINT16 *dc_val;
+ uint16_t *dc_val;
pred = msmpeg4_pred_dc(s, n, &dc_val, dir_ptr);
/* update predictor */
int last_non_zero, sign, slevel;
int code, run_diff, dc_pred_dir;
const RLTable *rl;
- const UINT8 *scantable;
+ const uint8_t *scantable;
if (s->mb_intra) {
set_stat(ST_DC);
}
/* recalculate block_last_index for M$ wmv1 */
- if(s->msmpeg4_version==4 && s->block_last_index[n]>0){
+ if(s->msmpeg4_version>=4 && s->block_last_index[n]>0){
for(last_index=63; last_index>=0; last_index--){
if(block[scantable[last_index]]) break;
}
+ s->block_last_index[n]= last_index;
}else
last_index = s->block_last_index[n];
/* AC coefs */
/* third escape */
put_bits(&s->pb, 1, 0);
put_bits(&s->pb, 1, last);
- if(s->msmpeg4_version==4){
+ if(s->msmpeg4_version>=4){
if(s->esc3_level_length==0){
s->esc3_level_length=8;
s->esc3_run_length= 6;
/****************************************/
/* decoding stuff */
-static VLC mb_non_intra_vlc;
+static VLC mb_non_intra_vlc[4];
static VLC mb_intra_vlc;
static VLC dc_lum_vlc[2];
static VLC dc_chroma_vlc[2];
&mvtab[0][1], 2, 1,
&mvtab[0][0], 2, 1);
- init_vlc(&mb_non_intra_vlc, MB_NON_INTRA_VLC_BITS, 128,
- &table_mb_non_intra[0][1], 8, 4,
- &table_mb_non_intra[0][0], 8, 4);
+ for(i=0; i<4; i++){
+ init_vlc(&mb_non_intra_vlc[i], MB_NON_INTRA_VLC_BITS, 128,
+ &wmv2_inter_table[i][0][1], 8, 4,
+ &wmv2_inter_table[i][0][0], 8, 4); //FIXME name?
+ }
+
init_vlc(&mb_intra_vlc, MB_INTRA_VLC_BITS, 64,
&table_mb_intra[0][1], 4, 2,
&table_mb_intra[0][0], 4, 2);
&table_inter_intra[0][1], 2, 1,
&table_inter_intra[0][0], 2, 1);
}
+
+ switch(s->msmpeg4_version){
+ case 1:
+ case 2:
+ s->decode_mb= msmpeg4v12_decode_mb;
+ break;
+ case 3:
+ case 4:
+ s->decode_mb= msmpeg4v34_decode_mb;
+ break;
+ case 5:
+ s->decode_mb= wmv2_decode_mb;
+ break;
+ }
+
+ s->slice_height= s->mb_height; //to avoid 1/0 if the first frame isnt a keyframe
+
return 0;
}
#if 0
{
int i;
-for(i=0; i<s->gb.size*8; i++)
+for(i=0; i<s->gb.size_in_bits; i++)
printf("%d", get_bits1(&s->gb));
// get_bits1(&s->gb);
printf("END\n");
}
#endif
s->qscale = get_bits(&s->gb, 5);
+ if(s->qscale==0){
+ fprintf(stderr, "invalid qscale\n");
+ return -1;
+ }
if (s->pict_type == I_TYPE) {
code = get_bits(&s->gb, 5);
s->no_rounding = 0;
}
}
+//printf("%d %d %d %d %d\n", s->pict_type, s->bit_rate, s->inter_intra_pred, s->width, s->height);
s->esc3_level_length= 0;
s->esc3_run_length= 0;
return pred;
sign = get_bits1(&s->gb);
shift = f_code - 1;
- val = (code - 1) << shift;
- if (shift > 0)
+ val = code;
+ if (shift) {
+ val = (val - 1) << shift;
val |= get_bits(&s->gb, shift);
- val++;
+ val++;
+ }
if (sign)
val = -val;
return val;
}
-
-static int msmpeg4v12_decode_mb(MpegEncContext *s,
- DCTELEM block[6][64])
+static int msmpeg4v12_decode_mb(MpegEncContext *s, DCTELEM block[6][64])
{
int cbp, code, i;
+
if (s->pict_type == P_TYPE) {
if (s->use_skip_mb_code) {
if (get_bits1(&s->gb)) {
}
for (i = 0; i < 6; i++) {
- if (msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1) < 0)
+ if (msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0)
{
fprintf(stderr,"\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i);
return -1;
return 0;
}
-int msmpeg4_decode_mb(MpegEncContext *s,
- DCTELEM block[6][64])
+static int msmpeg4v34_decode_mb(MpegEncContext *s, DCTELEM block[6][64])
{
int cbp, code, i;
- UINT8 *coded_val;
+ uint8_t *coded_val;
+ uint32_t * const mb_type_ptr= &s->current_picture.mb_type[ s->mb_x + s->mb_y*s->mb_stride ];
-#ifdef PRINT_MB
-if(s->mb_x==0){
- printf("\n");
- if(s->mb_y==0) printf("\n");
-}
-#endif
- /* special slice handling */
- handle_slices(s);
-
- if(s->msmpeg4_version<=2) return msmpeg4v12_decode_mb(s, block); //FIXME export function & call from outside perhaps
-
if (s->pict_type == P_TYPE) {
set_stat(ST_INTER_MB);
if (s->use_skip_mb_code) {
s->mv[0][0][0] = 0;
s->mv[0][0][1] = 0;
s->mb_skiped = 1;
-#ifdef PRINT_MB
-printf("S ");
-#endif
+ *mb_type_ptr = MB_TYPE_SKIP | MB_TYPE_L0 | MB_TYPE_16x16;
+
return 0;
}
}
- code = get_vlc2(&s->gb, mb_non_intra_vlc.table, MB_NON_INTRA_VLC_BITS, 3);
+ code = get_vlc2(&s->gb, mb_non_intra_vlc[DEFAULT_INTER_INDEX].table, MB_NON_INTRA_VLC_BITS, 3);
if (code < 0)
return -1;
//s->mb_intra = (code & 0x40) ? 0 : 1;
s->mv_type = MV_TYPE_16X16;
s->mv[0][0][0] = mx;
s->mv[0][0][1] = my;
-#ifdef PRINT_MB
-printf("P ");
-#endif
+ *mb_type_ptr = MB_TYPE_L0 | MB_TYPE_16x16;
} else {
//printf("I at %d %d %d %06X\n", s->mb_x, s->mb_y, ((cbp&3)? 1 : 0) +((cbp&0x3C)? 2 : 0), show_bits(&s->gb, 24));
set_stat(ST_INTRA_MB);
s->ac_pred = get_bits1(&s->gb);
-#ifdef PRINT_MB
-printf("%c", s->ac_pred ? 'A' : 'I');
-#endif
+ *mb_type_ptr = MB_TYPE_INTRA;
if(s->inter_intra_pred){
s->h263_aic_dir= get_vlc2(&s->gb, inter_intra_vlc.table, INTER_INTRA_VLC_BITS, 1);
// printf("%d%d %d %d/", s->ac_pred, s->h263_aic_dir, s->mb_x, s->mb_y);
}
for (i = 0; i < 6; i++) {
- if (msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1) < 0)
+ if (msmpeg4_decode_block(s, block[i], i, (cbp >> (5 - i)) & 1, NULL) < 0)
{
fprintf(stderr,"\nerror while decoding block: %d x %d (%d)\n", s->mb_x, s->mb_y, i);
return -1;
}
//#define ERROR_DETAILS
static inline int msmpeg4_decode_block(MpegEncContext * s, DCTELEM * block,
- int n, int coded)
+ int n, int coded, const uint8_t *scan_table)
{
int level, i, last, run, run_diff;
int dc_pred_dir;
RLTable *rl;
RL_VLC_ELEM *rl_vlc;
- const UINT8 *scan_table;
int qmul, qadd;
if (s->mb_intra) {
/* DC coef */
set_stat(ST_DC);
level = msmpeg4_decode_dc(s, n, &dc_pred_dir);
-#ifdef PRINT_MB
-{
- static int c;
- if(n==0) c=0;
- if(n==4) printf("%X", c);
- c+= c +dc_pred_dir;
-}
-#endif
+
if (level < 0){
fprintf(stderr, "dc overflow- block: %d qscale: %d//\n", n, s->qscale);
if(s->inter_intra_pred) level=0;
s->block_last_index[n] = i;
return 0;
}
- scan_table = s->inter_scantable.permutated;
+ if(!scan_table)
+ scan_table = s->inter_scantable.permutated;
set_stat(ST_INTER_AC);
rl_vlc= rl->rl_vlc[s->qscale];
}
if (i > 62){
i-= 192;
if(i&(~63)){
- const int left= s->gb.size*8 - get_bits_count(&s->gb);
- if(((i+192 == 64 && level/qmul==-1) || s->error_resilience<0) && left>=0){
+ const int left= s->gb.size_in_bits - get_bits_count(&s->gb);
+ if(((i+192 == 64 && level/qmul==-1) || s->error_resilience<=1) && left>=0){
fprintf(stderr, "ignoring overflow at %d %d\n", s->mb_x, s->mb_y);
break;
}else{
i = 63; /* XXX: not optimal */
}
}
- if(s->msmpeg4_version==4 && i>0) i=63; //FIXME/XXX optimize
+ if(s->msmpeg4_version>=4 && i>0) i=63; //FIXME/XXX optimize
s->block_last_index[n] = i;
return 0;
}
if(s->msmpeg4_version==1){
- INT32 *dc_val;
+ int32_t *dc_val;
pred = msmpeg4v1_pred_dc(s, n, &dc_val);
level += pred;
/* update predictor */
*dc_val= level;
}else{
- UINT16 *dc_val;
+ uint16_t *dc_val;
pred = msmpeg4_pred_dc(s, n, &dc_val, dir_ptr);
level += pred;
*my_ptr = my;
return 0;
}
+
+/* cleanest way to support it
+ * there is too much shared between versions so that we cant have 1 file per version & 1 common
+ * as allmost everything would be in the common file
+ */
+#include "wmv2.c"