📄 motionest.cc
字号:
if( ! picture.InRangeFieldMVRef( cross ) ) return false; uint8_t *sameref = ref + same_fieldoff + (same.x>>1) + (stride<<1)*(same.y>>1); uint8_t *crossref = ref + cross_fieldoff + (cross.x>>1) + (stride<<1)*(cross.y>>1); /* compute prediction error */ part_meas += meas( sameref, crossref, pred_mb, stride<<1, same.x&1, same.y&1, cross.x&1, cross.y&1, 8 ); } measure = part_meas; return true; // All vectors legal...}bool MacroBlock::FrameDualPrimeCand (uint8_t *ref, const SubSampledImg &ssmb, const MotionCand (&best_fieldmcs)[Parity::dim][Parity::dim], MotionCand &best_mc, MotionVector &min_dpmv){ int local_dist; int stride = picture->encparams.phy_width; bool dpmvfound = false; // Tricky here we need half-pel field co-ordinates so hpel won't do! const Coord mb( Coord::HalfPel(Coord::Field(pel)) ); /* Calculate Dual Prime distortions for 9 delta candidates * for each of the four minimum field vectors * Note: only for P pictures! */ /* initialize minimum dual prime distortion to maximum * macroblockvariance value. Ensure estimate won't be used if * no legal one can be found... */ int best_sad = 256*16*16; int (&m)[Parity::dim /*ref*/][Parity::dim /*pred*/] = dualprime_m[picture->topfirst]; Coord min_cross[Parity::dim]; Coord min_same; // Iterate over the different suggestions corresponding to the // different possible combinations of reference/prediction // field parity for ( int psugref=Parity::top; psugref<=Parity::bot; psugref++) { // Iterate of over parity predicted MB suggestion for ( int psugpred=Parity::top; psugpred<=Parity::top; psugpred++) { /* convert Cartesian absolute to relative motion vector * values (wrt current macroblock address (i,j) */ MotionVector suggestion = MotionVector::Frame(best_fieldmcs[psugref][psugpred].pos, mb ); /* If the candidate base vector is between opposite polarity fields we have to convert it to a corresponding dual-prime base-vector. N.b. this may *increase* its magnitude outside the legal range so we have to check for this... */ MotionVector base; base[Dim::X] = suggestion[Dim::X]*2/m[psugref][psugpred]; base[Dim::Y] = (suggestion[Dim::Y] - dualprime_e[psugref][psugpred])*2/m[psugref][psugpred]; if( ! picture->Legal( base ) ) continue; /* We use (legal) base motion vectors for the same polarity prediction and to derive the base motion vectors for the cross-polarity predictions */ Coord same( mb, base ); Coord cross[Parity::dim /* ref polarity */]; for( int pref = Parity::top; pref < Parity::dim; ++pref ) { int ppred = Parity::Invert(pref); cross[pref].x = rnddiv2(base[Dim::X] * m[pref][ppred]) + mb.x; cross[pref].y = rnddiv2(base[Dim::Y] * m[pref][ppred]) +dualprime_e[pref][ppred]+mb.y; } /* Now find the best differential motion vector for the cross-polarity predictions */ MotionVector dmv; for (dmv[Dim::Y]=-1; dmv[Dim::Y]<=1; ++dmv[Dim::Y]) { for (dmv[Dim::X]=-1; dmv[Dim::X]<=1; ++dmv[Dim::X]) { local_dist = 0; bool legal = DualPrimeMetric( *picture, pbsad, same, cross, dmv, ref, ssmb.mb, stride, local_dist ); /* update best legal MV with smallest distortion * distortion */ if ( local_dist < best_sad && legal ) { dpmvfound = true; min_dpmv = dmv; best_sad = local_dist; min_same = same; min_cross[Parity::top] = cross[Parity::top]; min_cross[Parity::bot] = cross[Parity::bot]; } } /* end delta x loop */ } /* end delta y loop */ } } if( dpmvfound ) { DualPrimeMetric( *picture, pbsumsq, min_same, min_cross, min_dpmv, ref, ssmb.mb, stride, best_mc.var ); best_mc.sad = best_sad + mv_coding_penalty( min_same.x-mb.x, min_same.y-mb.y ); best_mc.pos = min_same; } return dpmvfound;}static void dpfield_estimate( const Picture &picture, uint8_t *topref, uint8_t *botref, uint8_t *mb, int i, int j, MotionCand *bestsp_mc, MotionCand *bestdp_mc, int *vmcp ){ const EncoderParams &eparams = picture.encparams; uint8_t *sameref, *oppref; int io0,jo0,io,jo,delta_x,delta_y,mvxs,mvys,mvxo0,mvyo0; int imino = 0; int jmino = 0; int imindmv = 0; int jmindmv = 0; int vmc_dp,local_dist; int imins = 0; int jmins = 0; /* Calculate Dual Prime distortions for 9 delta candidates */ /* Note: only for P pictures! */ /* Assign opposite and same reference pointer */ if (picture.pict_struct==TOP_FIELD) { sameref = topref; oppref = botref; } else { sameref = botref; oppref = topref; } /* convert Cartesian absolute to relative motion vector * values (wrt current macroblock address (i,j) */ mvxs = imins - (i<<1); mvys = jmins - (j<<1); /* vector for prediction from field of opposite 'parity' */ mvxo0 = (mvxs+(mvxs>0)) >> 1; /* mvxs / / */ mvyo0 = (mvys+(mvys>0)) >> 1; /* mvys / / 2*/ /* vertical field shift correction */ if (picture.pict_struct==TOP_FIELD) mvyo0--; else mvyo0++; /* convert back to absolute coordinates */ io0 = mvxo0 + (i<<1); jo0 = mvyo0 + (j<<1); /* initialize minimum dual prime distortion to maximum * macroblock variance value */ vmc_dp = 256*256*16*16; for (delta_y = -1; delta_y <= 1; delta_y++) { for (delta_x = -1; delta_x <=1; delta_x++) { /* opposite field coordinates */ io = io0 + delta_x; jo = jo0 + delta_y; if (io >= 0 && io <= (eparams.enc_width-16)<<1 && jo >= 0 && jo <= (eparams.enc_height2-16)<<1) { /* compute prediction error */ local_dist = pbsumsq( sameref + (imins>>1) + eparams.phy_width2*(jmins>>1), oppref + (io>>1) + eparams.phy_width2*(jo>>1), mb, /* current mb location */ eparams.phy_width2, /* adjacent line distance */ imins&1, jmins&1, io&1, jo&1, /* half-pel flags */ 16); /* block height */ /* update delta with least distortion vector */ if (local_dist < vmc_dp) { imino = io; jmino = jo; imindmv = delta_x; jmindmv = delta_y; vmc_dp = local_dist; } } } /* end delta x loop */ } /* end delta y loop */ /* Compute L1 error for decision purposes */ bestdp_mc->sad = pbsad( sameref + (imins>>1) + eparams.phy_width2*(jmins>>1), oppref + (imino>>1) + eparams.phy_width2*(jmino>>1), mb, /* current mb location */ eparams.phy_width2, /* adjacent line distance */ imins&1, jmins&1, imino&1, jmino&1, /* half-pel flags */ 16); /* block height */ bestdp_mc->pos.x = imindmv; bestdp_mc->pos.x = jmindmv; *vmcp = vmc_dp;}/* * Collection motion estimates for the different modes for frame pictures * picture: picture object for which MC is to be computed. * * results: a vector of 'plausible' motion estimates. This function * which is a refined version of the original MSSE reference encoder * only every puts a single, heuristically 'best', estimate into the vector * * TODO: MC_DMV should trigger on the current (dynamically selected) * bigroup length and not the fixed Maximum bi-group length M. */#ifdef DEBUG_MOTION_ESTconst static bool trace_me = false;#endifvoid MacroBlock::FrameMEs(){ const Picture &picture = ParentPicture(); const EncoderParams &eparams = picture.encparams; int i = TopleftX(); int j = TopleftY(); // // Motion info for the various possible motion modes... // MotionCand framef_mc; MotionCand frameb_mc; MotionCand dualpf_mc; MotionCand topfldf_mc; MotionCand botfldf_mc; MotionCand topfldb_mc; MotionCand botfldb_mc; MotionCand zeromot_mc; // Pointers to macroblock's contents in YUV and half and quad // subsampled planes, and for FIELD modes, the bottom field // variants... SubSampledImg ssmb; SubSampledImg botssmb; MotionCand best_fieldmcs[2][2]; MotionVector min_dpmv; int mb_row_start = j*eparams.phy_width; MotionEst me; best_of_kind_me.erase(best_of_kind_me.begin(),best_of_kind_me.end()); /* A.Stevens fast motion estimation data is appended to actual luminance information. TODO: The append thing made sense before we had a nice tidy compression record for each picture but now it should really be replaced by additional pointers to seperate buffers. */ ssmb.mb = picture.org_img[0] + mb_row_start + i; ssmb.umb = (uint8_t*)(picture.org_img[1] + (i>>1) + (mb_row_start>>2)); ssmb.vmb = (uint8_t*)(picture.org_img[2] + (i>>1) + (mb_row_start>>2)); ssmb.fmb = (uint8_t*)(picture.org_img[0] + eparams.fsubsample_offset + ((i>>1) + (mb_row_start>>2))); ssmb.qmb = (uint8_t*)(picture.org_img[0] + eparams.qsubsample_offset + (i>>2) + (mb_row_start>>4)); /* Zero motion vector - useful for some optimisations */ zeromot_mc.pos.x = (i<<1); /* Damn but its messy carrying doubled */ zeromot_mc.pos.y = (j<<1); /* absolute Co-ordinates for M/C */ zeromot_mc.fieldsel = 0; zeromot_mc.fieldoff = 0; zeromot_mc.blk = picture.fwd_rec[0]+mb_row_start+i; zeromot_mc.hx = zeromot_mc.hy = 0; /* Compute variance MB as a measure of Intra-coding complexity We include chrominance information here, scaled to compensate for sub-sampling. Silly MPEG forcing chrom/lum to have same quantisations... ;-) */ pvariance(ssmb.mb,16,eparams.phy_width, &lum_variance, &lum_mean ); int intravar = lum_variance + chrom_var_sum(&ssmb,16,eparams.phy_width); /* We always have the possibility of INTRA coding */ me.mb_type = MB_INTRA; me.motion_type = 0; me.var = intravar; me.MV[0][0].Zero(); best_of_kind_me.push_back( me ); if (picture.pict_type==P_TYPE) { /* FRAME mode non-intra coding 0 MV and estimated MVs is always possible */ zeromot_mc.var = unidir_pred_var(&zeromot_mc, ssmb.mb, eparams.phy_width, 16 ); me.mb_type = 0; me.motion_type = MC_FRAME; me.var = unidir_var_sum(&zeromot_mc, picture.fwd_rec, &ssmb, eparams.phy_width, 16 ); best_of_kind_me.push_back( me ); mb_me_search( eparams, picture.fwd_org[0],picture.fwd_rec[0], 0, &ssmb, eparams.phy_width, i,j,picture.sxf,picture.syf,16, eparams.enc_width,eparams.enc_height, &framef_mc); framef_mc.fieldoff = 0; me.mb_type = MB_FORWARD; me.motion_type=MC_FRAME; me.var = unidir_var_sum( &framef_mc, picture.fwd_rec, &ssmb, eparams.phy_width, 16 ); me.MV[0][0] = MotionVector::Frame( framef_mc.pos, hpel ); best_of_kind_me.push_back( me ); /* FIELD modes only possible if appropriate picture type is legal */ if (!picture.frame_pred_dct ) { botssmb.mb = ssmb.mb+eparams.phy_width; botssmb.fmb = ssmb.fmb+(eparams.phy_width>>1); botssmb.qmb = ssmb.qmb+(eparams.phy_width>>2); botssmb.umb = ssmb.umb+(eparams.phy_width>>1); botssmb.vmb = ssmb.vmb+(eparams.phy_width>>1); FieldMotionCands( eparams, picture.fwd_org[0],picture.fwd_rec[0], &ssmb, &botssmb, i,j,picture.sxf,picture.syf, &topfldf_mc, &botfldf_mc, best_fieldmcs); me.mb_type = MB_FORWARD; me.motion_type = MC_FIELD; me.var = unidir_var_sum( &topfldf_mc, picture.fwd_rec, &ssmb, (eparams.phy_width<<1), 8 ) + unidir_var_sum( &botfldf_mc, picture.fwd_rec, &botssmb, (eparams.phy_width<<1), 8 ); me.MV[0][0] = MotionVector::Field(topfldf_mc.pos, hpel); me.MV[1][0] = MotionVector::Field(botfldf_mc.pos, hpel); me.field_sel[0][0] = topfldf_mc.fieldsel; me.field_sel[1][0] = botfldf_mc.fieldsel; best_of_kind_me.push_back( me ); if ( eparams.dualprime && FrameDualPrimeCand(picture.fwd_rec[0], ssmb, best_fieldmcs, dualpf_mc, min_dpmv ) ) { me.mb_type = MB_FORWARD; me.motion_type = MC_DMV; me.MV[0][0] = MotionVector::Field(dualpf_mc.pos, hpel); me.dualprimeMV = min_dpmv; // TODO: No actual calculation of chroma variances // just assumed identical per block as luma. me.var = dualpf_mc.var + dualpf_mc.var/2; best_of_kind_me.push_back( me ); } } } else if (picture.pict_type==B_TYPE) { /* FRAME modes: always possible */ // Forward motion estimates mb_me_search( eparams, picture.fwd_org[0],picture.fwd_rec[0],0,&ssmb, eparams.phy_width,i,j,picture.sxf,picture.syf, 16,eparams.enc_width,eparams.enc_height, &framef_mc ); framef_mc.fieldoff = 0; // Backword motion estimates... mb_me_search( eparams, picture.bwd_org[0],picture.bwd_rec[0],0,&ssmb, eparams.phy_width, i,j,picture.sxb,picture.syb, 16, eparams.enc_width, eparams.enc_height, &frameb_mc); frameb_mc.fieldoff = 0; me.motion_type = MC_FRAME; me.MV[0][0][0] = framef_mc.pos.x - (i<<1); me.MV[0][0][1] = framef_mc.pos.y - (j<<1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -