/*****************************************************************************
 *
 * This software module was originally developed by
 *
 *   Dietmar Zaig (Siemens AG / ACTS-MoMuSyS)
 *
 * and edited by
 * 
 *   Fernando Jaureguizar (UPM / ACTS-MoMuSyS)
 *   Bob Eifrig (NextLevel Systems)
 *
 * in the course of development of the MPEG-4 Video (ISO/IEC 14496-2) standard.
 * This software module is an implementation of a part of one or more MPEG-4
 * Video (ISO/IEC 14496-2) tools as specified by the MPEG-4 Video (ISO/IEC
 * 14496-2) standard.
 *
 * ISO/IEC gives users of the MPEG-4 Video (ISO/IEC 14496-2) standard free
 * license to this software module or modifications thereof for use in hardware
 * or software products claiming conformance to the MPEG-4 Video (ISO/IEC
 * 14496-2) standard.
 *
 * Those intending to use this software module in hardware or software products
 * are advised that its use may infringe existing patents. The original
 * developer of this software module and his/her company, the subsequent
 * editors and their companies, and ISO/IEC have no liability for use of this
 * software module or modifications thereof in an implementation. Copyright is
 * not released for non MPEG-4 Video (ISO/IEC 14496-2) Standard conforming
 * products.
 *
 * ACTS-MoMuSys partners retain full right to use the code for his/her own
 * purpose, assign or donate the code to a third party and to inhibit third
 * parties from using the code for non MPEG-4 Video (ISO/IEC 14496-2) Standard
 * conforming products. This copyright notice must be included in all copies or
 * derivative works.
 *
 * Copyright (c) 1996
 *
 *****************************************************************************/

/***********************************************************HeaderBegin*******
 *
 * File:        mot_decode.c
 *
 * Author:      Siemens AG - Dietmar Zaig
 * Created:     03.08.96
 *
 * Description: Includes functions needed for the Motion Vector encoding
 *              process. Two of them are also used in the motion estima-
 *              tion, while finding the predicted motion vector
 *
 * Notes:       Based on tmndecode, (C) 1995 Telenor R&D
 *
 * Modified:
 *      Version 1.0: used no shape information
 *      Version 1.1: used inform. about transparent blocks on MB level
 *      Version 1.2: used inform. about transparent blocks on block level.
 *                   Included new rules defined in 3.3.2.7
 *      Version 2.1: motion decoding according to VM 2.1 (without B-Vops)
 *      10.09.96 F. Jaureguizar: Reformatted to make the code more readable.
 *      18.09.96 F. Jaureguizar: Now new B_TRANSP and MB_TRANSP
 *               defines are in mot_util.h. Their calls are modified.
 *      01.05.97 Luis Ducla-Soares: Changes to allow 1D prediction
 *               used in error resilient mode and to set the predictions
 *               to zero after resync markers.
 *      14.05.97 F. Jaureguizar: new commentaries about new f_code
 *               range according to VM7.0
 *      21.05.97 A. Pacheco (UPM): Modifications in several functions
 *               to have just one function to compute the MVs prediction
 *               in both encoder/decoder (find_pmvs). Deletetion of the
 *               old find_pmv, moved to mot_util.c, and modified.
 *      16.06.97 Angel Pacheco: unified the TRANSPARENT modes.
 *      09.03.98 Fernando Jaureguizar: New formating.
 *
 ***********************************************************HeaderEnd*********/

/************************    INCLUDE FILES    ********************************/
 
#include "momusys.h"
#include "mom_bitstream_d.h"
#include "mot_decode.h"
#include "mot_util.h"

/***********************************************************CommentBegin******
 * 
 * -- DecodeMBVec -- 
 *
 * Author :
 *      
 *
 * Created :
 *      
 *
 * Purpose :
 *      Calculates a component of a block (or MB) vector by decoding 
 *      the magnitude & residual of the diff. vector, making the prediction, 
 *      and combining the decoded diff. and the predicted values
 *
 * Arguments in :
 *      Image       *mot,            x/y-motion vector field
 *      Image       *B_decisions,    field with number of vectors per MB
 *                                   (needed for prediction)
 *      Bitstream   *vop_bitstream,  bitstream to be parsed
 *      Trace       *trace,
 *      Int         xpos,            xpos of MB in multiples of 16 (0,..,w-1)
 *      Int         ypos,            ypos of MB in multiples of 16 (0,..,h-1)
 *      Int         block,           0 if one vector per MB, 1..4 else
 *      Int         f_code,          f_code for curretn Vop
 *
 * Arguments out :
 *      Int         *error_flag      set if an error occured
 *
 * Return values  : 
 *      Reconstructed vector component [ in half-pixels units ]    
 *      0 if an error occured
 *
 * Side effects :
 *
 *
 * Description :
 *
 *
 * See also :
 *
 *
 * Modified :
 *      01.05.97 Luis Ducla-Soares: Changes to set the prediction to zero after
 *               a resync marker. This is needed in the error resilient mode.
 *      21.05.97 Angel Pacheco: Interface changes to use one call for decoding
 *               at the same time mvx and mvy (needed to unify the predictors
 *               in both encoder and decoder).
 *      24.09.97 Noel Brady : added MB_decisions to paramter list and passed
 *               it into find_pmvs()
 *      01.12.97 Noel Brady : added arbitrary shape flag
 *      10.12.97 Luis Ducla-Soares: removed 'after_marker' from the
 *               arguments list.
 *      12.12.97 Bob Eifrig: added code for vertical field MV
 *
 ***********************************************************CommentEnd********/

Int
DecodeMBVec(
   Image       *mot_x,
   Image       *mot_y,
   Image       *MB_decisions,  /* MVP/Noel */
   Image       *B_decisions,
   Bitstream   *vop_bitstream, 
   Trace       *trace,
   Int         xpos,
   Int         ypos,
   Int         block,
   Int         f_code,
   Int         error_res_disable,
   Int         *error_flag,
   Float       *mv_x,       /* pixel units */
   Float       *mv_y,       /* pixel units */
   Int         **slice_nb,
   Int         arbitrary_shape
   )

{
  Int   pmvx=0, pmvy=0, mvx=0, mvy=0, 
        residualx=0, residualy=0, 
        vlc_code_magx=0, vlc_code_magy=0;
  Int   mbmode;

  /* decode component x */
  vlc_code_magx = VlcDecMV(vop_bitstream , error_flag , trace);
  if (*error_flag)
    return 0;

  if ( (f_code > 1) && (vlc_code_magx!=0) )
    residualx= BitstreamReadBits(vop_bitstream, f_code-1, "MV residual",
                                  trace, CODE);
  else
    residualx=0;

  /* decode component y */ 
  vlc_code_magy = VlcDecMV(vop_bitstream , error_flag , trace);
  if (*error_flag)
    return 0;    
 
  if ( (f_code > 1) && (vlc_code_magy!=0) )
    residualy= BitstreamReadBits(vop_bitstream, f_code-1, "MV residual",
                                  trace, CODE);
  else   
    residualy=0; 

  /* make prediction */
  if (error_res_disable)
    {
    /* MVP/Noel */
    find_pmvs(mot_x, mot_y, MB_decisions, B_decisions, xpos, ypos,
              block, MBM_TRANSPARENT, error_flag, &pmvx, &pmvy);
    }
  else
    {
    find_pmvsErrRes(mot_x, mot_y, MB_decisions, B_decisions, xpos, ypos, 
                    block, MBM_TRANSPARENT, error_flag, &pmvx, &pmvy, slice_nb,
                    arbitrary_shape);
    }

  if (*error_flag)
    return 0;

  /* descale */
  DeScaleMVD(f_code, residualx, vlc_code_magx, pmvx, &mvx);
  mbmode = ((SInt *)GetImageData(MB_decisions))[xpos +
                                             ypos*GetImageSizeX(MB_decisions)];
  if ((mbmode >= MBM_FIELD00) && (mbmode <= MBM_FIELD11))
    {
    DeScaleMVD(f_code, residualy, vlc_code_magy, 0, &mvy);
    mvy = 2 * (mvy + pmvy / 2);
    }
  else
    DeScaleMVD(f_code, residualy, vlc_code_magy, pmvy, &mvy);

  *mv_x=((Float)mvx)/2;
  *mv_y=((Float)mvy)/2;
  
  return 1;
}

/***********************************************************CommentBegin******
 *
 * -- DeScaleMVD -- Makes the inverse scaling in the MVD component acording
 *                  to the MV range
 *
 * Author :        
 *      UPM - Fernando Jaureguizar
 *
 * Created :        
 *      08.05.96
 *
 * Purpose :        
 *      Makes the inverse scaling of a Motion Vector Difference (MVD)
 *      component (x or y) according to the MV range. The maximum range that
 *      can be represented is determined by the f_code encoded in the VOP
 *      header.
 *      The MV component is obtained adding the computed MVD component and
 *      the input MV Prediction component. This MV component is corrected
 *      to fall in the correct range in half pixel units.
 * 
 * Arguments in :     
 *      Int f_code,        MV range in 1/2 units: 1=32,2=64,...,7=2048
 *      Int residual,      FLC coded part from the scaled MV Difference
 *      Int vlc_code_mag,  VLC coded part from the scaled MV Difference
 *      Int pred_vector,   MV Prediction component in 1/2 units
 *
 * Arguments in/out :    
 *
 *
 * Arguments out :    
 *      Int *vector,       Obtained MV component in 1/2 units
 *
 * Return values :    
 *      none
 *
 * Side effects :    
 *    
 *
 * Description :    
 *     1) The MV Diff. component is obtained from the code_mag and from
 *        the residual, according to the f_code.
 *     2) The MV Diff. component is added to the MV Prediction componet to
 *        obtain the MV component.
 *     3) The MV component is inverse scaled to fall in the correct range.
 *
 * See also :
 *    
 *
 * Modified :        
 *      11.05.96 Fernando Jaureguizar: New input (PMV) and output (MV)
 *               Reconstructed MV component is computed inside this function.
 *    
 ***********************************************************CommentEnd********/

Void
DeScaleMVD (
   Int  f_code,       /* <-- MV range in 1/2 units: 1=32,2=64,...,7=2048     */
   Int  residual,     /* <-- part of the MV Diff. FLC coded                  */
   Int  vlc_code_mag, /* <-- part of the MV Diff. VLC coded                  */
   Int  pred_vector,  /* <-- MV Prediction component in 1/2 units            */
   Int  *vector       /* --> Obtained MV component in 1/2 units              */
   )
{
  Int   range;
  Int   scale_factor;
  Int   r_size;
  Int   low;
  Int   high;
  Int   diff_vector;

  r_size = f_code-1;
  scale_factor = 1<<r_size;
  range = 32*scale_factor;
  low   = -range;
  high  =  range-1;

  if (scale_factor==1 || vlc_code_mag==0)
    diff_vector = vlc_code_mag;
  else
    {
    diff_vector = ((ABS(vlc_code_mag)-1)<<r_size) + residual + 1;
    if (vlc_code_mag < 0)
      diff_vector = -diff_vector;
    }

  *vector = pred_vector + diff_vector;

  if (*vector < low)
    *vector += 2*range;
  else if (*vector > high)
    *vector -= 2*range;
}
