Commit f4f3223f authored by Michael Niedermayer's avatar Michael Niedermayer

reuse motion vectors/mb types/field select values of the source video, if the...

reuse motion vectors/mb types/field select values of the source video, if the SSE for a macroblock which is predicted with these values is below me_threshold
currently works only with mpeg1/2 source or some luck
may need -sync 0 as otherwise framedrops could lead to extreemly long b frame sequences

Originally committed as revision 3042 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 10f3005f
...@@ -159,6 +159,7 @@ static int noise_reduction = 0; ...@@ -159,6 +159,7 @@ static int noise_reduction = 0;
static int sc_threshold = 0; static int sc_threshold = 0;
static int debug = 0; static int debug = 0;
static int debug_mv = 0; static int debug_mv = 0;
static int me_threshold = 0;
extern int loop_input; /* currently a hack */ extern int loop_input; /* currently a hack */
static int gop_size = 12; static int gop_size = 12;
...@@ -187,6 +188,7 @@ static int bitexact = 0; ...@@ -187,6 +188,7 @@ static int bitexact = 0;
static char *pass_logfilename = NULL; static char *pass_logfilename = NULL;
static int audio_stream_copy = 0; static int audio_stream_copy = 0;
static int video_stream_copy = 0; static int video_stream_copy = 0;
static int sync_method= 1;
static int rate_emu = 0; static int rate_emu = 0;
...@@ -577,6 +579,7 @@ static void do_video_out(AVFormatContext *s, ...@@ -577,6 +579,7 @@ static void do_video_out(AVFormatContext *s,
/* NOTE: the A/V sync is always done by considering the audio is /* NOTE: the A/V sync is always done by considering the audio is
the master clock. It is suffisant for transcoding or playing, the master clock. It is suffisant for transcoding or playing,
but not for the general case */ but not for the general case */
if(sync_method){
if (audio_sync) { if (audio_sync) {
/* compute the A-V delay and duplicate/remove frames if needed */ /* compute the A-V delay and duplicate/remove frames if needed */
double adelta, vdelta, av_delay; double adelta, vdelta, av_delay;
...@@ -588,11 +591,11 @@ static void do_video_out(AVFormatContext *s, ...@@ -588,11 +591,11 @@ static void do_video_out(AVFormatContext *s,
s->pts_num / s->pts_den); s->pts_num / s->pts_den);
av_delay = adelta - vdelta; av_delay = adelta - vdelta;
// printf("delay=%f\n", av_delay);
if (av_delay < -AV_DELAY_MAX) if (av_delay < -AV_DELAY_MAX)
nb_frames = 2; nb_frames = 2;
else if (av_delay > AV_DELAY_MAX) else if (av_delay > AV_DELAY_MAX)
nb_frames = 0; nb_frames = 0;
// printf("delay=%f nb=%d (A)\n", av_delay, nb_frames);
} else { } else {
double vdelta; double vdelta;
...@@ -607,7 +610,9 @@ static void do_video_out(AVFormatContext *s, ...@@ -607,7 +610,9 @@ static void do_video_out(AVFormatContext *s,
if (!ost->sync_ipts_offset) if (!ost->sync_ipts_offset)
ost->sync_ipts_offset = 0.000001; /* one microsecond */ ost->sync_ipts_offset = 0.000001; /* one microsecond */
} }
// printf("delay=%f nb=%d (V)\n",vdelta, nb_frames);
} }
}
#if defined(AVSYNC_DEBUG) #if defined(AVSYNC_DEBUG)
{ {
...@@ -793,7 +798,8 @@ static void do_video_out(AVFormatContext *s, ...@@ -793,7 +798,8 @@ static void do_video_out(AVFormatContext *s,
big_picture.quality = ist->st->quality; big_picture.quality = ist->st->quality;
}else }else
big_picture.quality = ost->st->quality; big_picture.quality = ost->st->quality;
big_picture.pict_type = 0; if(!me_threshold)
big_picture.pict_type = 0;
big_picture.pts = AV_NOPTS_VALUE; //FIXME big_picture.pts = AV_NOPTS_VALUE; //FIXME
ret = avcodec_encode_video(enc, ret = avcodec_encode_video(enc,
video_buffer, VIDEO_BUFFER_SIZE, video_buffer, VIDEO_BUFFER_SIZE,
...@@ -1853,6 +1859,11 @@ static void opt_idct_algo(const char *arg) ...@@ -1853,6 +1859,11 @@ static void opt_idct_algo(const char *arg)
idct_algo = atoi(arg); idct_algo = atoi(arg);
} }
static void opt_me_threshold(const char *arg)
{
me_threshold = atoi(arg);
}
static void opt_error_resilience(const char *arg) static void opt_error_resilience(const char *arg)
{ {
...@@ -1880,6 +1891,11 @@ static void opt_verbose(const char *arg) ...@@ -1880,6 +1891,11 @@ static void opt_verbose(const char *arg)
av_log_set_level(atoi(arg)); av_log_set_level(atoi(arg));
} }
static void opt_sync_method(const char *arg)
{
sync_method = atoi(arg);
}
static void opt_frame_rate(const char *arg) static void opt_frame_rate(const char *arg)
{ {
if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) { if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) {
...@@ -2554,6 +2570,8 @@ static void opt_input_file(const char *filename) ...@@ -2554,6 +2570,8 @@ static void opt_input_file(const char *filename)
enc->debug_mv = debug_mv; enc->debug_mv = debug_mv;
if(bitexact) if(bitexact)
enc->flags|= CODEC_FLAG_BITEXACT; enc->flags|= CODEC_FLAG_BITEXACT;
if(me_threshold)
enc->debug |= FF_DEBUG_MV;
assert(enc->frame_rate_base == rfps_base); // should be true for now assert(enc->frame_rate_base == rfps_base); // should be true for now
if (enc->frame_rate != rfps) { if (enc->frame_rate != rfps) {
...@@ -2844,6 +2862,7 @@ static void opt_output_file(const char *filename) ...@@ -2844,6 +2862,7 @@ static void opt_output_file(const char *filename)
video_enc->inter_quant_bias = video_inter_quant_bias; video_enc->inter_quant_bias = video_inter_quant_bias;
video_enc->dct_algo = dct_algo; video_enc->dct_algo = dct_algo;
video_enc->idct_algo = idct_algo; video_enc->idct_algo = idct_algo;
video_enc->me_threshold= me_threshold;
video_enc->strict_std_compliance = strict; video_enc->strict_std_compliance = strict;
video_enc->error_rate = error_rate; video_enc->error_rate = error_rate;
video_enc->noise_reduction= noise_reduction; video_enc->noise_reduction= noise_reduction;
...@@ -3415,6 +3434,7 @@ const OptionDef options[] = { ...@@ -3415,6 +3434,7 @@ const OptionDef options[] = {
{ "v", HAS_ARG, {(void*)opt_verbose}, "control amount of logging", "verbose" }, { "v", HAS_ARG, {(void*)opt_verbose}, "control amount of logging", "verbose" },
{ "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\" or \"dvd\")", "type" }, { "target", HAS_ARG, {(void*)opt_target}, "specify target file type (\"vcd\", \"svcd\" or \"dvd\")", "type" },
{ "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" }, { "threads", HAS_ARG | OPT_EXPERT, {(void*)opt_thread_count}, "thread count", "count" },
{ "sync", HAS_ARG | OPT_EXPERT, {(void*)opt_sync_method}, "sync method", "" },
/* video options */ /* video options */
{ "b", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate}, "set video bitrate (in kbit/s)", "bitrate" }, { "b", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate}, "set video bitrate (in kbit/s)", "bitrate" },
...@@ -3461,6 +3481,7 @@ const OptionDef options[] = { ...@@ -3461,6 +3481,7 @@ const OptionDef options[] = {
"method" }, "method" },
{ "dct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_dct_algo}, "set dct algo", "algo" }, { "dct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_dct_algo}, "set dct algo", "algo" },
{ "idct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_idct_algo}, "set idct algo", "algo" }, { "idct_algo", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_idct_algo}, "set idct algo", "algo" },
{ "me_threshold", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_me_threshold}, "motion estimaton threshold", "" },
{ "er", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_resilience}, "set error resilience", "n" }, { "er", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_resilience}, "set error resilience", "n" },
{ "ec", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_concealment}, "set error concealment", "bit_mask" }, { "ec", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_error_concealment}, "set error concealment", "bit_mask" },
{ "bf", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_b_frames}, "use 'frames' B frames", "frames" }, { "bf", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_b_frames}, "use 'frames' B frames", "frames" },
......
...@@ -973,6 +973,119 @@ static int interlaced_search(MpegEncContext *s, int ref_index, ...@@ -973,6 +973,119 @@ static int interlaced_search(MpegEncContext *s, int ref_index,
} }
} }
static inline int check_input_motion(MpegEncContext * s, int mb_x, int mb_y, int p_type){
MotionEstContext * const c= &s->me;
Picture *p= s->current_picture_ptr;
int mb_xy= mb_x + mb_y*s->mb_stride;
int xy= 2*mb_x + 2*mb_y*s->b8_stride;
int mb_type= s->current_picture.mb_type[mb_xy];
int flags= c->flags;
int shift= (flags&FLAG_QPEL) + 1;
int mask= (1<<shift)-1;
int x, y;
int d=0;
me_cmp_func cmpf= s->dsp.sse[0];
me_cmp_func chroma_cmpf= s->dsp.sse[1];
assert(p_type==0 || !USES_LIST(mb_type, 1));
assert(IS_INTRA(mb_type) || USES_LIST(mb_type,0) || USES_LIST(mb_type,1));
if(IS_INTERLACED(mb_type)){
int xy2= xy + s->b8_stride;
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTRA;
c->stride<<=1;
c->uvstride<<=1;
c->ref[1][0] = c->ref[0][0] + s->linesize;
c->ref[3][0] = c->ref[2][0] + s->linesize;
c->src[1][0] = c->src[0][0] + s->linesize;
if(c->flags & FLAG_CHROMA){
c->ref[1][1] = c->ref[0][1] + s->uvlinesize;
c->ref[1][2] = c->ref[0][2] + s->uvlinesize;
c->ref[3][1] = c->ref[2][1] + s->uvlinesize;
c->ref[3][2] = c->ref[2][2] + s->uvlinesize;
c->src[1][1] = c->src[0][1] + s->uvlinesize;
c->src[1][2] = c->src[0][2] + s->uvlinesize;
}
if(USES_LIST(mb_type, 0)){
int field_select0= p->ref_index[0][xy ];
int field_select1= p->ref_index[0][xy2];
assert(field_select0==0 ||field_select0==1);
assert(field_select1==0 ||field_select1==1);
if(p_type){
s->p_field_select_table[0][mb_xy]= field_select0;
s->p_field_select_table[1][mb_xy]= field_select1;
*(uint32_t*)s->p_field_mv_table[0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[0][xy ];
*(uint32_t*)s->p_field_mv_table[1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[0][xy2];
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTER_I;
}else{
s->b_field_select_table[0][0][mb_xy]= field_select0;
s->b_field_select_table[0][1][mb_xy]= field_select1;
*(uint32_t*)s->b_field_mv_table[0][0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[0][xy ];
*(uint32_t*)s->b_field_mv_table[0][1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[0][xy2];
s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_FORWARD_I;
}
x= p->motion_val[0][xy ][0];
y= p->motion_val[0][xy ][1];
d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select0, 0, cmpf, chroma_cmpf, flags);
x= p->motion_val[0][xy2][0];
y= p->motion_val[0][xy2][1];
d+= cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select1, 1, cmpf, chroma_cmpf, flags);
}
if(USES_LIST(mb_type, 1)){
int field_select0= p->ref_index[1][xy ];
int field_select1= p->ref_index[1][xy2];
assert(field_select0==0 ||field_select0==1);
assert(field_select1==0 ||field_select1==1);
s->b_field_select_table[1][0][mb_xy]= field_select0;
s->b_field_select_table[1][1][mb_xy]= field_select1;
*(uint32_t*)s->b_field_mv_table[1][0][field_select0][mb_xy]= *(uint32_t*)p->motion_val[1][xy ];
*(uint32_t*)s->b_field_mv_table[1][1][field_select1][mb_xy]= *(uint32_t*)p->motion_val[1][xy2];
if(USES_LIST(mb_type, 0)){
s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_BIDIR_I;
}else{
s->mb_type[mb_xy]= CANDIDATE_MB_TYPE_BACKWARD_I;
}
x= p->motion_val[1][xy ][0];
y= p->motion_val[1][xy ][1];
d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select0+2, 0, cmpf, chroma_cmpf, flags);
x= p->motion_val[1][xy2][0];
y= p->motion_val[1][xy2][1];
d+= cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 8, field_select1+2, 1, cmpf, chroma_cmpf, flags);
//FIXME bidir scores
}
c->stride>>=1;
c->uvstride>>=1;
}else{
if(USES_LIST(mb_type, 0)){
if(p_type){
*(uint32_t*)s->p_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy];
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTER;
}else if(USES_LIST(mb_type, 1)){
*(uint32_t*)s->b_bidir_forw_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy];
*(uint32_t*)s->b_bidir_back_mv_table[mb_xy]= *(uint32_t*)p->motion_val[1][xy];
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_BIDIR;
}else{
*(uint32_t*)s->b_forw_mv_table[mb_xy]= *(uint32_t*)p->motion_val[0][xy];
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_FORWARD;
}
x= p->motion_val[0][xy][0];
y= p->motion_val[0][xy][1];
d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 16, 0, 0, cmpf, chroma_cmpf, flags);
}else if(USES_LIST(mb_type, 1)){
*(uint32_t*)s->b_back_mv_table[mb_xy]= *(uint32_t*)p->motion_val[1][xy];
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_BACKWARD;
x= p->motion_val[1][xy][0];
y= p->motion_val[1][xy][1];
d = cmp(s, x>>shift, y>>shift, x&mask, y&mask, 0, 16, 2, 0, cmpf, chroma_cmpf, flags);
}else
s->mb_type[mb_xy]=CANDIDATE_MB_TYPE_INTRA;
}
return d;
}
void ff_estimate_p_frame_motion(MpegEncContext * s, void ff_estimate_p_frame_motion(MpegEncContext * s,
int mb_x, int mb_y) int mb_x, int mb_y)
{ {
...@@ -999,6 +1112,28 @@ void ff_estimate_p_frame_motion(MpegEncContext * s, ...@@ -999,6 +1112,28 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
get_limits(s, 16*mb_x, 16*mb_y); get_limits(s, 16*mb_x, 16*mb_y);
s->me.skip=0; s->me.skip=0;
if(s->avctx->me_threshold){
vard= (check_input_motion(s, mb_x, mb_y, 1)+128)>>8;
if(vard<s->avctx->me_threshold){
pix = c->src[0][0];
sum = s->dsp.pix_sum(pix, s->linesize);
varc = (s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500 + 128)>>8;
pic->mb_var [s->mb_stride * mb_y + mb_x] = varc;
pic->mc_mb_var[s->mb_stride * mb_y + mb_x] = vard;
pic->mb_mean [s->mb_stride * mb_y + mb_x] = (sum+128)>>8;
s->mb_var_sum_temp += varc;
s->mc_mb_var_sum_temp += vard;
if (vard <= 64 || vard < varc) { //FIXME
s->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
}else{
s->scene_change_score+= s->qscale;
}
return;
}
}
switch(s->me_method) { switch(s->me_method) {
case ME_ZERO: case ME_ZERO:
default: default:
...@@ -1555,6 +1690,28 @@ void ff_estimate_b_frame_motion(MpegEncContext * s, ...@@ -1555,6 +1690,28 @@ void ff_estimate_b_frame_motion(MpegEncContext * s,
init_mc(s, 0, s->me.flags); init_mc(s, 0, s->me.flags);
s->me.skip=0; s->me.skip=0;
if(s->avctx->me_threshold){
int vard= (check_input_motion(s, mb_x, mb_y, 0)+128)>>8;
if(vard<s->avctx->me_threshold){
// pix = c->src[0][0];
// sum = s->dsp.pix_sum(pix, s->linesize);
// varc = (s->dsp.pix_norm1(pix, s->linesize) - (((unsigned)(sum*sum))>>8) + 500 + 128)>>8;
// pic->mb_var [s->mb_stride * mb_y + mb_x] = varc;
s->current_picture.mc_mb_var[s->mb_stride * mb_y + mb_x] = vard;
/* pic->mb_mean [s->mb_stride * mb_y + mb_x] = (sum+128)>>8;
s->mb_var_sum_temp += varc;*/
s->mc_mb_var_sum_temp += vard;
/* if (vard <= 64 || vard < varc) {
s->scene_change_score+= ff_sqrt(vard) - ff_sqrt(varc);
}else{
s->scene_change_score+= s->qscale;
}*/
return;
}
}
if (s->codec_id == CODEC_ID_MPEG4) if (s->codec_id == CODEC_ID_MPEG4)
dmin= direct_search(s, mb_x, mb_y); dmin= direct_search(s, mb_x, mb_y);
else else
......
...@@ -295,7 +295,8 @@ static void copy_picture_attributes(MpegEncContext *s, AVFrame *dst, AVFrame *sr ...@@ -295,7 +295,8 @@ static void copy_picture_attributes(MpegEncContext *s, AVFrame *dst, AVFrame *sr
if(!src->ref_index[0]) if(!src->ref_index[0])
av_log(s->avctx, AV_LOG_ERROR, "AVFrame.ref_index not set!\n"); av_log(s->avctx, AV_LOG_ERROR, "AVFrame.ref_index not set!\n");
if(src->motion_subsample_log2 != dst->motion_subsample_log2) if(src->motion_subsample_log2 != dst->motion_subsample_log2)
av_log(s->avctx, AV_LOG_ERROR, "AVFrame.motion_subsample_log2 doesnt match!\n"); av_log(s->avctx, AV_LOG_ERROR, "AVFrame.motion_subsample_log2 doesnt match! (%d!=%d)\n",
src->motion_subsample_log2, dst->motion_subsample_log2);
memcpy(dst->mb_type, src->mb_type, s->mb_stride * s->mb_height * sizeof(dst->mb_type[0])); memcpy(dst->mb_type, src->mb_type, s->mb_stride * s->mb_height * sizeof(dst->mb_type[0]));
...@@ -2055,11 +2056,12 @@ static void select_input_picture(MpegEncContext *s){ ...@@ -2055,11 +2056,12 @@ static void select_input_picture(MpegEncContext *s){
s->reordered_input_picture[0]->data[i]= NULL; s->reordered_input_picture[0]->data[i]= NULL;
s->reordered_input_picture[0]->type= 0; s->reordered_input_picture[0]->type= 0;
copy_picture_attributes(s, (AVFrame*)pic, (AVFrame*)s->reordered_input_picture[0]);
pic->reference = s->reordered_input_picture[0]->reference; pic->reference = s->reordered_input_picture[0]->reference;
alloc_picture(s, pic, 0); alloc_picture(s, pic, 0);
copy_picture_attributes(s, (AVFrame*)pic, (AVFrame*)s->reordered_input_picture[0]);
s->current_picture_ptr= pic; s->current_picture_ptr= pic;
}else{ }else{
// input is not a shared pix -> reuse buffer for current_pix // input is not a shared pix -> reuse buffer for current_pix
...@@ -4676,7 +4678,7 @@ static void encode_picture(MpegEncContext *s, int picture_number) ...@@ -4676,7 +4678,7 @@ static void encode_picture(MpegEncContext *s, int picture_number)
/* Estimate motion for every MB */ /* Estimate motion for every MB */
if(s->pict_type != I_TYPE){ if(s->pict_type != I_TYPE){
if(s->pict_type != B_TYPE){ if(s->pict_type != B_TYPE && s->avctx->me_threshold==0){
if((s->avctx->pre_me && s->last_non_b_pict_type==I_TYPE) || s->avctx->pre_me==2){ if((s->avctx->pre_me && s->last_non_b_pict_type==I_TYPE) || s->avctx->pre_me==2){
s->avctx->execute(s->avctx, pre_estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count); s->avctx->execute(s->avctx, pre_estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment