//-------------------------------------------------------------------------
PVideoFrame __stdcall MVFlowInter::GetFrame(int n, IScriptEnvironment* env)
{
   PVideoFrame dst;
   BYTE *pDst[3];
	const BYTE *pRef[3], *pSrc[3];
    int nDstPitches[3], nRefPitches[3], nSrcPitches[3];
	unsigned char *pDstYUY2;
	int nDstPitchYUY2;

   int off = mvClipB.GetDeltaFrame(); // integer offset of reference frame

	PVideoFrame mvF = mvClipF.GetFrame(n+off, env);
  mvClipF.Update(mvF, env);// forward from current to next
  mvF = 0;
	PVideoFrame mvB = mvClipB.GetFrame(n, env);
   mvClipB.Update(mvB, env);// backward from next to current
   mvB = 0;

//   int sharp = mvClipB.GetSharp();
	PVideoFrame	src	= finest->GetFrame(n, env);
		PVideoFrame ref = finest->GetFrame(n+off, env);//  ref for  compensation
		dst = env->NewVideoFrame(vi);

   if ( mvClipB.IsUsable()  && mvClipF.IsUsable() )
   {
		if ( (pixelType & VideoInfo::CS_YUY2) == VideoInfo::CS_YUY2 )
		{
            // planar data packed to interleaved format (same as interleved2planar by kassandro) - v2.0.0.5
            pSrc[0] = src->GetReadPtr();
            pSrc[1] = pSrc[0] + src->GetRowSize()/2;
            pSrc[2] = pSrc[1] + src->GetRowSize()/4;
            nSrcPitches[0] = src->GetPitch();
            nSrcPitches[1] = nSrcPitches[0];
            nSrcPitches[2] = nSrcPitches[0];
            // planar data packed to interleaved format (same as interleved2planar by kassandro) - v2.0.0.5
            pRef[0] = ref->GetReadPtr();
            pRef[1] = pRef[0] + ref->GetRowSize()/2;
            pRef[2] = pRef[1] + ref->GetRowSize()/4;
            nRefPitches[0] = ref->GetPitch();
            nRefPitches[1] = nRefPitches[0];
            nRefPitches[2] = nRefPitches[0];

            if (!planar)
            {
			pDstYUY2 = dst->GetWritePtr();
			nDstPitchYUY2 = dst->GetPitch();
			pDst[0] = DstPlanes->GetPtr();
			pDst[1] = DstPlanes->GetPtrU();
			pDst[2] = DstPlanes->GetPtrV();
			nDstPitches[0]  = DstPlanes->GetPitch();
			nDstPitches[1]  = DstPlanes->GetPitchUV();
			nDstPitches[2]  = DstPlanes->GetPitchUV();
			}
			else
			{
                pDst[0] = dst->GetWritePtr();
                pDst[1] = pDst[0] + dst->GetRowSize()/2;
                pDst[2] = pDst[1] + dst->GetRowSize()/4;;
                nDstPitches[0] = dst->GetPitch();
                nDstPitches[1] = nDstPitches[0];
                nDstPitches[2] = nDstPitches[0];
			}
		}
		else
		{
         pDst[0] = YWPLAN(dst);
         pDst[1] = UWPLAN(dst);
         pDst[2] = VWPLAN(dst);
         nDstPitches[0] = YPITCH(dst);
         nDstPitches[1] = UPITCH(dst);
         nDstPitches[2] = VPITCH(dst);

         pRef[0] = YRPLAN(ref);
         pRef[1] = URPLAN(ref);
         pRef[2] = VRPLAN(ref);
         nRefPitches[0] = YPITCH(ref);
         nRefPitches[1] = UPITCH(ref);
         nRefPitches[2] = VPITCH(ref);

         pSrc[0] = YRPLAN(src);
         pSrc[1] = URPLAN(src);
         pSrc[2] = VRPLAN(src);
         nSrcPitches[0] = YPITCH(src);
         nSrcPitches[1] = UPITCH(src);
         nSrcPitches[2] = VPITCH(src);
		}

    int nOffsetY = nRefPitches[0] * nVPadding*nPel + nHPadding*nPel;
    int nOffsetUV = nRefPitches[1] * nVPaddingUV*nPel + nHPaddingUV*nPel;


	  // make  vector vx and vy small masks
	 // 1. ATTENTION: vectors are assumed SHORT (|vx|, |vy| < 127) !
	 // 2. they will be zeroed if not
	// 3. added 128 to all values
	MakeVectorSmallMasks(mvClipB, nBlkX, nBlkY, VXSmallYB, nBlkXP, VYSmallYB, nBlkXP);
	MakeVectorSmallMasks(mvClipF, nBlkX, nBlkY, VXSmallYF, nBlkXP, VYSmallYF, nBlkXP);
	if (nBlkXP > nBlkX) // fill right
	{
		for (int j=0; j<nBlkY; j++)
		{
			VXSmallYB[j*nBlkXP + nBlkX] = min(VXSmallYB[j*nBlkXP + nBlkX-1],128);
			VYSmallYB[j*nBlkXP + nBlkX] = VYSmallYB[j*nBlkXP + nBlkX-1];
			VXSmallYF[j*nBlkXP + nBlkX] = min(VXSmallYF[j*nBlkXP + nBlkX-1],128);
			VYSmallYF[j*nBlkXP + nBlkX] = VYSmallYF[j*nBlkXP + nBlkX-1];
		}
	}
	if (nBlkYP > nBlkY) // fill bottom
	{
		for (int i=0; i<nBlkXP; i++)
		{
			VXSmallYB[nBlkXP*nBlkY +i] = VXSmallYB[nBlkXP*(nBlkY-1) +i];
			VYSmallYB[nBlkXP*nBlkY +i] = min(VYSmallYB[nBlkXP*(nBlkY-1) +i],128);
			VXSmallYF[nBlkXP*nBlkY +i] = VXSmallYF[nBlkXP*(nBlkY-1) +i];
			VYSmallYF[nBlkXP*nBlkY +i] = min(VYSmallYF[nBlkXP*(nBlkY-1) +i],128);
		}
	}
	VectorSmallMaskYToHalfUV(VXSmallYB, nBlkXP, nBlkYP, VXSmallUVB, 2);
	VectorSmallMaskYToHalfUV(VYSmallYB, nBlkXP, nBlkYP, VYSmallUVB, yRatioUV);
	VectorSmallMaskYToHalfUV(VXSmallYF, nBlkXP, nBlkYP, VXSmallUVF, 2);
	VectorSmallMaskYToHalfUV(VYSmallYF, nBlkXP, nBlkYP, VYSmallUVF, yRatioUV);

	  // analyse vectors field to detect occlusion
//	  double occNormB = (256-time256)/(256*ml);
	MakeVectorOcclusionMaskTime(mvClipB, nBlkX, nBlkY, ml, 1.0, nPel, MaskSmallB, nBlkXP, (256-time256), nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
//	  double occNormF = time256/(256*ml);
	MakeVectorOcclusionMaskTime(mvClipF, nBlkX, nBlkY, ml, 1.0, nPel, MaskSmallF, nBlkXP, time256, nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
	if (nBlkXP > nBlkX) // fill right
	{
		for (int j=0; j<nBlkY; j++)
		{
			MaskSmallB[j*nBlkXP + nBlkX] = MaskSmallB[j*nBlkXP + nBlkX-1];
			MaskSmallF[j*nBlkXP + nBlkX] = MaskSmallF[j*nBlkXP + nBlkX-1];
		}
	}
	if (nBlkYP > nBlkY) // fill bottom
	{
		for (int i=0; i<nBlkXP; i++)
		{
			MaskSmallB[nBlkXP*nBlkY +i] = MaskSmallB[nBlkXP*(nBlkY-1) +i];
			MaskSmallF[nBlkXP*nBlkY +i] = MaskSmallF[nBlkXP*(nBlkY-1) +i];
		}
	}
	  // upsize (bilinear interpolate) vector masks to fullframe size


	  int dummyplane = PLANAR_Y; // use luma plane resizer code for all planes if we resize from luma small mask
	  upsizer->SimpleResizeDo(VXFullYB, nWidthP, nHeightP, VPitchY, VXSmallYB, nBlkXP, nBlkXP, dummyplane);
	  upsizer->SimpleResizeDo(VYFullYB, nWidthP, nHeightP, VPitchY, VYSmallYB, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VXFullUVB, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVB, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VYFullUVB, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVB, nBlkXP, nBlkXP, dummyplane);

	  upsizer->SimpleResizeDo(VXFullYF, nWidthP, nHeightP, VPitchY, VXSmallYF, nBlkXP, nBlkXP, dummyplane);
	  upsizer->SimpleResizeDo(VYFullYF, nWidthP, nHeightP, VPitchY, VYSmallYF, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VXFullUVF, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVF, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VYFullUVF, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVF, nBlkXP, nBlkXP, dummyplane);

    upsizer->SimpleResizeDo(MaskFullYB, nWidthP, nHeightP, VPitchY, MaskSmallB, nBlkXP, nBlkXP, dummyplane);
	upsizerUV->SimpleResizeDo(MaskFullUVB, nWidthPUV, nHeightPUV, VPitchUV, MaskSmallB, nBlkXP, nBlkXP, dummyplane);

    upsizer->SimpleResizeDo(MaskFullYF, nWidthP, nHeightP, VPitchY, MaskSmallF, nBlkXP, nBlkXP, dummyplane);
	upsizerUV->SimpleResizeDo(MaskFullUVF, nWidthPUV, nHeightPUV, VPitchUV, MaskSmallF, nBlkXP, nBlkXP, dummyplane);


    // Get motion info from more frames for occlusion areas
	PVideoFrame mvFF = mvClipF.GetFrame(n, env);
    mvClipF.Update(mvFF, env);// forward from prev to cur
    mvFF = 0;
	PVideoFrame mvBB = mvClipB.GetFrame(n+off, env);
    mvClipB.Update(mvBB, env);// backward from next next to next
    mvBB = 0;

   if ( mvClipB.IsUsable()  && mvClipF.IsUsable() )
   {
    // get vector mask from extra frames
	MakeVectorSmallMasks(mvClipB, nBlkX, nBlkY, VXSmallYBB, nBlkXP, VYSmallYBB, nBlkXP);
	MakeVectorSmallMasks(mvClipF, nBlkX, nBlkY, VXSmallYFF, nBlkXP, VYSmallYFF, nBlkXP);
	if (nBlkXP > nBlkX) // fill right
	{
		for (int j=0; j<nBlkY; j++)
		{
			VXSmallYBB[j*nBlkXP + nBlkX] = min(VXSmallYBB[j*nBlkXP + nBlkX-1],128);
			VYSmallYBB[j*nBlkXP + nBlkX] = VYSmallYBB[j*nBlkXP + nBlkX-1];
			VXSmallYFF[j*nBlkXP + nBlkX] = min(VXSmallYFF[j*nBlkXP + nBlkX-1],128);
			VYSmallYFF[j*nBlkXP + nBlkX] = VYSmallYFF[j*nBlkXP + nBlkX-1];
		}
	}
	if (nBlkYP > nBlkY) // fill bottom
	{
		for (int i=0; i<nBlkXP; i++)
		{
			VXSmallYBB[nBlkXP*nBlkY +i] = VXSmallYBB[nBlkXP*(nBlkY-1) +i];
			VYSmallYBB[nBlkXP*nBlkY +i] = min(VYSmallYBB[nBlkXP*(nBlkY-1) +i],128);
			VXSmallYFF[nBlkXP*nBlkY +i] = VXSmallYFF[nBlkXP*(nBlkY-1) +i];
			VYSmallYFF[nBlkXP*nBlkY +i] = min(VYSmallYFF[nBlkXP*(nBlkY-1) +i],128);
		}
	}
	VectorSmallMaskYToHalfUV(VXSmallYBB, nBlkXP, nBlkYP, VXSmallUVBB, 2);
	VectorSmallMaskYToHalfUV(VYSmallYBB, nBlkXP, nBlkYP, VYSmallUVBB, yRatioUV);
	VectorSmallMaskYToHalfUV(VXSmallYFF, nBlkXP, nBlkYP, VXSmallUVFF, 2);
	VectorSmallMaskYToHalfUV(VYSmallYFF, nBlkXP, nBlkYP, VYSmallUVFF, yRatioUV);

    // upsize vectors to full frame
	  upsizer->SimpleResizeDo(VXFullYBB, nWidthP, nHeightP, VPitchY, VXSmallYBB, nBlkXP, nBlkXP, dummyplane);
	  upsizer->SimpleResizeDo(VYFullYBB, nWidthP, nHeightP, VPitchY, VYSmallYBB, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VXFullUVBB, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVBB, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VYFullUVBB, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVBB, nBlkXP, nBlkXP, dummyplane);

	  upsizer->SimpleResizeDo(VXFullYFF, nWidthP, nHeightP, VPitchY, VXSmallYFF, nBlkXP, nBlkXP, dummyplane);
	  upsizer->SimpleResizeDo(VYFullYFF, nWidthP, nHeightP, VPitchY, VYSmallYFF, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VXFullUVFF, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVFF, nBlkXP, nBlkXP, dummyplane);
	  upsizerUV->SimpleResizeDo(VYFullUVFF, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVFF, nBlkXP, nBlkXP, dummyplane);

			FlowInterExtra(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, pSrc[0] + nOffsetY, nRefPitches[0],
				VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
				nWidth, nHeight, time256, nPel, LUTVB, LUTVF, VXFullYBB, VXFullYFF, VYFullYBB, VYFullYFF);
			FlowInterExtra(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, pSrc[1] + nOffsetUV, nRefPitches[1],
				VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
				nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);
			FlowInterExtra(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, pSrc[2] + nOffsetUV, nRefPitches[2],
				VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
				nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);
   }
   else // bad extra frames, use old method without extra frames
   {
			FlowInter(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, pSrc[0] + nOffsetY, nRefPitches[0],
				VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
				nWidth, nHeight, time256, nPel, LUTVB, LUTVF);
			FlowInter(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, pSrc[1] + nOffsetUV, nRefPitches[1],
				VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
				nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
			FlowInter(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, pSrc[2] + nOffsetUV, nRefPitches[2],
				VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
				nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
   }

		if ( (pixelType & VideoInfo::CS_YUY2) == VideoInfo::CS_YUY2 && !planar)
		{
			YUY2FromPlanes(pDstYUY2, nDstPitchYUY2, nWidth, nHeight,
								  pDst[0], nDstPitches[0], pDst[1], pDst[2], nDstPitches[1], isse);
		}
		return dst;
   }
   else
   {
       // poor estimation

        // prepare pointers
        PVideoFrame src = child->GetFrame(n,env); // it is easy to use child here - v2.0

	if (blend) //let's blend src with ref frames like ConvertFPS
	{
        PVideoFrame ref = child->GetFrame(n+off,env);
         if ( (pixelType & VideoInfo::CS_YUY2) == VideoInfo::CS_YUY2 )
		{
			pSrc[0] = src->GetReadPtr(); // we can blend YUY2
			nSrcPitches[0] = src->GetPitch();
			pRef[0] = ref->GetReadPtr();
			nRefPitches[0]  = ref->GetPitch();
			pDstYUY2 = dst->GetWritePtr();
			nDstPitchYUY2 = dst->GetPitch();
            Blend(pDstYUY2, pSrc[0], pRef[0], nHeight, nWidth*2, nDstPitchYUY2, nSrcPitches[0], nRefPitches[0], time256, isse);
		}
		else
		{
         pDst[0] = YWPLAN(dst);
         pDst[1] = UWPLAN(dst);
         pDst[2] = VWPLAN(dst);
         nDstPitches[0] = YPITCH(dst);
         nDstPitches[1] = UPITCH(dst);
         nDstPitches[2] = VPITCH(dst);

         pRef[0] = YRPLAN(ref);
         pRef[1] = URPLAN(ref);
         pRef[2] = VRPLAN(ref);
         nRefPitches[0] = YPITCH(ref);
         nRefPitches[1] = UPITCH(ref);
         nRefPitches[2] = VPITCH(ref);

         pSrc[0] = YRPLAN(src);
         pSrc[1] = URPLAN(src);
         pSrc[2] = VRPLAN(src);
         nSrcPitches[0] = YPITCH(src);
         nSrcPitches[1] = UPITCH(src);
         nSrcPitches[2] = VPITCH(src);
       // blend with time weight
        Blend(pDst[0], pSrc[0], pRef[0], nHeight, nWidth, nDstPitches[0], nSrcPitches[0], nRefPitches[0], time256, isse);
        Blend(pDst[1], pSrc[1], pRef[1], nHeightUV, nWidthUV, nDstPitches[1], nSrcPitches[1], nRefPitches[1], time256, isse);
        Blend(pDst[2], pSrc[2], pRef[2], nHeightUV, nWidthUV, nDstPitches[2], nSrcPitches[2], nRefPitches[2], time256, isse);
		}
 		return dst;
	}
	else
	{
		return src; // like ChangeFPS
	}
   }

}
//-------------------------------------------------------------------------
PVideoFrame __stdcall MVFlowInter::GetFrame(int n, IScriptEnvironment* env)
{
    PVideoFrame src	= child->GetFrame(n, env);
    PVideoFrame dst = env->NewVideoFrame(vi);

    // convert to frames
    unsigned char *pDst[3];
    int nDstPitches[3];
    DstPlanes->ConvertVideoFrameToPlanes(&dst, pDst, nDstPitches);

    int off = mvClipB.GetDeltaFrame(); // integer offset of reference frame

    // get reference frame
    PVideoFrame ref = child->GetFrame(n+off, env);//  ref for  compensation

    PVideoFrame mvB = mvClipB.GetFrame(n, env);
    mvClipB.Update(mvB, env);// backward from next to current
    PVideoFrame mvF = mvClipF.GetFrame(n+off, env);
    mvClipF.Update(mvF, env);// forward from current to next

    if ( mvClipB.IsUsable()  && mvClipF.IsUsable()) {
        PMVGroupOfFrames pRefGOFF = mvCore->GetFrame(nIdx, n); // forward ref
        PMVGroupOfFrames pRefGOFB = mvCore->GetFrame(nIdx, n + off); // backward ref

        if (!pRefGOFF->IsProcessed()) {
            PVideoFrame src2x;
            pRefGOFF->SetParity(child->GetParity(n));
            if (usePelClipHere) {
                src2x = pelclip->GetFrame(n, env);
            }
            ProcessFrameIntoGroupOfFrames(&pRefGOFF, &src, &src2x, mvClipF.GetSharp(), pixelType, 
                                          nHeight, nWidth, nPel, isse);
        }

        if (!pRefGOFB->IsProcessed()) {
            PVideoFrame ref2x;
            pRefGOFB->SetParity(child->GetParity(n + off));
            if (usePelClipHere) {
                ref2x = pelclip->GetFrame(n+off, env);
            }
            ProcessFrameIntoGroupOfFrames(&pRefGOFB, &ref, &ref2x, mvClipB.GetSharp(), pixelType, 
                                          nHeight, nWidth, nPel, isse);
        }

        MVPlane *pPlanesB[3];
        MVPlane *pPlanesF[3];

        pPlanesB[0] = pRefGOFB->GetFrame(0)->GetPlane(YPLANE);
        pPlanesB[1] = pRefGOFB->GetFrame(0)->GetPlane(UPLANE);
        pPlanesB[2] = pRefGOFB->GetFrame(0)->GetPlane(VPLANE);

        pPlanesF[0] = pRefGOFF->GetFrame(0)->GetPlane(YPLANE);
        pPlanesF[1] = pRefGOFF->GetFrame(0)->GetPlane(UPLANE);
        pPlanesF[2] = pRefGOFF->GetFrame(0)->GetPlane(VPLANE);

        if (nPel>=2) {
            if (usePelClipHere) { // simply padding 2x planes
                PlaneCopy(pel2PlaneYB + nHPadding*nPel + nVPadding*nPel * pel2PitchY, pel2PitchY,
                          pRefGOFB->GetVF2xYPtr(), pRefGOFB->GetVF2xYPitch(), nWidth*nPel, nHeight*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneYB, pel2PitchY, nHPadding*nPel, nVPadding*nPel, nWidth*nPel, 
                                           nHeight*nPel);
                PlaneCopy(pel2PlaneUB + nHPaddingUV*nPel + nVPaddingUV*nPel * pel2PitchUV, pel2PitchUV,
                          pRefGOFB->GetVF2xUPtr(), pRefGOFB->GetVF2xUPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneUB, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
                PlaneCopy(pel2PlaneVB + nHPaddingUV*nPel + nVPaddingUV*nPel * pel2PitchUV, pel2PitchUV,
                          pRefGOFB->GetVF2xVPtr(), pRefGOFB->GetVF2xVPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneVB, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
                PlaneCopy(pel2PlaneYF + nHPadding*nPel + nVPadding*nPel * pel2PitchY, pel2PitchY,
                          pRefGOFF->GetVF2xYPtr(), pRefGOFF->GetVF2xYPitch(), nWidth*nPel, nHeight*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneYB, pel2PitchY, nHPadding*nPel, nVPadding*nPel, nWidth*nPel, 
                                           nHeight*nPel);
                PlaneCopy(pel2PlaneUF + nHPaddingUV*nPel + nVPaddingUV*nPel * pel2PitchUV, pel2PitchUV,
                          pRefGOFF->GetVF2xUPtr(), pRefGOFF->GetVF2xUPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneUB, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
                PlaneCopy(pel2PlaneVF + nHPaddingUV*nPel + nVPaddingUV*nPel * pel2PitchUV, pel2PitchUV,
                          pRefGOFF->GetVF2xVPtr(), pRefGOFF->GetVF2xVPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneVF, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
            }
            else if (nPel==2) {
                // merge refined planes to big single plane
                Merge4PlanesToBig(pel2PlaneYB, pel2PitchY, pPlanesB[0]->GetAbsolutePointer(0,0),
                                  pPlanesB[0]->GetAbsolutePointer(1,0), pPlanesB[0]->GetAbsolutePointer(0,1),
                                  pPlanesB[0]->GetAbsolutePointer(1,1), pPlanesB[0]->GetExtendedWidth(),
                                  pPlanesB[0]->GetExtendedHeight(), pPlanesB[0]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneUB, pel2PitchUV, pPlanesB[1]->GetAbsolutePointer(0,0),
                                  pPlanesB[1]->GetAbsolutePointer(1,0), pPlanesB[1]->GetAbsolutePointer(0,1),
                                  pPlanesB[1]->GetAbsolutePointer(1,1), pPlanesB[1]->GetExtendedWidth(),
                                  pPlanesB[1]->GetExtendedHeight(), pPlanesB[1]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneVB, pel2PitchUV, pPlanesB[2]->GetAbsolutePointer(0,0),
                                  pPlanesB[2]->GetAbsolutePointer(1,0), pPlanesB[2]->GetAbsolutePointer(0,1),
                                  pPlanesB[2]->GetAbsolutePointer(1,1), pPlanesB[2]->GetExtendedWidth(),
                                  pPlanesB[2]->GetExtendedHeight(), pPlanesB[2]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneYF, pel2PitchY, pPlanesF[0]->GetAbsolutePointer(0,0),
                                  pPlanesF[0]->GetAbsolutePointer(1,0), pPlanesF[0]->GetAbsolutePointer(0,1),
                                  pPlanesF[0]->GetAbsolutePointer(1,1), pPlanesF[0]->GetExtendedWidth(),
                                  pPlanesF[0]->GetExtendedHeight(), pPlanesF[0]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneUF, pel2PitchUV, pPlanesF[1]->GetAbsolutePointer(0,0),
                                  pPlanesF[1]->GetAbsolutePointer(1,0), pPlanesF[1]->GetAbsolutePointer(0,1),
                                  pPlanesF[1]->GetAbsolutePointer(1,1), pPlanesF[1]->GetExtendedWidth(),
                                  pPlanesF[1]->GetExtendedHeight(), pPlanesF[1]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneVF, pel2PitchUV, pPlanesF[2]->GetAbsolutePointer(0,0),
                                  pPlanesF[2]->GetAbsolutePointer(1,0), pPlanesF[2]->GetAbsolutePointer(0,1),
                                  pPlanesF[2]->GetAbsolutePointer(1,1), pPlanesF[2]->GetExtendedWidth(),
                                  pPlanesF[2]->GetExtendedHeight(), pPlanesF[2]->GetPitch(), isse);
            }
            else if (nPel==4) {
                // merge refined planes to big single plane
                Merge16PlanesToBig(pel2PlaneYB, pel2PitchY,
                                   pPlanesB[0]->GetAbsolutePointer(0,0), pPlanesB[0]->GetAbsolutePointer(1,0),
                                   pPlanesB[0]->GetAbsolutePointer(2,0), pPlanesB[0]->GetAbsolutePointer(3,0),
                                   pPlanesB[0]->GetAbsolutePointer(1,0), pPlanesB[0]->GetAbsolutePointer(1,1),
                                   pPlanesB[0]->GetAbsolutePointer(1,2), pPlanesB[0]->GetAbsolutePointer(1,3),
                                   pPlanesB[0]->GetAbsolutePointer(2,0), pPlanesB[0]->GetAbsolutePointer(2,1),
                                   pPlanesB[0]->GetAbsolutePointer(2,2), pPlanesB[0]->GetAbsolutePointer(2,3),
                                   pPlanesB[0]->GetAbsolutePointer(3,0), pPlanesB[0]->GetAbsolutePointer(3,1),
                                   pPlanesB[0]->GetAbsolutePointer(3,2), pPlanesB[0]->GetAbsolutePointer(3,3),
                                   pPlanesB[0]->GetExtendedWidth(), pPlanesB[0]->GetExtendedHeight(), 
                                   pPlanesB[0]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneUB, pel2PitchUV,
                                   pPlanesB[1]->GetAbsolutePointer(0,0), pPlanesB[1]->GetAbsolutePointer(1,0),
                                   pPlanesB[1]->GetAbsolutePointer(2,0), pPlanesB[1]->GetAbsolutePointer(3,0),
                                   pPlanesB[1]->GetAbsolutePointer(1,0), pPlanesB[1]->GetAbsolutePointer(1,1),
                                   pPlanesB[1]->GetAbsolutePointer(1,2), pPlanesB[1]->GetAbsolutePointer(1,3),
                                   pPlanesB[1]->GetAbsolutePointer(2,0), pPlanesB[1]->GetAbsolutePointer(2,1),
                                   pPlanesB[1]->GetAbsolutePointer(2,2), pPlanesB[1]->GetAbsolutePointer(2,3),
                                   pPlanesB[1]->GetAbsolutePointer(3,0), pPlanesB[1]->GetAbsolutePointer(3,1),
                                   pPlanesB[1]->GetAbsolutePointer(3,2), pPlanesB[1]->GetAbsolutePointer(3,3),
                                   pPlanesB[1]->GetExtendedWidth(), pPlanesB[1]->GetExtendedHeight(), 
                                   pPlanesB[1]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneVB, pel2PitchUV,
                                   pPlanesB[2]->GetAbsolutePointer(0,0), pPlanesB[2]->GetAbsolutePointer(1,0),
                                   pPlanesB[2]->GetAbsolutePointer(2,0), pPlanesB[2]->GetAbsolutePointer(3,0),
                                   pPlanesB[2]->GetAbsolutePointer(1,0), pPlanesB[2]->GetAbsolutePointer(1,1),
                                   pPlanesB[2]->GetAbsolutePointer(1,2), pPlanesB[2]->GetAbsolutePointer(1,3),
                                   pPlanesB[2]->GetAbsolutePointer(2,0), pPlanesB[2]->GetAbsolutePointer(2,1),
                                   pPlanesB[2]->GetAbsolutePointer(2,2), pPlanesB[2]->GetAbsolutePointer(2,3),
                                   pPlanesB[2]->GetAbsolutePointer(3,0), pPlanesB[2]->GetAbsolutePointer(3,1),
                                   pPlanesB[2]->GetAbsolutePointer(3,2), pPlanesB[2]->GetAbsolutePointer(3,3),
                                   pPlanesB[2]->GetExtendedWidth(), pPlanesB[2]->GetExtendedHeight(), 
                                   pPlanesB[2]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneYF, pel2PitchY,
                                   pPlanesF[0]->GetAbsolutePointer(0,0), pPlanesF[0]->GetAbsolutePointer(1,0),
                                   pPlanesF[0]->GetAbsolutePointer(2,0), pPlanesF[0]->GetAbsolutePointer(3,0),
                                   pPlanesF[0]->GetAbsolutePointer(1,0), pPlanesF[0]->GetAbsolutePointer(1,1),
                                   pPlanesF[0]->GetAbsolutePointer(1,2), pPlanesF[0]->GetAbsolutePointer(1,3),
                                   pPlanesF[0]->GetAbsolutePointer(2,0), pPlanesF[0]->GetAbsolutePointer(2,1),
                                   pPlanesF[0]->GetAbsolutePointer(2,2), pPlanesF[0]->GetAbsolutePointer(2,3),
                                   pPlanesF[0]->GetAbsolutePointer(3,0), pPlanesF[0]->GetAbsolutePointer(3,1),
                                   pPlanesF[0]->GetAbsolutePointer(3,2), pPlanesF[0]->GetAbsolutePointer(3,3),
                                   pPlanesF[0]->GetExtendedWidth(), pPlanesF[0]->GetExtendedHeight(), 
                                   pPlanesF[0]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneUF, pel2PitchUV,
                                   pPlanesF[1]->GetAbsolutePointer(0,0), pPlanesF[1]->GetAbsolutePointer(1,0),
                                   pPlanesF[1]->GetAbsolutePointer(2,0), pPlanesF[1]->GetAbsolutePointer(3,0),
                                   pPlanesF[1]->GetAbsolutePointer(1,0), pPlanesF[1]->GetAbsolutePointer(1,1),
                                   pPlanesF[1]->GetAbsolutePointer(1,2), pPlanesF[1]->GetAbsolutePointer(1,3),
                                   pPlanesF[1]->GetAbsolutePointer(2,0), pPlanesF[1]->GetAbsolutePointer(2,1),
                                   pPlanesF[1]->GetAbsolutePointer(2,2), pPlanesF[1]->GetAbsolutePointer(2,3),
                                   pPlanesF[1]->GetAbsolutePointer(3,0), pPlanesF[1]->GetAbsolutePointer(3,1),
                                   pPlanesF[1]->GetAbsolutePointer(3,2), pPlanesF[1]->GetAbsolutePointer(3,3),
                                   pPlanesF[1]->GetExtendedWidth(), pPlanesF[1]->GetExtendedHeight(),
                                   pPlanesF[1]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneVF, pel2PitchUV,
                                   pPlanesF[2]->GetAbsolutePointer(0,0), pPlanesF[2]->GetAbsolutePointer(1,0),
                                   pPlanesF[2]->GetAbsolutePointer(2,0), pPlanesF[2]->GetAbsolutePointer(3,0),
                                   pPlanesF[2]->GetAbsolutePointer(1,0), pPlanesF[2]->GetAbsolutePointer(1,1),
                                   pPlanesF[2]->GetAbsolutePointer(1,2), pPlanesF[2]->GetAbsolutePointer(1,3),
                                   pPlanesF[2]->GetAbsolutePointer(2,0), pPlanesF[2]->GetAbsolutePointer(2,1),
                                   pPlanesF[2]->GetAbsolutePointer(2,2), pPlanesF[2]->GetAbsolutePointer(2,3),
                                   pPlanesF[2]->GetAbsolutePointer(3,0), pPlanesF[2]->GetAbsolutePointer(3,1),
                                   pPlanesF[2]->GetAbsolutePointer(3,2), pPlanesF[2]->GetAbsolutePointer(3,3),
                                   pPlanesF[2]->GetExtendedWidth(), pPlanesF[2]->GetExtendedHeight(), pPlanesF[2]->GetPitch(), isse);
                }
        }


        // make  vector vx and vy small masks
        // 1. ATTENTION: vectors are assumed SHORT (|vx|, |vy| < 127) !
        // 2. they will be zeroed if not
        // 3. added 128 to all values
        MakeVectorSmallMasks(mvClipB, nBlkX, nBlkY, VXSmallYB, nBlkXP, VYSmallYB, nBlkXP);
        MakeVectorSmallMasks(mvClipF, nBlkX, nBlkY, VXSmallYF, nBlkXP, VYSmallYF, nBlkXP);
        if (nBlkXP > nBlkX) // fill right
        {
            for (int j=0; j<nBlkY; j++) {
                VXSmallYB[j*nBlkXP + nBlkX] = std::min<BYTE>(VXSmallYB[j*nBlkXP + nBlkX-1],128);
                VYSmallYB[j*nBlkXP + nBlkX] = VYSmallYB[j*nBlkXP + nBlkX-1];
                VXSmallYF[j*nBlkXP + nBlkX] = std::min<BYTE>(VXSmallYF[j*nBlkXP + nBlkX-1],128);
                VYSmallYF[j*nBlkXP + nBlkX] = VYSmallYF[j*nBlkXP + nBlkX-1];
            }
        }
        if (nBlkYP > nBlkY) // fill bottom
        {
            for (int i=0; i<nBlkXP; i++) {
                VXSmallYB[nBlkXP*nBlkY +i] = VXSmallYB[nBlkXP*(nBlkY-1) +i];
                VYSmallYB[nBlkXP*nBlkY +i] = std::min<BYTE>(VYSmallYB[nBlkXP*(nBlkY-1) +i],128);
                VXSmallYF[nBlkXP*nBlkY +i] = VXSmallYF[nBlkXP*(nBlkY-1) +i];
                VYSmallYF[nBlkXP*nBlkY +i] = std::min<BYTE>(VYSmallYF[nBlkXP*(nBlkY-1) +i],128);
            }
        }
        VectorSmallMaskYToHalfUV(VXSmallYB, nBlkXP, nBlkYP, VXSmallUVB, 2);
        VectorSmallMaskYToHalfUV(VYSmallYB, nBlkXP, nBlkYP, VYSmallUVB, yRatioUV);
        VectorSmallMaskYToHalfUV(VXSmallYF, nBlkXP, nBlkYP, VXSmallUVF, 2);
        VectorSmallMaskYToHalfUV(VYSmallYF, nBlkXP, nBlkYP, VYSmallUVF, yRatioUV);

        // analyse vectors field to detect occlusion
        //	  double occNormB = (256-time256)/(256*ml);
        MakeVectorOcclusionMaskTime(mvClipB, nBlkX, nBlkY, 1/ml, 1.0, nPel, MaskSmallB, nBlkXP, 
                                    (256-time256), nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
        //	  double occNormF = time256/(256*ml);
        MakeVectorOcclusionMaskTime(mvClipF, nBlkX, nBlkY, 1/ml, 1.0, nPel, MaskSmallF, nBlkXP, 
                                    time256, nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
        if (nBlkXP > nBlkX) // fill right
        {
            for (int j=0; j<nBlkY; j++) {
                MaskSmallB[j*nBlkXP + nBlkX] = MaskSmallB[j*nBlkXP + nBlkX-1];
                MaskSmallF[j*nBlkXP + nBlkX] = MaskSmallF[j*nBlkXP + nBlkX-1];
            }
        }
        if (nBlkYP > nBlkY) // fill bottom
        {
            for (int i=0; i<nBlkXP; i++) {
                MaskSmallB[nBlkXP*nBlkY +i] = MaskSmallB[nBlkXP*(nBlkY-1) +i];
                MaskSmallF[nBlkXP*nBlkY +i] = MaskSmallF[nBlkXP*(nBlkY-1) +i];
            }
        }

        int dummyplane = PLANAR_Y; // use luma plane resizer code for all planes if we resize from luma small mask
        upsizer->SimpleResizeDo(VXFullYB, nWidthP, nHeightP, VPitchY, VXSmallYB, nBlkXP, nBlkXP, dummyplane);
        upsizer->SimpleResizeDo(VYFullYB, nWidthP, nHeightP, VPitchY, VYSmallYB, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VXFullUVB, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVB, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VYFullUVB, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVB, nBlkXP, nBlkXP, dummyplane);

        upsizer->SimpleResizeDo(VXFullYF, nWidthP, nHeightP, VPitchY, VXSmallYF, nBlkXP, nBlkXP, dummyplane);
        upsizer->SimpleResizeDo(VYFullYF, nWidthP, nHeightP, VPitchY, VYSmallYF, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VXFullUVF, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVF, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VYFullUVF, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVF, nBlkXP, nBlkXP, dummyplane);

        upsizer->SimpleResizeDo(MaskFullYB, nWidthP, nHeightP, VPitchY, MaskSmallB, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(MaskFullUVB, nWidthPUV, nHeightPUV, VPitchUV, MaskSmallB, nBlkXP, nBlkXP, dummyplane);

        upsizer->SimpleResizeDo(MaskFullYF, nWidthP, nHeightP, VPitchY, MaskSmallF, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(MaskFullUVF, nWidthPUV, nHeightPUV, VPitchUV, MaskSmallF, nBlkXP, nBlkXP, dummyplane);

        // Get motion info from more frames for occlusion areas, and reverse backward and forward
        PVideoFrame mvBB = mvClipB.GetFrame(n+off, env);
        mvClipB.Update(mvBB, env);// backward from next next to next
        PVideoFrame mvFF = mvClipF.GetFrame(n, env);
        mvClipF.Update(mvFF, env);// forward from prev to cur

        if ( mvClipB.IsUsable()  && mvClipF.IsUsable() ) {
            // get vector mask from extra frames
            MakeVectorSmallMasks(mvClipB, nBlkX, nBlkY, VXSmallYBB, nBlkXP, VYSmallYBB, nBlkXP);
            MakeVectorSmallMasks(mvClipF, nBlkX, nBlkY, VXSmallYFF, nBlkXP, VYSmallYFF, nBlkXP);
            if (nBlkXP > nBlkX) // fill right
            {
                for (int j=0; j<nBlkY; j++) {
                    VXSmallYBB[j*nBlkXP + nBlkX] = std::min<BYTE>(VXSmallYBB[j*nBlkXP + nBlkX-1],128);
                    VYSmallYBB[j*nBlkXP + nBlkX] = VYSmallYBB[j*nBlkXP + nBlkX-1];
                    VXSmallYFF[j*nBlkXP + nBlkX] = std::min<BYTE>(VXSmallYFF[j*nBlkXP + nBlkX-1],128);
                    VYSmallYFF[j*nBlkXP + nBlkX] = VYSmallYFF[j*nBlkXP + nBlkX-1];
                }
            }
            if (nBlkYP > nBlkY) // fill bottom
            {
                for (int i=0; i<nBlkXP; i++) {
                    VXSmallYBB[nBlkXP*nBlkY +i] = VXSmallYBB[nBlkXP*(nBlkY-1) +i];
                    VYSmallYBB[nBlkXP*nBlkY +i] = std::min<BYTE>(VYSmallYBB[nBlkXP*(nBlkY-1) +i],128);
                    VXSmallYFF[nBlkXP*nBlkY +i] = VXSmallYFF[nBlkXP*(nBlkY-1) +i];
                    VYSmallYFF[nBlkXP*nBlkY +i] = std::min<BYTE>(VYSmallYFF[nBlkXP*(nBlkY-1) +i],128);
                }
            }
            VectorSmallMaskYToHalfUV(VXSmallYBB, nBlkXP, nBlkYP, VXSmallUVBB, 2);
            VectorSmallMaskYToHalfUV(VYSmallYBB, nBlkXP, nBlkYP, VYSmallUVBB, yRatioUV);
            VectorSmallMaskYToHalfUV(VXSmallYFF, nBlkXP, nBlkYP, VXSmallUVFF, 2);
            VectorSmallMaskYToHalfUV(VYSmallYFF, nBlkXP, nBlkYP, VYSmallUVFF, yRatioUV);

            // upsize vectors to full frame
            upsizer->SimpleResizeDo(VXFullYBB, nWidthP, nHeightP, VPitchY, VXSmallYBB, nBlkXP, nBlkXP, dummyplane);
            upsizer->SimpleResizeDo(VYFullYBB, nWidthP, nHeightP, VPitchY, VYSmallYBB, nBlkXP, nBlkXP, dummyplane);
            upsizerUV->SimpleResizeDo(VXFullUVBB, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVBB, nBlkXP, nBlkXP, dummyplane);
            upsizerUV->SimpleResizeDo(VYFullUVBB, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVBB, nBlkXP, nBlkXP, dummyplane);

            upsizer->SimpleResizeDo(VXFullYFF, nWidthP, nHeightP, VPitchY, VXSmallYFF, nBlkXP, nBlkXP, dummyplane);
            upsizer->SimpleResizeDo(VYFullYFF, nWidthP, nHeightP, VPitchY, VYSmallYFF, nBlkXP, nBlkXP, dummyplane);
            upsizerUV->SimpleResizeDo(VXFullUVFF, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUVFF, nBlkXP, nBlkXP, dummyplane);
            upsizerUV->SimpleResizeDo(VYFullUVFF, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUVFF, nBlkXP, nBlkXP, dummyplane);

            if (nPel>=2) {
                FlowInterExtra(pDst[0], nDstPitches[0], pel2PlaneYB + pel2OffsetY, pel2PlaneYF + pel2OffsetY, pel2PitchY,
                               VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                               nWidth, nHeight, time256, nPel, LUTVB, LUTVF, VXFullYBB, VXFullYFF, VYFullYBB, VYFullYFF);
                FlowInterExtra(pDst[1], nDstPitches[1], pel2PlaneUB + pel2OffsetUV, pel2PlaneUF + pel2OffsetUV, pel2PitchUV,
                               VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                               nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);
                FlowInterExtra(pDst[2], nDstPitches[2], pel2PlaneVB + pel2OffsetUV, pel2PlaneVF + pel2OffsetUV, pel2PitchUV,
                               VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                               nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);

            }
            else if (nPel==1) {
                FlowInterExtra(pDst[0], nDstPitches[0], pPlanesB[0]->GetPointer(0,0), pPlanesF[0]->GetPointer(0,0), pPlanesB[0]->GetPitch(),
                               VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                               nWidth, nHeight, time256, nPel, LUTVB, LUTVF, VXFullYBB, VXFullYFF, VYFullYBB, VYFullYFF);
                FlowInterExtra(pDst[1], nDstPitches[1], pPlanesB[1]->GetPointer(0,0), pPlanesF[1]->GetPointer(0,0), pPlanesB[1]->GetPitch(),
                               VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                               nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);
                FlowInterExtra(pDst[2], nDstPitches[2], pPlanesB[2]->GetPointer(0,0), pPlanesF[2]->GetPointer(0,0), pPlanesB[2]->GetPitch(),
                               VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                               nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF);
            }
        }
        else // bad extra frames, use old method without extra frames
        {
            if (nPel>=2) {
                FlowInter(pDst[0], nDstPitches[0], pel2PlaneYB + pel2OffsetY, pel2PlaneYF + pel2OffsetY, pel2PitchY,
                          VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                          nWidth, nHeight, time256, nPel, LUTVB, LUTVF);
                FlowInter(pDst[1], nDstPitches[1], pel2PlaneUB + pel2OffsetUV, pel2PlaneUF + pel2OffsetUV, pel2PitchUV,
                          VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                          nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
                FlowInter(pDst[2], nDstPitches[2], pel2PlaneVB + pel2OffsetUV, pel2PlaneVF + pel2OffsetUV, pel2PitchUV,
                          VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                          nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
            }
            else if (nPel==1) {
                FlowInter(pDst[0], nDstPitches[0], pPlanesB[0]->GetPointer(0,0), pPlanesF[0]->GetPointer(0,0), pPlanesB[0]->GetPitch(),
                          VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                          nWidth, nHeight, time256, nPel, LUTVB, LUTVF);
                FlowInter(pDst[1], nDstPitches[1], pPlanesB[1]->GetPointer(0,0), pPlanesF[1]->GetPointer(0,0), pPlanesB[1]->GetPitch(),
                          VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                          nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
                FlowInter(pDst[2], nDstPitches[2], pPlanesB[2]->GetPointer(0,0), pPlanesF[2]->GetPointer(0,0), pPlanesB[2]->GetPitch(),
                          VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                          nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF);
            }
        }
    }
    else {
        //	   return src;
        // poor estimation, let's blend src with ref frames
        unsigned char const *pRef[3], *pSrc[3];
        int nRefPitches[3], nSrcPitches[3];
        SrcPlanes->ConvertVideoFrameToPlanes(&src, pSrc, nSrcPitches);
        RefPlanes->ConvertVideoFrameToPlanes(&ref, pRef, nRefPitches);

        // blend with time weight
        Blend(pDst[0], pSrc[0], pRef[0], nHeight, nWidth, nDstPitches[0], nSrcPitches[0], nRefPitches[0], time256, isse);
        Blend(pDst[1], pSrc[1], pRef[1], nHeightUV, nWidthUV, nDstPitches[1], nSrcPitches[1], nRefPitches[1], time256, isse);
        Blend(pDst[2], pSrc[2], pRef[2], nHeightUV, nWidthUV, nDstPitches[2], nSrcPitches[2], nRefPitches[2], time256, isse);
    }

    // convert back from planes
    unsigned char *pDstYUY2 = dst->GetWritePtr();
    int nDstPitchYUY2 = dst->GetPitch();
    DstPlanes->YUY2FromPlanes(pDstYUY2, nDstPitchYUY2);

    return dst;
}
static const VSFrameRef *VS_CC mvflowfpsGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) {
    MVFlowFPSData *d = (MVFlowFPSData *) * instanceData;

    if (activationReason == arInitial) {
        int off = d->mvClipB->GetDeltaFrame(); // integer offset of reference frame

        int nleft = (int)(n * d->fa / d->fb);
        int nright = nleft + off;

        int time256 = int( (double(n) * double(d->fa) / double(d->fb) - nleft) * 256 + 0.5);
        if (off > 1)
            time256 = time256 / off;

        if (time256 == 0) {
            vsapi->requestFrameFilter(d->vi.numFrames ? VSMIN(nleft, d->vi.numFrames - 1) : nleft, d->node, frameCtx);
            return 0;
        } else if (time256 == 256) {
            vsapi->requestFrameFilter(d->vi.numFrames ? VSMIN(nright, d->vi.numFrames - 1) : nright, d->node, frameCtx);
            return 0;
        }

        if ((nleft < d->vi.numFrames && nright < d->vi.numFrames) || !d->vi.numFrames) { // for the good estimation case
            if (d->maskmode == 2)
                vsapi->requestFrameFilter(nleft, d->mvfw, frameCtx); // requests nleft - off, nleft
            vsapi->requestFrameFilter(nright, d->mvfw, frameCtx); // requests nleft, nleft + off
            vsapi->requestFrameFilter(nleft, d->mvbw, frameCtx); // requests nleft, nleft + off
            if (d->maskmode == 2)
                vsapi->requestFrameFilter(nright, d->mvbw, frameCtx); // requests nleft + off, nleft + off + off

            vsapi->requestFrameFilter(nleft, d->finest, frameCtx);
            vsapi->requestFrameFilter(nright, d->finest, frameCtx);
        } 

        vsapi->requestFrameFilter(d->vi.numFrames ? VSMIN(nleft, d->vi.numFrames - 1) : nleft, d->node, frameCtx);

        if (d->blend)
            vsapi->requestFrameFilter(d->vi.numFrames ? VSMIN(nright, d->vi.numFrames - 1) : nright, d->node, frameCtx);

    } else if (activationReason == arAllFramesReady) {
        int nleft = (int)(n * d->fa / d->fb);
        // intermediate product may be very large! Now I know how to multiply int64
        int time256 = int( (double(n)*double(d->fa)/double(d->fb) - nleft) * 256 + 0.5);

        int off = d->mvClipB->GetDeltaFrame(); // integer offset of reference frame
        // usually off must be = 1
        if (off > 1)
            time256 = time256 / off;

        int nright = nleft + off;

        if (time256 == 0) {
            return vsapi->getFrameFilter(d->vi.numFrames ? VSMIN(nleft, d->vi.numFrames - 1) : nleft, d->node, frameCtx); // simply left
        } else if (time256 == 256) {
            return vsapi->getFrameFilter(d->vi.numFrames ? VSMIN(nright, d->vi.numFrames - 1) : nright, d->node, frameCtx); // simply right
        }

        MVClipBalls ballsF(d->mvClipF, vsapi);
        MVClipBalls ballsB(d->mvClipB, vsapi);

        bool isUsableF = false;
        bool isUsableB = false;

        if ((nleft < d->vi.numFrames && nright < d->vi.numFrames) || !d->vi.numFrames) {
            const VSFrameRef *mvF = vsapi->getFrameFilter(nright, d->mvfw, frameCtx);
            ballsF.Update(mvF);// forward from current to next
            isUsableF = ballsF.IsUsable();
            vsapi->freeFrame(mvF);

            const VSFrameRef *mvB = vsapi->getFrameFilter(nleft, d->mvbw, frameCtx);
            ballsB.Update(mvB);// backward from next to current
            isUsableB = ballsB.IsUsable();
            vsapi->freeFrame(mvB);
        }

        const int nWidth = d->bleh->nWidth;
        const int nHeight = d->bleh->nHeight;
        const int nWidthUV = d->nWidthUV;
        const int nHeightUV = d->nHeightUV;
        const int maskmode = d->maskmode;
        const bool blend = d->blend;
        const bool isse = d->isse;
        const double ml = d->ml;
        const int xRatioUV = d->bleh->xRatioUV;
        const int yRatioUV = d->bleh->yRatioUV;
        const int nBlkX = d->bleh->nBlkX;
        const int nBlkY = d->bleh->nBlkY;
        const int nBlkSizeX = d->bleh->nBlkSizeX;
        const int nBlkSizeY = d->bleh->nBlkSizeY;
        const int nOverlapX = d->bleh->nOverlapX;
        const int nOverlapY = d->bleh->nOverlapY;
        const int nVPadding = d->bleh->nVPadding;
        const int nHPadding = d->bleh->nHPadding;
        const int nVPaddingUV = d->nVPaddingUV;
        const int nHPaddingUV = d->nHPaddingUV;
        const int nPel = d->bleh->nPel;
        const int VPitchY = d->VPitchY;
        const int VPitchUV = d->VPitchUV;
        const int nBlkXP = d->nBlkXP;
        const int nBlkYP = d->nBlkYP;
        SimpleResize *upsizer = d->upsizer;
        SimpleResize *upsizerUV = d->upsizerUV;
        int *LUTVB = d->LUTVB;
        int *LUTVF = d->LUTVF;

        uint8_t *VXFullYB = d->VXFullYB;
        uint8_t *VXFullUVB = d->VXFullUVB;
        uint8_t *VYFullYB = d->VYFullYB;
        uint8_t *VYFullUVB = d->VYFullUVB;
        uint8_t *VXSmallYB = d->VXSmallYB;
        uint8_t *VYSmallYB = d->VYSmallYB;
        uint8_t *VXSmallUVB = d->VXSmallUVB;
        uint8_t *VYSmallUVB = d->VYSmallUVB;
        uint8_t *VXFullYF = d->VXFullYF;
        uint8_t *VXFullUVF = d->VXFullUVF;
        uint8_t *VYFullYF = d->VYFullYF;
        uint8_t *VYFullUVF = d->VYFullUVF;
        uint8_t *VXSmallYF = d->VXSmallYF;
        uint8_t *VYSmallYF = d->VYSmallYF;
        uint8_t *VXSmallUVF = d->VXSmallUVF;
        uint8_t *VYSmallUVF = d->VYSmallUVF;

        uint8_t *VXFullYBB = d->VXFullYBB;
        uint8_t *VXFullUVBB = d->VXFullUVBB;
        uint8_t *VYFullYBB = d->VYFullYBB;
        uint8_t *VYFullUVBB = d->VYFullUVBB;
        uint8_t *VXSmallYBB = d->VXSmallYBB;
        uint8_t *VYSmallYBB = d->VYSmallYBB;
        uint8_t *VXSmallUVBB = d->VXSmallUVBB;
        uint8_t *VYSmallUVBB = d->VYSmallUVBB;
        uint8_t *VXFullYFF = d->VXFullYFF;
        uint8_t *VXFullUVFF = d->VXFullUVFF;
        uint8_t *VYFullYFF = d->VYFullYFF;
        uint8_t *VYFullUVFF = d->VYFullUVFF;
        uint8_t *VXSmallYFF = d->VXSmallYFF;
        uint8_t *VYSmallYFF = d->VYSmallYFF;
        uint8_t *VXSmallUVFF = d->VXSmallUVFF;
        uint8_t *VYSmallUVFF = d->VYSmallUVFF;

        uint8_t *MaskSmallB = d->MaskSmallB;
        uint8_t *MaskFullYB = d->MaskFullYB;
        uint8_t *MaskFullUVB = d->MaskFullUVB;
        uint8_t *MaskSmallF = d->MaskSmallF;
        uint8_t *MaskFullYF = d->MaskFullYF;
        uint8_t *MaskFullUVF = d->MaskFullUVF;

        int bitsPerSample = d->vi.format->bitsPerSample;
        int bytesPerSample = d->vi.format->bytesPerSample;

        if (isUsableB && isUsableF) {
            uint8_t *pDst[3];
            const uint8_t *pRef[3], *pSrc[3];
            int nDstPitches[3], nRefPitches[3];

            // If both are usable, that means both nleft and nright are less than numFrames, or that we don't have numFrames. Thus there is no need to check nleft and nright here.
            const VSFrameRef *src = vsapi->getFrameFilter(nleft, d->finest, frameCtx);
            const VSFrameRef *ref = vsapi->getFrameFilter(nright, d->finest, frameCtx);//  right frame for  compensation
            VSFrameRef *dst = vsapi->newVideoFrame(d->vi.format, d->vi.width, d->vi.height, src, core);

            Create_LUTV(time256, LUTVB, LUTVF); // lookup table

            for (int i = 0; i < d->vi.format->numPlanes; i++) {
                pDst[i] = vsapi->getWritePtr(dst, i);
                pRef[i] = vsapi->getReadPtr(ref, i);
                pSrc[i] = vsapi->getReadPtr(src, i);
                nDstPitches[i] = vsapi->getStride(dst, i);
                nRefPitches[i] = vsapi->getStride(ref, i);
            }

            int nOffsetY = nRefPitches[0] * nVPadding * nPel + nHPadding * bytesPerSample * nPel;
            int nOffsetUV = nRefPitches[1] * nVPaddingUV * nPel + nHPaddingUV * bytesPerSample * nPel;

            if (nright != d->nrightLast) {
                // make  vector vx and vy small masks
                // 1. ATTENTION: vectors are assumed SHORT (|vx|, |vy| < 127) !
                // 2. they will be zeroed if not
                // 3. added 128 to all values
                MakeVectorSmallMasks(&ballsB, nBlkX, nBlkY, VXSmallYB, nBlkXP, VYSmallYB, nBlkXP);
                if (nBlkXP > nBlkX) {// fill right
                    for (int j=0; j<nBlkY; j++) {
                        VXSmallYB[j*nBlkXP + nBlkX] = VSMIN(VXSmallYB[j*nBlkXP + nBlkX-1],128);
                        VYSmallYB[j*nBlkXP + nBlkX] = VYSmallYB[j*nBlkXP + nBlkX-1];
                    }
                }
                if (nBlkYP > nBlkY) {// fill bottom
                    for (int i=0; i<nBlkXP; i++) {
                        VXSmallYB[nBlkXP*nBlkY +i] = VXSmallYB[nBlkXP*(nBlkY-1) +i];
                        VYSmallYB[nBlkXP*nBlkY +i] = VSMIN(VYSmallYB[nBlkXP*(nBlkY-1) +i],128);
                    }
                }

                upsizer->Resize(VXFullYB, VPitchY, VXSmallYB, nBlkXP);
                upsizer->Resize(VYFullYB, VPitchY, VYSmallYB, nBlkXP);

                if (d->vi.format->colorFamily != cmGray) {
                    VectorSmallMaskYToHalfUV(VXSmallYB, nBlkXP, nBlkYP, VXSmallUVB, xRatioUV);
                    VectorSmallMaskYToHalfUV(VYSmallYB, nBlkXP, nBlkYP, VYSmallUVB, yRatioUV);

                    upsizerUV->Resize(VXFullUVB, VPitchUV, VXSmallUVB, nBlkXP);
                    upsizerUV->Resize(VYFullUVB, VPitchUV, VYSmallUVB, nBlkXP);
                }
            }
            // analyse vectors field to detect occlusion
            //        double occNormB = (256-time256)/(256*ml);
            //        MakeVectorOcclusionMask(mvClipB, nBlkX, nBlkY, occNormB, 1.0, nPel, MaskSmallB, nBlkXP);
            MakeVectorOcclusionMaskTime(&ballsB, nBlkX, nBlkY, ml, 1.0, nPel, MaskSmallB, nBlkXP, (256-time256), nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
            if (nBlkXP > nBlkX) // fill right
                for (int j=0; j<nBlkY; j++)
                    MaskSmallB[j*nBlkXP + nBlkX] = MaskSmallB[j*nBlkXP + nBlkX-1];
            if (nBlkYP > nBlkY) // fill bottom
                for (int i=0; i<nBlkXP; i++)
                    MaskSmallB[nBlkXP*nBlkY +i] = MaskSmallB[nBlkXP*(nBlkY-1) +i];

            upsizer->Resize(MaskFullYB, VPitchY, MaskSmallB, nBlkXP);
            if (d->vi.format->colorFamily != cmGray)
                upsizerUV->Resize(MaskFullUVB, VPitchUV, MaskSmallB, nBlkXP);

            d->nrightLast = nright;

            if (nleft != d->nleftLast) {
                // make  vector vx and vy small masks
                // 1. ATTENTION: vectors are assumed SHORT (|vx|, |vy| < 127) !
                // 2. they will be zeroed if not
                // 3. added 128 to all values
                MakeVectorSmallMasks(&ballsF, nBlkX, nBlkY, VXSmallYF, nBlkXP, VYSmallYF, nBlkXP);
                if (nBlkXP > nBlkX) {// fill right
                    for (int j=0; j<nBlkY; j++) {
                        VXSmallYF[j*nBlkXP + nBlkX] = VSMIN(VXSmallYF[j*nBlkXP + nBlkX-1],128);
                        VYSmallYF[j*nBlkXP + nBlkX] = VYSmallYF[j*nBlkXP + nBlkX-1];
                    }
                }
                if (nBlkYP > nBlkY) {// fill bottom
                    for (int i=0; i<nBlkXP; i++) {
                        VXSmallYF[nBlkXP*nBlkY +i] = VXSmallYF[nBlkXP*(nBlkY-1) +i];
                        VYSmallYF[nBlkXP*nBlkY +i] = VSMIN(VYSmallYF[nBlkXP*(nBlkY-1) +i],128);
                    }
                }

                upsizer->Resize(VXFullYF, VPitchY, VXSmallYF, nBlkXP);
                upsizer->Resize(VYFullYF, VPitchY, VYSmallYF, nBlkXP);

                if (d->vi.format->colorFamily != cmGray) {
                    VectorSmallMaskYToHalfUV(VXSmallYF, nBlkXP, nBlkYP, VXSmallUVF, xRatioUV);
                    VectorSmallMaskYToHalfUV(VYSmallYF, nBlkXP, nBlkYP, VYSmallUVF, yRatioUV);

                    upsizerUV->Resize(VXFullUVF, VPitchUV, VXSmallUVF, nBlkXP);
                    upsizerUV->Resize(VYFullUVF, VPitchUV, VYSmallUVF, nBlkXP);
                }
            }
            // analyse vectors field to detect occlusion
            //        double occNormF = time256/(256*ml);
            //        MakeVectorOcclusionMask(mvClipF, nBlkX, nBlkY, occNormF, 1.0, nPel, MaskSmallF, nBlkXP);
            MakeVectorOcclusionMaskTime(&ballsF, nBlkX, nBlkY, ml, 1.0, nPel, MaskSmallF, nBlkXP, time256, nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY);
            if (nBlkXP > nBlkX) // fill right
                for (int j=0; j<nBlkY; j++)
                    MaskSmallF[j*nBlkXP + nBlkX] = MaskSmallF[j*nBlkXP + nBlkX-1];
            if (nBlkYP > nBlkY) // fill bottom
                for (int i=0; i<nBlkXP; i++)
                    MaskSmallF[nBlkXP*nBlkY +i] = MaskSmallF[nBlkXP*(nBlkY-1) +i];

            upsizer->Resize(MaskFullYF, VPitchY, MaskSmallF, nBlkXP);
            if (d->vi.format->colorFamily != cmGray)
                upsizerUV->Resize(MaskFullUVF, VPitchUV, MaskSmallF, nBlkXP);

            d->nleftLast = nleft;

            if (maskmode == 2) { // These motion vectors should only be needed with maskmode 2. Why was the Avisynth plugin requesting them for all mask modes?
                // Get motion info from more frames for occlusion areas
                const VSFrameRef *mvFF = vsapi->getFrameFilter(nleft, d->mvfw, frameCtx);
                ballsF.Update(mvFF);// forward from prev to cur
                isUsableF = ballsF.IsUsable();
                vsapi->freeFrame(mvFF);

                const VSFrameRef *mvBB = vsapi->getFrameFilter(nright, d->mvbw, frameCtx);
                ballsB.Update(mvBB);// backward from next next to next
                isUsableB = ballsB.IsUsable();
                vsapi->freeFrame(mvBB);
            }

            if (maskmode == 2 && isUsableB && isUsableF) {// slow method with extra frames
                // get vector mask from extra frames
                MakeVectorSmallMasks(&ballsB, nBlkX, nBlkY, VXSmallYBB, nBlkXP, VYSmallYBB, nBlkXP);
                MakeVectorSmallMasks(&ballsF, nBlkX, nBlkY, VXSmallYFF, nBlkXP, VYSmallYFF, nBlkXP);
                if (nBlkXP > nBlkX) {// fill right
                    for (int j=0; j<nBlkY; j++) {
                        VXSmallYBB[j*nBlkXP + nBlkX] = VSMIN(VXSmallYBB[j*nBlkXP + nBlkX-1],128);
                        VYSmallYBB[j*nBlkXP + nBlkX] = VYSmallYBB[j*nBlkXP + nBlkX-1];
                        VXSmallYFF[j*nBlkXP + nBlkX] = VSMIN(VXSmallYFF[j*nBlkXP + nBlkX-1],128);
                        VYSmallYFF[j*nBlkXP + nBlkX] = VYSmallYFF[j*nBlkXP + nBlkX-1];
                    }
                }
                if (nBlkYP > nBlkY) {// fill bottom
                    for (int i=0; i<nBlkXP; i++) {
                        VXSmallYBB[nBlkXP*nBlkY +i] = VXSmallYBB[nBlkXP*(nBlkY-1) +i];
                        VYSmallYBB[nBlkXP*nBlkY +i] = VSMIN(VYSmallYBB[nBlkXP*(nBlkY-1) +i],128);
                        VXSmallYFF[nBlkXP*nBlkY +i] = VXSmallYFF[nBlkXP*(nBlkY-1) +i];
                        VYSmallYFF[nBlkXP*nBlkY +i] = VSMIN(VYSmallYFF[nBlkXP*(nBlkY-1) +i],128);
                    }
                }

                upsizer->Resize(VXFullYBB, VPitchY, VXSmallYBB, nBlkXP);
                upsizer->Resize(VYFullYBB, VPitchY, VYSmallYBB, nBlkXP);

                upsizer->Resize(VXFullYFF, VPitchY, VXSmallYFF, nBlkXP);
                upsizer->Resize(VYFullYFF, VPitchY, VYSmallYFF, nBlkXP);

                FlowInterExtra(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, pSrc[0] + nOffsetY, nRefPitches[0],
                        VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                        nWidth, nHeight, time256, nPel, LUTVB, LUTVF, VXFullYBB, VXFullYFF, VYFullYBB, VYFullYFF, bitsPerSample);
                if (d->vi.format->colorFamily != cmGray) {
                    VectorSmallMaskYToHalfUV(VXSmallYBB, nBlkXP, nBlkYP, VXSmallUVBB, xRatioUV);
                    VectorSmallMaskYToHalfUV(VYSmallYBB, nBlkXP, nBlkYP, VYSmallUVBB, yRatioUV);
                    VectorSmallMaskYToHalfUV(VXSmallYFF, nBlkXP, nBlkYP, VXSmallUVFF, xRatioUV);
                    VectorSmallMaskYToHalfUV(VYSmallYFF, nBlkXP, nBlkYP, VYSmallUVFF, yRatioUV);

                    upsizerUV->Resize(VXFullUVBB, VPitchUV, VXSmallUVBB, nBlkXP);
                    upsizerUV->Resize(VYFullUVBB, VPitchUV, VYSmallUVBB, nBlkXP);

                    upsizerUV->Resize(VXFullUVFF, VPitchUV, VXSmallUVFF, nBlkXP);
                    upsizerUV->Resize(VYFullUVFF, VPitchUV, VYSmallUVFF, nBlkXP);

                    FlowInterExtra(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, pSrc[1] + nOffsetUV, nRefPitches[1],
                            VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                            nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF, bitsPerSample);
                    FlowInterExtra(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, pSrc[2] + nOffsetUV, nRefPitches[2],
                            VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                            nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, VXFullUVBB, VXFullUVFF, VYFullUVBB, VYFullUVFF, bitsPerSample);
                }
            } else if (maskmode == 1) {// old method without extra frames
                FlowInter(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, pSrc[0] + nOffsetY, nRefPitches[0],
                        VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                        nWidth, nHeight, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                if (d->vi.format->colorFamily != cmGray) {
                    FlowInter(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, pSrc[1] + nOffsetUV, nRefPitches[1],
                            VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                            nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                    FlowInter(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, pSrc[2] + nOffsetUV, nRefPitches[2],
                        VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                        nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                }
            } else {// mode=0, faster simple method
                FlowInterSimple(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, pSrc[0] + nOffsetY, nRefPitches[0],
                        VXFullYB, VXFullYF, VYFullYB, VYFullYF, MaskFullYB, MaskFullYF, VPitchY,
                        nWidth, nHeight, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                if (d->vi.format->colorFamily != cmGray) {
                    FlowInterSimple(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, pSrc[1] + nOffsetUV, nRefPitches[1],
                            VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                            nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                    FlowInterSimple(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, pSrc[2] + nOffsetUV, nRefPitches[2],
                            VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, MaskFullUVB, MaskFullUVF, VPitchUV,
                            nWidthUV, nHeightUV, time256, nPel, LUTVB, LUTVF, bitsPerSample);
                }
            }

            vsapi->freeFrame(src);
            vsapi->freeFrame(ref);

            return dst;
        } else { // poor estimation
            const VSFrameRef *src = vsapi->getFrameFilter(d->vi.numFrames ? VSMIN(nleft, d->vi.numFrames - 1) : nleft, d->node, frameCtx);

            if (blend) {//let's blend src with ref frames like ConvertFPS
                uint8_t *pDst[3];
                const uint8_t *pRef[3], *pSrc[3];
                int nDstPitches[3], nRefPitches[3], nSrcPitches[3];

                const VSFrameRef *ref = vsapi->getFrameFilter(d->vi.numFrames ? VSMIN(nright, d->vi.numFrames - 1) : nright, d->node, frameCtx);

                VSFrameRef *dst = vsapi->newVideoFrame(d->vi.format, d->vi.width, d->vi.height, src, core);

                for (int i = 0; i < d->vi.format->numPlanes; i++) {
                    pDst[i] = vsapi->getWritePtr(dst, i);
                    pRef[i] = vsapi->getReadPtr(ref, i);
                    pSrc[i] = vsapi->getReadPtr(src, i);
                    nDstPitches[i] = vsapi->getStride(dst, i);
                    nRefPitches[i] = vsapi->getStride(ref, i);
                    nSrcPitches[i] = vsapi->getStride(src, i);
                }

                // blend with time weight
                Blend(pDst[0], pSrc[0], pRef[0], nHeight, nWidth, nDstPitches[0], nSrcPitches[0], nRefPitches[0], time256, isse, bitsPerSample);
                if (d->vi.format->colorFamily != cmGray) {
                    Blend(pDst[1], pSrc[1], pRef[1], nHeightUV, nWidthUV, nDstPitches[1], nSrcPitches[1], nRefPitches[1], time256, isse, bitsPerSample);
                    Blend(pDst[2], pSrc[2], pRef[2], nHeightUV, nWidthUV, nDstPitches[2], nSrcPitches[2], nRefPitches[2], time256, isse, bitsPerSample);
                }

                vsapi->freeFrame(src);
                vsapi->freeFrame(ref);

                return dst;
            } else {
                return src; // like ChangeFPS
            }
        }
    }

    return 0;
}
//-------------------------------------------------------------------------
PVideoFrame __stdcall MVFlow::GetFrame(int n, IScriptEnvironment* env)
{
    PVideoFrame src	= child->GetFrame(n, env);
    bool paritySrc = child->GetParity(n);

    int nref;
    int off = mvClip.GetDeltaFrame(); // integer offset of reference frame
    if ( mvClip.IsBackward() ) {
        nref = n + off;
    }
    else {
        nref = n - off;
    }

    PVideoFrame mvn = mvClip.GetFrame(n, env);
    mvClip.Update(mvn, env);// backward from next to current

    int sharp = mvClip.GetSharp();

    if ( mvClip.IsUsable()) {
        // get reference frames
        PMVGroupOfFrames pRefGOF = mvCore->GetFrame(nIdx, nref);
        if (!pRefGOF->IsProcessed()) {
            PVideoFrame ref, ref2x;
            ref = child->GetFrame(nref, env);
            pRefGOF->SetParity(child->GetParity(nref));
            if (usePelClipHere)
                ref2x= pelclip->GetFrame(nref, env);

            ProcessFrameIntoGroupOfFrames(&pRefGOF, &ref, &ref2x, sharp, pixelType, nHeight, nWidth, nPel, isse);
        }

        PVideoFrame dst = env->NewVideoFrame(vi);
        // convert to frames
        unsigned char *pDst[3];
        int nDstPitches[3];
        DstPlanes->ConvertVideoFrameToPlanes(&dst, pDst, nDstPitches);

        MVPlane *pPlanes[3];

        pPlanes[0] = pRefGOF->GetFrame(0)->GetPlane(YPLANE);
        pPlanes[1] = pRefGOF->GetFrame(0)->GetPlane(UPLANE);
        pPlanes[2] = pRefGOF->GetFrame(0)->GetPlane(VPLANE);

        if (nPel>=2 ){
            if (usePelClipHere) { // simply padding 2x or 4x planes
                PlaneCopy(pel2PlaneY + pel2OffsetY, pel2PitchY,
                          pRefGOF->GetVFYPtr(), pRefGOF->GetVFYPitch(), nWidth*nPel, nHeight*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneY, pel2PitchY, nHPadding*nPel, nVPadding*nPel, nWidth*nPel, 
                                           nHeight*nPel);
                PlaneCopy(pel2PlaneU + pel2OffsetUV, pel2PitchUV,
                          pRefGOF->GetVFUPtr(), pRefGOF->GetVFUPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneU, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
                PlaneCopy(pel2PlaneV + pel2OffsetUV, pel2PitchUV,
                          pRefGOF->GetVFVPtr(), pRefGOF->GetVFVPitch(), nWidthUV*nPel, nHeightUV*nPel, isse);
                Padding::PadReferenceFrame(pel2PlaneV, pel2PitchUV, nHPaddingUV*nPel, nVPaddingUV*nPel, nWidthUV*nPel, 
                                           nHeightUV*nPel);
            }
            else if (nPel==2) {
                // merge refined planes to big single plane
                Merge4PlanesToBig(pel2PlaneY, pel2PitchY, pPlanes[0]->GetAbsolutePointer(0,0),
                                  pPlanes[0]->GetAbsolutePointer(1,0), pPlanes[0]->GetAbsolutePointer(0,1),
                                  pPlanes[0]->GetAbsolutePointer(1,1), pPlanes[0]->GetExtendedWidth(),
                                  pPlanes[0]->GetExtendedHeight(), pPlanes[0]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneU, pel2PitchUV, pPlanes[1]->GetAbsolutePointer(0,0),
                                  pPlanes[1]->GetAbsolutePointer(1,0), pPlanes[1]->GetAbsolutePointer(0,1),
                                  pPlanes[1]->GetAbsolutePointer(1,1), pPlanes[1]->GetExtendedWidth(),
                                  pPlanes[1]->GetExtendedHeight(), pPlanes[1]->GetPitch(), isse);
                Merge4PlanesToBig(pel2PlaneV, pel2PitchUV, pPlanes[2]->GetAbsolutePointer(0,0),
                                  pPlanes[2]->GetAbsolutePointer(1,0), pPlanes[2]->GetAbsolutePointer(0,1),
                                  pPlanes[2]->GetAbsolutePointer(1,1), pPlanes[2]->GetExtendedWidth(),
                                  pPlanes[2]->GetExtendedHeight(), pPlanes[2]->GetPitch(), isse);
            }
            else if (nPel==4) {
                // merge refined planes to big single plane
                Merge16PlanesToBig(pel2PlaneY, pel2PitchY,
                                   pPlanes[0]->GetAbsolutePointer(0,0), pPlanes[0]->GetAbsolutePointer(1,0),
                                   pPlanes[0]->GetAbsolutePointer(2,0), pPlanes[0]->GetAbsolutePointer(3,0),
                                   pPlanes[0]->GetAbsolutePointer(1,0), pPlanes[0]->GetAbsolutePointer(1,1),
                                   pPlanes[0]->GetAbsolutePointer(1,2), pPlanes[0]->GetAbsolutePointer(1,3),
                                   pPlanes[0]->GetAbsolutePointer(2,0), pPlanes[0]->GetAbsolutePointer(2,1),
                                   pPlanes[0]->GetAbsolutePointer(2,2), pPlanes[0]->GetAbsolutePointer(2,3),
                                   pPlanes[0]->GetAbsolutePointer(3,0), pPlanes[0]->GetAbsolutePointer(3,1),
                                   pPlanes[0]->GetAbsolutePointer(3,2), pPlanes[0]->GetAbsolutePointer(3,3),
                                   pPlanes[0]->GetExtendedWidth(), pPlanes[0]->GetExtendedHeight(), pPlanes[0]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneU, pel2PitchUV,
                                   pPlanes[1]->GetAbsolutePointer(0,0), pPlanes[1]->GetAbsolutePointer(1,0),
                                   pPlanes[1]->GetAbsolutePointer(2,0), pPlanes[1]->GetAbsolutePointer(3,0),
                                   pPlanes[1]->GetAbsolutePointer(1,0), pPlanes[1]->GetAbsolutePointer(1,1),
                                   pPlanes[1]->GetAbsolutePointer(1,2), pPlanes[1]->GetAbsolutePointer(1,3),
                                   pPlanes[1]->GetAbsolutePointer(2,0), pPlanes[1]->GetAbsolutePointer(2,1),
                                   pPlanes[1]->GetAbsolutePointer(2,2), pPlanes[1]->GetAbsolutePointer(2,3),
                                   pPlanes[1]->GetAbsolutePointer(3,0), pPlanes[1]->GetAbsolutePointer(3,1),
                                   pPlanes[1]->GetAbsolutePointer(3,2), pPlanes[1]->GetAbsolutePointer(3,3),
                                   pPlanes[1]->GetExtendedWidth(), pPlanes[1]->GetExtendedHeight(), pPlanes[1]->GetPitch(), isse);
                Merge16PlanesToBig(pel2PlaneV, pel2PitchUV,
                                   pPlanes[2]->GetAbsolutePointer(0,0), pPlanes[2]->GetAbsolutePointer(1,0),
                                   pPlanes[2]->GetAbsolutePointer(2,0), pPlanes[2]->GetAbsolutePointer(3,0),
                                   pPlanes[2]->GetAbsolutePointer(1,0), pPlanes[2]->GetAbsolutePointer(1,1),
                                   pPlanes[2]->GetAbsolutePointer(1,2), pPlanes[2]->GetAbsolutePointer(1,3),
                                   pPlanes[2]->GetAbsolutePointer(2,0), pPlanes[2]->GetAbsolutePointer(2,1),
                                   pPlanes[2]->GetAbsolutePointer(2,2), pPlanes[2]->GetAbsolutePointer(2,3),
                                   pPlanes[2]->GetAbsolutePointer(3,0), pPlanes[2]->GetAbsolutePointer(3,1),
                                   pPlanes[2]->GetAbsolutePointer(3,2), pPlanes[2]->GetAbsolutePointer(3,3),
                                   pPlanes[2]->GetExtendedWidth(), pPlanes[2]->GetExtendedHeight(), pPlanes[2]->GetPitch(), isse);
            }
        }

        //		 char debugbuf[100];
        //		 for (int V=100; V<145; V++)
        //		 {
        //			 int vx1 = ((V-128)*time256)>>8;
        //				int vx2 = ((V*time256+127)>>8) - (time256>>1);
        //				int vx3 = ((V*time256)/256) - (time256/2);
        //				int vx4 = ((V-128)*time256)/256;
        //		 		int vx5 = V-128;
        //				if (vx5 < 0) vx5++;
        //				vx5 = (vx5*time256)>>8;
        //
        //			 sprintf(debugbuf,"MVFlow: V=%d %d %d %d %d %d", V,vx1,vx2,vx3,vx4,vx5);
        //			 OutputDebugString(debugbuf);
        //		 }
        //
        // make  vector vx and vy small masks
        // 1. ATTENTION: vectors are assumed SHORT (|vx|, |vy| < 127) !
        // 2. they will be zeroed if not
        // 3. added 128 to all values
        MakeVectorSmallMasks(mvClip, nBlkX, nBlkY, VXSmallY, nBlkXP, VYSmallY, nBlkXP);
        if (nBlkXP > nBlkX) // fill right
        {
            for (int j=0; j<nBlkY; j++) {
                VXSmallY[j*nBlkXP + nBlkX] = std::min<BYTE>(VXSmallY[j*nBlkXP + nBlkX-1],128);
                VYSmallY[j*nBlkXP + nBlkX] = VYSmallY[j*nBlkXP + nBlkX-1];
            }
        }
        if (nBlkYP > nBlkY) // fill bottom
        {
            for (int i=0; i<nBlkXP; i++) {
                VXSmallY[nBlkXP*nBlkY +i] = VXSmallY[nBlkXP*(nBlkY-1) +i];
                VYSmallY[nBlkXP*nBlkY +i] = std::min<BYTE>(VYSmallY[nBlkXP*(nBlkY-1) +i],128);
            }
        }

        int fieldShift = 0;
        if (fields && (nPel >= 2) && (off %2 != 0)) {
            fieldShift = (paritySrc && !pRefGOF->Parity()) ? (nPel/2) : ((pRefGOF->Parity() && !paritySrc) ? -(nPel/2) : 0);
            // vertical shift of fields for fieldbased video at finest level pel2
        }

        for (int j=0; j<nBlkYP; j++) {
            for (int i=0; i<nBlkXP; i++) {
            VYSmallY[j*nBlkXP + i] += fieldShift;
            }
        }

        VectorSmallMaskYToHalfUV(VXSmallY, nBlkXP, nBlkYP, VXSmallUV, 2);
        VectorSmallMaskYToHalfUV(VYSmallY, nBlkXP, nBlkYP, VYSmallUV, yRatioUV);

        // upsize (bilinear interpolate) vector masks to fullframe size

        int dummyplane = PLANAR_Y; // use luma plane resizer code for all planes if we resize from luma small mask
        upsizer->SimpleResizeDo(VXFullY, nWidthP, nHeightP, VPitchY, VXSmallY, nBlkXP, nBlkXP, dummyplane);
        upsizer->SimpleResizeDo(VYFullY, nWidthP, nHeightP, VPitchY, VYSmallY, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VXFullUV, nWidthPUV, nHeightPUV, VPitchUV, VXSmallUV, nBlkXP, nBlkXP, dummyplane);
        upsizerUV->SimpleResizeDo(VYFullUV, nWidthPUV, nHeightPUV, VPitchUV, VYSmallUV, nBlkXP, nBlkXP, dummyplane);


        if (mode==0) // fetch mode
        {
            if (nPel>=2)  {
                Fetch(pDst[0], nDstPitches[0], pel2PlaneY + pel2OffsetY, pel2PitchY, VXFullY, VPitchY, VYFullY, 
                      VPitchY, nWidth, nHeight, time256); //padded
                Fetch(pDst[1], nDstPitches[1], pel2PlaneU + pel2OffsetUV, pel2PitchUV, VXFullUV, VPitchUV, VYFullUV, 
                      VPitchUV, nWidthUV, nHeightUV, time256);
                Fetch(pDst[2], nDstPitches[2], pel2PlaneV + pel2OffsetUV, pel2PitchUV, VXFullUV, VPitchUV, VYFullUV, 
                      VPitchUV, nWidthUV, nHeightUV, time256);
            }
            else //(nPel==1)
            {
                Fetch(pDst[0], nDstPitches[0], pPlanes[0]->GetPointer(0,0), pPlanes[0]->GetPitch(), VXFullY, VPitchY, VYFullY, 
                      VPitchY, nWidth, nHeight, time256); //padded
                Fetch(pDst[1], nDstPitches[1], pPlanes[1]->GetPointer(0,0), pPlanes[1]->GetPitch(), VXFullUV, VPitchUV, VYFullUV, 
                      VPitchUV, nWidthUV, nHeightUV, time256);
                Fetch(pDst[2], nDstPitches[2], pPlanes[2]->GetPointer(0,0), pPlanes[2]->GetPitch(), VXFullUV, VPitchUV, VYFullUV, 
                      VPitchUV, nWidthUV, nHeightUV, time256);
            }
        }
        else if (mode==1) // shift mode
        {
            MemZoneSet(pDst[0], 0, nWidth, nHeight, 0, 0, nDstPitches[0]);
            MemZoneSet(pDst[1], 0, nWidthUV, nHeightUV, 0, 0, nDstPitches[1]);
            MemZoneSet(pDst[2], 0, nWidthUV, nHeightUV, 0, 0, nDstPitches[2]);
            Shift(pDst[0], nDstPitches[0], pPlanes[0]->GetPointer(0,0), pPlanes[0]->GetPitch(), 
                  VXFullY, VPitchY, VYFullY, VPitchY, nWidth, nHeight, time256);
            Shift(pDst[1], nDstPitches[1], pPlanes[1]->GetPointer(0,0), pPlanes[1]->GetPitch(), 
                  VXFullUV, VPitchUV, VYFullUV, VPitchUV, nWidthUV, nHeightUV, time256);
            Shift(pDst[2], nDstPitches[2], pPlanes[2]->GetPointer(0,0), pPlanes[2]->GetPitch(), 
                  VXFullUV, VPitchUV, VYFullUV, VPitchUV, nWidthUV, nHeightUV, time256);
        }

        // convert back from planes
        unsigned char *pDstYUY2 = dst->GetWritePtr();
        int nDstPitchYUY2 = dst->GetPitch();
        DstPlanes->YUY2FromPlanes(pDstYUY2, nDstPitchYUY2);

        return dst;
    }
    else
    {
        return src;
    }
}
Exemple #5
0
static const VSFrameRef *VS_CC mvflowblurGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) {
    (void)frameData;

    MVFlowBlurData *d = (MVFlowBlurData *)*instanceData;

    if (activationReason == arInitial) {
        int off = d->mvbw_data.nDeltaFrame; // integer offset of reference frame

        if (n - off >= 0 && n + off < d->vi->numFrames) {
            vsapi->requestFrameFilter(n - off, d->mvbw, frameCtx);
            vsapi->requestFrameFilter(n + off, d->mvfw, frameCtx);
        }

        vsapi->requestFrameFilter(n, d->finest, frameCtx);
        vsapi->requestFrameFilter(n, d->node, frameCtx);
    } else if (activationReason == arAllFramesReady) {
        uint8_t *pDst[3];
        const uint8_t *pRef[3];
        int nDstPitches[3];
        int nRefPitches[3];

        FakeGroupOfPlanes fgopF, fgopB;

        fgopInit(&fgopF, &d->mvfw_data);
        fgopInit(&fgopB, &d->mvbw_data);

        int isUsableB = 0;
        int isUsableF = 0;

        int off = d->mvbw_data.nDeltaFrame; // integer offset of reference frame

        if (n - off >= 0 && n + off < d->vi->numFrames) {
            const VSFrameRef *mvF = vsapi->getFrameFilter(n + off, d->mvfw, frameCtx);
            const VSMap *mvprops = vsapi->getFramePropsRO(mvF);
            fgopUpdate(&fgopF, (const int *)vsapi->propGetData(mvprops, prop_MVTools_vectors, 0, NULL));
            isUsableF = fgopIsUsable(&fgopF, d->thscd1, d->thscd2);
            vsapi->freeFrame(mvF);

            const VSFrameRef *mvB = vsapi->getFrameFilter(n - off, d->mvbw, frameCtx);
            mvprops = vsapi->getFramePropsRO(mvB);
            fgopUpdate(&fgopB, (const int *)vsapi->propGetData(mvprops, prop_MVTools_vectors, 0, NULL));
            isUsableB = fgopIsUsable(&fgopB, d->thscd1, d->thscd2);
            vsapi->freeFrame(mvB);
        }


        if (isUsableB && isUsableF) {
            const VSFrameRef *ref = vsapi->getFrameFilter(n, d->finest, frameCtx); //  ref for  compensation
            VSFrameRef *dst = vsapi->newVideoFrame(d->vi->format, d->vi->width, d->vi->height, ref, core);

            for (int i = 0; i < d->vi->format->numPlanes; i++) {
                pDst[i] = vsapi->getWritePtr(dst, i);
                pRef[i] = vsapi->getReadPtr(ref, i);
                nDstPitches[i] = vsapi->getStride(dst, i);
                nRefPitches[i] = vsapi->getStride(ref, i);
            }

            const int nWidth = d->mvbw_data.nWidth;
            const int nHeight = d->mvbw_data.nHeight;
            const int nWidthUV = d->nWidthUV;
            const int nHeightUV = d->nHeightUV;
            const int xRatioUV = d->mvbw_data.xRatioUV;
            const int yRatioUV = d->mvbw_data.yRatioUV;
            const int nBlkX = d->mvbw_data.nBlkX;
            const int nBlkY = d->mvbw_data.nBlkY;
            const int nVPadding = d->mvbw_data.nVPadding;
            const int nHPadding = d->mvbw_data.nHPadding;
            const int nVPaddingUV = d->nVPaddingUV;
            const int nHPaddingUV = d->nHPaddingUV;
            const int nPel = d->mvbw_data.nPel;
            const int blur256 = d->blur256;
            const int prec = d->prec;
            const int VPitchY = d->VPitchY;
            const int VPitchUV = d->VPitchUV;

            int bitsPerSample = d->vi->format->bitsPerSample;
            int bytesPerSample = d->vi->format->bytesPerSample;

            int nOffsetY = nRefPitches[0] * nVPadding * nPel + nHPadding * bytesPerSample * nPel;
            int nOffsetUV = nRefPitches[1] * nVPaddingUV * nPel + nHPaddingUV * bytesPerSample * nPel;


            size_t full_size = nHeight * VPitchY * sizeof(int16_t);
            size_t small_size = nBlkY * nBlkX * sizeof(int16_t);

            int16_t *VXFullYB = (int16_t *)malloc(full_size);
            int16_t *VYFullYB = (int16_t *)malloc(full_size);
            int16_t *VXFullYF = (int16_t *)malloc(full_size);
            int16_t *VYFullYF = (int16_t *)malloc(full_size);
            int16_t *VXSmallYB = (int16_t *)malloc(small_size);
            int16_t *VYSmallYB = (int16_t *)malloc(small_size);
            int16_t *VXSmallYF = (int16_t *)malloc(small_size);
            int16_t *VYSmallYF = (int16_t *)malloc(small_size);

            // make  vector vx and vy small masks
            MakeVectorSmallMasks(&fgopB, nBlkX, nBlkY, VXSmallYB, nBlkX, VYSmallYB, nBlkX);
            MakeVectorSmallMasks(&fgopF, nBlkX, nBlkY, VXSmallYF, nBlkX, VYSmallYF, nBlkX);

            // analyse vectors field to detect occlusion

            // upsize (bilinear interpolate) vector masks to fullframe size


            d->upsizer.simpleResize_int16_t(&d->upsizer, VXFullYB, VPitchY, VXSmallYB, nBlkX);
            d->upsizer.simpleResize_int16_t(&d->upsizer, VYFullYB, VPitchY, VYSmallYB, nBlkX);
            d->upsizer.simpleResize_int16_t(&d->upsizer, VXFullYF, VPitchY, VXSmallYF, nBlkX);
            d->upsizer.simpleResize_int16_t(&d->upsizer, VYFullYF, VPitchY, VYSmallYF, nBlkX);

            FlowBlur(pDst[0], nDstPitches[0], pRef[0] + nOffsetY, nRefPitches[0],
                     VXFullYB, VXFullYF, VYFullYB, VYFullYF, VPitchY,
                     nWidth, nHeight, blur256, prec, nPel, bitsPerSample);

            if (d->vi->format->colorFamily != cmGray) {
                size_t full_size_uv = nHeightUV * VPitchUV * sizeof(int16_t);
                size_t small_size_uv = nBlkY * nBlkX * sizeof(int16_t);

                int16_t *VXFullUVB = (int16_t *)malloc(full_size_uv);
                int16_t *VYFullUVB = (int16_t *)malloc(full_size_uv);

                int16_t *VXFullUVF = (int16_t *)malloc(full_size_uv);
                int16_t *VYFullUVF = (int16_t *)malloc(full_size_uv);

                int16_t *VXSmallUVB = (int16_t *)malloc(small_size_uv);
                int16_t *VYSmallUVB = (int16_t *)malloc(small_size_uv);

                int16_t *VXSmallUVF = (int16_t *)malloc(small_size_uv);
                int16_t *VYSmallUVF = (int16_t *)malloc(small_size_uv);

                VectorSmallMaskYToHalfUV(VXSmallYB, nBlkX, nBlkY, VXSmallUVB, xRatioUV);
                VectorSmallMaskYToHalfUV(VYSmallYB, nBlkX, nBlkY, VYSmallUVB, yRatioUV);

                VectorSmallMaskYToHalfUV(VXSmallYF, nBlkX, nBlkY, VXSmallUVF, xRatioUV);
                VectorSmallMaskYToHalfUV(VYSmallYF, nBlkX, nBlkY, VYSmallUVF, yRatioUV);

                d->upsizerUV.simpleResize_int16_t(&d->upsizerUV, VXFullUVB, VPitchUV, VXSmallUVB, nBlkX);
                d->upsizerUV.simpleResize_int16_t(&d->upsizerUV, VYFullUVB, VPitchUV, VYSmallUVB, nBlkX);

                d->upsizerUV.simpleResize_int16_t(&d->upsizerUV, VXFullUVF, VPitchUV, VXSmallUVF, nBlkX);
                d->upsizerUV.simpleResize_int16_t(&d->upsizerUV, VYFullUVF, VPitchUV, VYSmallUVF, nBlkX);


                FlowBlur(pDst[1], nDstPitches[1], pRef[1] + nOffsetUV, nRefPitches[1],
                         VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, VPitchUV,
                         nWidthUV, nHeightUV, blur256, prec, nPel, bitsPerSample);
                FlowBlur(pDst[2], nDstPitches[2], pRef[2] + nOffsetUV, nRefPitches[2],
                         VXFullUVB, VXFullUVF, VYFullUVB, VYFullUVF, VPitchUV,
                         nWidthUV, nHeightUV, blur256, prec, nPel, bitsPerSample);

                free(VXFullUVB);
                free(VYFullUVB);
                free(VXSmallUVB);
                free(VYSmallUVB);
                free(VXFullUVF);
                free(VYFullUVF);
                free(VXSmallUVF);
                free(VYSmallUVF);
            }

            free(VXFullYB);
            free(VYFullYB);
            free(VXSmallYB);
            free(VYSmallYB);
            free(VXFullYF);
            free(VYFullYF);
            free(VXSmallYF);
            free(VYSmallYF);

            vsapi->freeFrame(ref);

            fgopDeinit(&fgopF);
            fgopDeinit(&fgopB);

            return dst;
        } else { // not usable
            fgopDeinit(&fgopF);
            fgopDeinit(&fgopB);

            return vsapi->getFrameFilter(n, d->node, frameCtx);
        }
    }

    return 0;
}