📄 motionest.cc
字号:
/* motionest.cc, motion estimation *//* Copyright (C) 1996, MPEG Software Simulation Group. All Rights Reserved. *//* * Disclaimer of Warranty * * These software programs are available to the user without any license fee or * royalty on an "as is" basis. The MPEG Software Simulation Group disclaims * any and all warranties, whether express, implied, or statuary, including any * implied warranties or merchantability or of fitness for a particular * purpose. In no event shall the copyright-holder be liable for any * incidental, punitive, or consequential damages of any kind whatsoever * arising from the use of these programs. * * This disclaimer of warranty extends to the user of these programs and user's * customers, employees, agents, transferees, successors, and assigns. * * The MPEG Software Simulation Group does not represent or warrant that the * programs furnished hereunder are free of infringement of any third-party * patents. * * Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, * are subject to royalty fees to patent holders. Many of these patents are * general enough such that they are unavoidable regardless of implementation * design. * *//* Modifications and enhancements (C) 2000-2004 Andrew Stevens *//* These modifications are free software; you can redistribute it * and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <cassert>#include <math.h>#include <mpeg2syntaxcodes.h>#include "cpu_accel.h"#include "simd.h"#include "fastintfns.h"#include "motionsearch.h"#include "mjpeg_logging.h"#include "encoderparams.hh"#include "picture.hh"/* See ISO13818-2 7.6.3.5 */int dualprime_m[FieldOrder::dim][Parity::dim /*ref*/][Parity::dim /*pred*/] ={ { { 2, 1 }, { 3, 2 } }, // Botfield first { { 2, 3 }, { 1, 2 } } // Topfield first};int dualprime_e[Parity::dim /*ref*/ ][Parity::dim /*pred*/ ] ={ { 0, +1 }, { -1, 0 }}; /* Macro-block Motion estimation results record */struct MotionCand{ Coord pos; // Half-pel co-ormv[1]dinates of source block int sad; // Sum of absolute difference int var; uint8_t *blk ; // Source block data (in luminace data array) int hx, hy; // Half-pel offsets int fieldsel; // 0 = top 1 = bottom int fieldoff; // Offset from start of frame data to first line // of field. (top = 0, bottom = width );};struct SubSampledImg{ uint8_t *mb; // One pel uint8_t *fmb; // Two-pel subsampled uint8_t *qmb; // Four-pel subsampled uint8_t *umb; // U compoenent one-pel uint8_t *vmb; // V component one-pel};/* Main field and frame based motion estimation entry points.*/static void field_estimate (const Picture &picture, uint8_t *toporg, uint8_t *topref, uint8_t *botorg, uint8_t *botref, SubSampledImg *ssmb, int i, int j, int sx, int sy, MotionCand *bestfr, MotionCand *best8u, MotionCand *best8l, MotionCand *bestsp);static void mb_me_search ( const EncoderParams &eparams, uint8_t *org, uint8_t *ref, int fieldoff, SubSampledImg *ssblk, int lx, int i0, int j0, int sx, int sy, int h, int xmax, int ymax, MotionCand *motion );inline int mv_coding_penalty( int mv_x, int mv_y ){ return (abs(mv_x) + abs(mv_y))<<3;}/* * Compute subsampled images for fast motion compensation search * N.b. Sub-sampling works correctly if we treat interlaced images * as two half-height images side-by-side. *//* * Compute the variance of the residual of uni-directionally motion * compensated block. * */static inline int unidir_pred_var( const MotionCand *motion, uint8_t *mb, int lx, int h){ return psumsq(motion->blk, mb, lx, motion->hx, motion->hy, h);}/* * Compute the variance of the residual of bi-directionally motion * compensated block. */static inline int bidir_pred_var( const MotionCand *motion_f, const MotionCand *motion_b, uint8_t *mb, int lx, int h){ return pbsumsq( motion_f->blk, motion_b->blk, mb, lx, motion_f->hx, motion_f->hy, motion_b->hx, motion_b->hy, h);}/* unidir_var_sum * * Compute the combined variance of luminance and * chrominance information for a particular non-intra macro block * after unidirectional motion estimation... * * Note: results are scaled to give chrominance equal weight to * chrominance. The variance of the luminance portion is computed * at the time the motion estimation is computed. * * TODO: Perhaps we should compute the whole thing in mb_mc_search * not seperate it. However, that would involve a lot of fiddling * with field_* and until its thoroughly debugged and tested I think * I'll leave that alone. Furthermore, it is unclear if its really * worth * doing these computations for B *and* P frames. * * TODO: BUG: ONLY works for 420 video... * */static int unidir_var_sum( MotionCand *lum_mc, uint8_t **ref, SubSampledImg *ssblk, int lx, int h ){ int uvlx = (lx>>1); int uvh = (h>>1); /* N.b. MC co-ordinates are computed in half-pel units! */ int cblkoffset = (lum_mc->fieldoff>>1) + (lum_mc->pos.x>>2) + (lum_mc->pos.y>>2)*uvlx; return lum_mc->var + (psumsq_sub22( ref[1] + cblkoffset, ssblk->umb, uvlx, uvh) + psumsq_sub22( ref[2] + cblkoffset, ssblk->vmb, uvlx, uvh));}/* * bidir_var_sum * Compute the combined variance of luminance and chrominance information * for a particular non-intra macro block after bidirectional * motion estimation... * * Note: results are scaled to give chrominance equal weight to * chrominance. The variance of the luminance portion is computed * at the time the motion estimation is computed. * * Note: results scaled to give chrominance equal weight to chrominance. * * TODO: BUG: ONLY works for 420 video... * * NOTE: Currently unused but may be required if it turns out that taking * chrominance into account in B frames is needed. * */static int bidir_var_sum( MotionCand *lum_mc_f, MotionCand *lum_mc_b, uint8_t **ref_f, uint8_t **ref_b, SubSampledImg *ssblk, int lx, int h ){ int uvlx = (lx>>1); int uvh = (h>>1); /* N.b. MC co-ordinates are computed in half-pel units! */ int cblkoffset_f = (lum_mc_f->fieldoff>>1) + (lum_mc_f->pos.x>>2) + (lum_mc_f->pos.y>>2)*uvlx; int cblkoffset_b = (lum_mc_b->fieldoff>>1) + (lum_mc_b->pos.x>>2) + (lum_mc_b->pos.y>>2)*uvlx; return ( pbsumsq( lum_mc_f->blk, lum_mc_b->blk, ssblk->mb, lx, lum_mc_f->hx, lum_mc_f->hy, lum_mc_b->hx, lum_mc_b->hy, h) + pbsumsq_sub22( ref_f[1] + cblkoffset_f, ref_b[1] + cblkoffset_b, ssblk->umb, uvlx, uvh ) + pbsumsq_sub22( ref_f[2] + cblkoffset_f, ref_b[2] + cblkoffset_b, ssblk->vmb, uvlx, uvh ));}/* * Sum of chrominance variance of a block. */static inline int chrom_var_sum( SubSampledImg *ssblk, int h, int lx ){ uint32_t var1, var2, dummy_mean; assert( (h>>1) == 8 || (h>>1) == 16 ); pvariance(ssblk->umb,(h>>1),(lx>>1), &var1, &dummy_mean); pvariance(ssblk->vmb,(h>>1),(lx>>1), &var2, &dummy_mean); return (var1+var2)*2;}/* * Compute SAD for bi-directionally motion compensated blocks... */static inline int bidir_pred_sad( const MotionCand *motion_f, const MotionCand *motion_b, uint8_t *mb, int lx, int h){ return pbsad(motion_f->blk, motion_b->blk, mb, lx, motion_f->hx, motion_f->hy, motion_b->hx, motion_b->hy, h);}#ifdef DEBUG_MCstatic void display_mb(MotionCand *lum_mc, uint8_t **ref, SubSampledImg *ssblk, int lx, int h ){ int x,y; int sum = 0; int uvlx = (lx>>1); int uvh = (h>>1); /* N.b. MC co-ordinates are computed in half-pel units! */ int lblkoffset = lum_mc->fieldoff + (lum_mc->pos.x>>1) + (lum_mc->pos.y>>1)*lx; /*int cblkoffset = (lum_mc->fieldoff>>1) + (lum_mc->pos.x>>2) + (lum_mc->pos.y>>2)*uvlx;*/ fprintf(stderr, "ref[0] = %08x (%d,%d) width=%d reconbase = %08x blk =%08x\n", (int)ref[0], (lum_mc->pos.x>>1), (lum_mc->pos.y>>1), lx, (int)(ref[0]+lblkoffset), (int)(lum_mc->blk) ); for( y = 0; y < 16; ++y ) { for( x = 0; x< 16; ++x ) { int diff = *(ref[0]+lblkoffset+x+y*lx)-*(ssblk->mb+x+y*lx); sum += diff*diff; fprintf( stderr,"%04d ", diff ); } fprintf(stderr,"\n"); } fprintf(stderr, "sumsq = %d [%d] (%d)\n", sum, lum_mc->var, unidir_pred_var(lum_mc, ssblk->mb, lx, h) ); }#endifvoid FieldMotionCands( const EncoderParams &eparams, uint8_t *org, uint8_t *ref, SubSampledImg *topssmb, SubSampledImg *botssmb, int i, int j, int sx, int sy, MotionCand *besttop, MotionCand *bestbot, MotionCand (&fieldmcs)[2][2] ){ /* predict top field from top field */ mb_me_search( eparams, org,ref,0,topssmb, eparams.phy_width<<1,i,j>>1,sx,sy>>1,8, eparams.enc_width,eparams.enc_height>>1, &fieldmcs[Parity::top][Parity::top]); /* predict top field from bottom field */ mb_me_search( eparams, org,ref,eparams.phy_width,topssmb, eparams.phy_width<<1,i,j>>1,sx,sy>>1,8, eparams.enc_width,eparams.enc_height>>1, &fieldmcs[Parity::bot][Parity::top]); /* set correct field selectors... */ // TODO fieldset and fieldoff are redundant. Use only fieldoff // and derive fieldset as fieldoff != 0 fieldmcs[Parity::top][Parity::top].fieldsel = 0; fieldmcs[Parity::bot][Parity::top].fieldsel = 1; fieldmcs[Parity::top][Parity::top].fieldoff = 0; fieldmcs[Parity::bot][Parity::top].fieldoff = eparams.phy_width; /* select prediction for top field */ if (fieldmcs[Parity::top][Parity::top].sad<=fieldmcs[Parity::bot][Parity::top].sad) { *besttop = fieldmcs[Parity::top][Parity::top]; } else { *besttop = fieldmcs[Parity::bot][Parity::top]; } /* predict bottom field from top field */ mb_me_search( eparams, org,ref,0,botssmb, eparams.phy_width<<1,i,j>>1,sx,sy>>1,8, eparams.enc_width,eparams.enc_height>>1, &fieldmcs[Parity::top][Parity::bot]); /* predict bottom field from bottom field */ mb_me_search( eparams, org,ref,eparams.phy_width,botssmb, eparams.phy_width<<1,i,j>>1,sx,sy>>1,8, eparams.enc_width,eparams.enc_height>>1, &fieldmcs[Parity::bot][Parity::bot]); /* set correct field selectors... */ fieldmcs[Parity::top][Parity::bot].fieldsel = 0; fieldmcs[Parity::bot][Parity::bot].fieldsel = 1; fieldmcs[Parity::top][Parity::bot].fieldoff = 0; fieldmcs[Parity::bot][Parity::bot].fieldoff = eparams.phy_width; /* select prediction for bottom field */ if (fieldmcs[Parity::bot][Parity::bot].sad<=fieldmcs[Parity::top][Parity::bot].sad) { *bestbot = fieldmcs[Parity::bot][Parity::bot]; } else { *bestbot = fieldmcs[Parity::top][Parity::bot]; }}typedef int (*DualPrimeMeasure)( uint8_t *sameref, uint8_t *crossref, uint8_t *pred_mb, int field_stride, int same_fx, int same_fy, int cross_fx, int cross_fy, int h );bool DualPrimeMetric( const Picture &picture, DualPrimeMeasure meas, const Coord &same, const Coord (&crossblks)[Parity::dim], // Cross-field ref const MotionVector &dmv, uint8_t *ref, uint8_t *pred_mb, int stride, int &measure ){ bool all_legal = true; Coord cross; int part_meas = 0; // Base MV is out-of-range if( ! picture.InRangeFieldMVRef( same ) ) return false; for( int ppred = Parity::top; ppred <= Parity::bot; ++ppred ) { int same_fieldoff = (ppred == Parity::top ? 0 : stride); Coord cross(crossblks[Parity::Invert(ppred)],dmv); int cross_fieldoff = stride - same_fieldoff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -