mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
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
This commit is contained in:
parent
10f3005f51
commit
f4f3223ffd
25
ffmpeg.c
25
ffmpeg.c
@ -159,6 +159,7 @@ static int noise_reduction = 0;
|
||||
static int sc_threshold = 0;
|
||||
static int debug = 0;
|
||||
static int debug_mv = 0;
|
||||
static int me_threshold = 0;
|
||||
extern int loop_input; /* currently a hack */
|
||||
|
||||
static int gop_size = 12;
|
||||
@ -187,6 +188,7 @@ static int bitexact = 0;
|
||||
static char *pass_logfilename = NULL;
|
||||
static int audio_stream_copy = 0;
|
||||
static int video_stream_copy = 0;
|
||||
static int sync_method= 1;
|
||||
|
||||
static int rate_emu = 0;
|
||||
|
||||
@ -577,6 +579,7 @@ static void do_video_out(AVFormatContext *s,
|
||||
/* NOTE: the A/V sync is always done by considering the audio is
|
||||
the master clock. It is suffisant for transcoding or playing,
|
||||
but not for the general case */
|
||||
if(sync_method){
|
||||
if (audio_sync) {
|
||||
/* compute the A-V delay and duplicate/remove frames if needed */
|
||||
double adelta, vdelta, av_delay;
|
||||
@ -588,11 +591,11 @@ static void do_video_out(AVFormatContext *s,
|
||||
s->pts_num / s->pts_den);
|
||||
|
||||
av_delay = adelta - vdelta;
|
||||
// printf("delay=%f\n", av_delay);
|
||||
if (av_delay < -AV_DELAY_MAX)
|
||||
nb_frames = 2;
|
||||
else if (av_delay > AV_DELAY_MAX)
|
||||
nb_frames = 0;
|
||||
// printf("delay=%f nb=%d (A)\n", av_delay, nb_frames);
|
||||
} else {
|
||||
double vdelta;
|
||||
|
||||
@ -607,7 +610,9 @@ static void do_video_out(AVFormatContext *s,
|
||||
if (!ost->sync_ipts_offset)
|
||||
ost->sync_ipts_offset = 0.000001; /* one microsecond */
|
||||
}
|
||||
// printf("delay=%f nb=%d (V)\n",vdelta, nb_frames);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AVSYNC_DEBUG)
|
||||
{
|
||||
@ -793,7 +798,8 @@ static void do_video_out(AVFormatContext *s,
|
||||
big_picture.quality = ist->st->quality;
|
||||
}else
|
||||
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
|
||||
ret = avcodec_encode_video(enc,
|
||||
video_buffer, VIDEO_BUFFER_SIZE,
|
||||
@ -1853,6 +1859,11 @@ static void opt_idct_algo(const char *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)
|
||||
{
|
||||
@ -1880,6 +1891,11 @@ static void opt_verbose(const char *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)
|
||||
{
|
||||
if (parse_frame_rate(&frame_rate, &frame_rate_base, arg) < 0) {
|
||||
@ -2554,6 +2570,8 @@ static void opt_input_file(const char *filename)
|
||||
enc->debug_mv = debug_mv;
|
||||
if(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
|
||||
if (enc->frame_rate != rfps) {
|
||||
@ -2844,6 +2862,7 @@ static void opt_output_file(const char *filename)
|
||||
video_enc->inter_quant_bias = video_inter_quant_bias;
|
||||
video_enc->dct_algo = dct_algo;
|
||||
video_enc->idct_algo = idct_algo;
|
||||
video_enc->me_threshold= me_threshold;
|
||||
video_enc->strict_std_compliance = strict;
|
||||
video_enc->error_rate = error_rate;
|
||||
video_enc->noise_reduction= noise_reduction;
|
||||
@ -3415,6 +3434,7 @@ const OptionDef options[] = {
|
||||
{ "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" },
|
||||
{ "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 */
|
||||
{ "b", HAS_ARG | OPT_VIDEO, {(void*)opt_video_bitrate}, "set video bitrate (in kbit/s)", "bitrate" },
|
||||
@ -3461,6 +3481,7 @@ const OptionDef options[] = {
|
||||
"method" },
|
||||
{ "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" },
|
||||
{ "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" },
|
||||
{ "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" },
|
||||
|
@ -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,
|
||||
int mb_x, int mb_y)
|
||||
{
|
||||
@ -999,6 +1112,28 @@ void ff_estimate_p_frame_motion(MpegEncContext * s,
|
||||
get_limits(s, 16*mb_x, 16*mb_y);
|
||||
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) {
|
||||
case ME_ZERO:
|
||||
default:
|
||||
@ -1555,6 +1690,28 @@ void ff_estimate_b_frame_motion(MpegEncContext * s,
|
||||
init_mc(s, 0, s->me.flags);
|
||||
|
||||
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)
|
||||
dmin= direct_search(s, mb_x, mb_y);
|
||||
else
|
||||
|
@ -295,7 +295,8 @@ static void copy_picture_attributes(MpegEncContext *s, AVFrame *dst, AVFrame *sr
|
||||
if(!src->ref_index[0])
|
||||
av_log(s->avctx, AV_LOG_ERROR, "AVFrame.ref_index not set!\n");
|
||||
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]));
|
||||
|
||||
@ -2055,11 +2056,12 @@ static void select_input_picture(MpegEncContext *s){
|
||||
s->reordered_input_picture[0]->data[i]= NULL;
|
||||
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;
|
||||
|
||||
alloc_picture(s, pic, 0);
|
||||
|
||||
copy_picture_attributes(s, (AVFrame*)pic, (AVFrame*)s->reordered_input_picture[0]);
|
||||
|
||||
s->current_picture_ptr= pic;
|
||||
}else{
|
||||
// input is not a shared pix -> reuse buffer for current_pix
|
||||
@ -4676,7 +4678,7 @@ static void encode_picture(MpegEncContext *s, int picture_number)
|
||||
|
||||
/* Estimate motion for every MB */
|
||||
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){
|
||||
s->avctx->execute(s->avctx, pre_estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user