//------------------------------------------------------------------------- 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; }
//------------------------------------------------------------------------- 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 } } }
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; }