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; }
static const VSFrameRef *VS_CC mvrecalculateGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { (void)frameData; MVRecalculateData *d = (MVRecalculateData *)*instanceData; if (activationReason == arInitial) { vsapi->requestFrameFilter(n, d->vectors, frameCtx); int nref; int offset = d->analysisData.nDeltaFrame; if (offset > 0) { nref = d->analysisData.isBackward ? n + offset : n - offset; } else { nref = -offset; } if (nref >= 0 && nref < d->vi->numFrames) { if (n < nref) { vsapi->requestFrameFilter(n, d->node, frameCtx); vsapi->requestFrameFilter(nref, d->node, frameCtx); } else { vsapi->requestFrameFilter(nref, d->node, frameCtx); vsapi->requestFrameFilter(n, d->node, frameCtx); } } else { // too close to beginning/end of clip vsapi->requestFrameFilter(n, d->node, frameCtx); } } else if (activationReason == arAllFramesReady) { GroupOfPlanes vectorFields; gopInit(&vectorFields, d->analysisData.nBlkSizeX, d->analysisData.nBlkSizeY, d->analysisData.nLvCount, d->analysisData.nPel, d->analysisData.nMotionFlags, d->analysisData.nCPUFlags, d->analysisData.nOverlapX, d->analysisData.nOverlapY, d->analysisData.nBlkX, d->analysisData.nBlkY, d->analysisData.xRatioUV, d->analysisData.yRatioUV, d->divideExtra, d->vi->format->bitsPerSample); const uint8_t *pSrc[3] = { NULL }; const uint8_t *pRef[3] = { NULL }; int nSrcPitch[3] = { 0 }; int nRefPitch[3] = { 0 }; int nref; int offset = d->analysisData.nDeltaFrame; if (offset > 0) { nref = d->analysisData.isBackward ? n + offset : n - offset; } else { nref = -offset; } const VSFrameRef *src = vsapi->getFrameFilter(n, d->node, frameCtx); const VSMap *srcprops = vsapi->getFramePropsRO(src); int err; int src_top_field = !!vsapi->propGetInt(srcprops, "_Field", 0, &err); if (err && d->fields && !d->tff_exists) { vsapi->setFilterError("Recalculate: _Field property not found in input frame. Therefore, you must pass tff argument.", frameCtx); gopDeinit(&vectorFields); vsapi->freeFrame(src); return NULL; } // if tff was passed, it overrides _Field. if (d->tff_exists) src_top_field = d->tff ^ (n % 2); for (int plane = 0; plane < d->vi->format->numPlanes; plane++) { pSrc[plane] = vsapi->getReadPtr(src, plane); nSrcPitch[plane] = vsapi->getStride(src, plane); } FakeGroupOfPlanes fgop; fgopInit(&fgop, &d->vectors_data); const VSFrameRef *mvn = vsapi->getFrameFilter(n, d->vectors, frameCtx); const VSMap *mvprops = vsapi->getFramePropsRO(mvn); fgopUpdate(&fgop, (const int *)vsapi->propGetData(mvprops, prop_MVTools_vectors, 0, NULL)); vsapi->freeFrame(mvn); int vectors_size = gopGetArraySize(&vectorFields) * sizeof(int); int *vectors = (int *)malloc(vectors_size); if (fgopIsValid(&fgop) && nref >= 0 && nref < d->vi->numFrames) { const VSFrameRef *ref = vsapi->getFrameFilter(nref, d->node, frameCtx); const VSMap *refprops = vsapi->getFramePropsRO(ref); int ref_top_field = !!vsapi->propGetInt(refprops, "_Field", 0, &err); if (err && d->fields && !d->tff_exists) { vsapi->setFilterError("Recalculate: _Field property not found in input frame. Therefore, you must pass tff argument.", frameCtx); gopDeinit(&vectorFields); vsapi->freeFrame(src); vsapi->freeFrame(ref); free(vectors); fgopDeinit(&fgop); return NULL; } // if tff was passed, it overrides _Field. if (d->tff_exists) ref_top_field = d->tff ^ (nref % 2); int fieldShift = 0; if (d->fields && d->analysisData.nPel > 1 && (d->analysisData.nDeltaFrame % 2)) { fieldShift = (src_top_field && !ref_top_field) ? d->analysisData.nPel / 2 : ((ref_top_field && !src_top_field) ? -(d->analysisData.nPel / 2) : 0); // vertical shift of fields for fieldbased video at finest level pel2 } for (int plane = 0; plane < d->vi->format->numPlanes; plane++) { pRef[plane] = vsapi->getReadPtr(ref, plane); nRefPitch[plane] = vsapi->getStride(ref, plane); } MVGroupOfFrames pSrcGOF, pRefGOF; mvgofInit(&pSrcGOF, d->nSuperLevels, d->analysisData.nWidth, d->analysisData.nHeight, d->nSuperPel, d->nSuperHPad, d->nSuperVPad, d->nSuperModeYUV, d->opt, d->analysisData.xRatioUV, d->analysisData.yRatioUV, d->vi->format->bitsPerSample); mvgofInit(&pRefGOF, d->nSuperLevels, d->analysisData.nWidth, d->analysisData.nHeight, d->nSuperPel, d->nSuperHPad, d->nSuperVPad, d->nSuperModeYUV, d->opt, d->analysisData.xRatioUV, d->analysisData.yRatioUV, d->vi->format->bitsPerSample); // cast away the const, because why not. mvgofUpdate(&pSrcGOF, (uint8_t **)pSrc, nSrcPitch); mvgofUpdate(&pRefGOF, (uint8_t **)pRef, nRefPitch); DCTFFTW *DCTc = NULL; if (d->dctmode >= 1 && d->dctmode <= 4) { DCTc = (DCTFFTW *)malloc(sizeof(DCTFFTW)); dctInit(DCTc, d->analysisData.nBlkSizeX, d->analysisData.nBlkSizeY, d->vi->format->bitsPerSample, d->opt); } gopRecalculateMVs(&vectorFields, &fgop, &pSrcGOF, &pRefGOF, d->searchType, d->nSearchParam, d->nLambda, d->pnew, vectors, fieldShift, d->thSAD, DCTc, d->dctmode, d->smooth, d->meander); if (d->divideExtra) { // make extra level with divided sublocks with median (not estimated) motion gopExtraDivide(&vectorFields, vectors); } gopDeinit(&vectorFields); if (DCTc) { dctDeinit(DCTc); free(DCTc); } mvgofDeinit(&pSrcGOF); mvgofDeinit(&pRefGOF); vsapi->freeFrame(ref); } else {// too close to the beginning or end to do anything gopWriteDefaultToArray(&vectorFields, vectors); gopDeinit(&vectorFields); } VSFrameRef *dst = vsapi->copyFrame(src, core); VSMap *dstprops = vsapi->getFramePropsRW(dst); vsapi->propSetData(dstprops, prop_MVTools_MVAnalysisData, (const char *)(d->divideExtra ? &d->analysisDataDivided : &d->analysisData), sizeof(MVAnalysisData), paReplace); vsapi->propSetData(dstprops, prop_MVTools_vectors, (const char *)vectors, vectors_size, paReplace); free(vectors); #if defined(MVTOOLS_X86) // FIXME: Get rid of all mmx shit. mvtools_cpu_emms(); #endif vsapi->freeFrame(src); fgopDeinit(&fgop); return dst; } return 0; }
static const VSFrameRef *VS_CC mvmaskGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { (void)frameData; MVMaskData *d = (MVMaskData *)*instanceData; if (activationReason == arInitial) { vsapi->requestFrameFilter(n, d->vectors, frameCtx); vsapi->requestFrameFilter(n, d->node, frameCtx); } else if (activationReason == arAllFramesReady) { const VSFrameRef *src = vsapi->getFrameFilter(n, d->node, frameCtx); VSFrameRef *dst = vsapi->newVideoFrame(d->vi.format, d->vi.width, d->vi.height, src, core); const uint8_t *pSrc[3]; uint8_t *pDst[3]; int nDstPitches[3]; int nSrcPitches[3]; pSrc[0] = vsapi->getReadPtr(src, 0); nSrcPitches[0] = vsapi->getStride(src, 0); for (int i = 0; i < 3; i++) { pDst[i] = vsapi->getWritePtr(dst, i); nDstPitches[i] = vsapi->getStride(dst, i); } FakeGroupOfPlanes fgop; const VSFrameRef *mvn = vsapi->getFrameFilter(n, d->vectors, frameCtx); fgopInit(&fgop, &d->vectors_data); const VSMap *mvprops = vsapi->getFramePropsRO(mvn); fgopUpdate(&fgop, (const uint8_t *)vsapi->propGetData(mvprops, prop_MVTools_vectors, 0, NULL)); vsapi->freeFrame(mvn); const int kind = d->kind; const int nWidth = d->vectors_data.nWidth; const int nHeight = d->vectors_data.nHeight; const int nWidthUV = d->nWidthUV; const int nHeightUV = d->nHeightUV; const int nSceneChangeValue = d->nSceneChangeValue; if (fgopIsUsable(&fgop, d->thscd1, d->thscd2)) { const int nBlkX = d->vectors_data.nBlkX; const int nBlkY = d->vectors_data.nBlkY; const int nBlkCount = nBlkX * nBlkY; const float fMaskNormFactor = d->fMaskNormFactor; const float fMaskNormFactor2 = d->fMaskNormFactor2; const float fGamma = d->fGamma; const float fHalfGamma = d->fHalfGamma; const int nPel = d->vectors_data.nPel; const int nBlkSizeX = d->vectors_data.nBlkSizeX; const int nBlkSizeY = d->vectors_data.nBlkSizeY; const int nOverlapX = d->vectors_data.nOverlapX; const int nOverlapY = d->vectors_data.nOverlapY; const int nWidthB = d->nWidthB; const int nHeightB = d->nHeightB; const int nWidthBUV = d->nWidthBUV; const int nHeightBUV = d->nHeightBUV; SimpleResize *upsizer = &d->upsizer; SimpleResize *upsizerUV = &d->upsizerUV; const int time256 = d->time256; const int bitsPerSample = vsapi->getFrameFormat(src)->bitsPerSample; uint8_t *smallMask = (uint8_t *)malloc(nBlkX * nBlkY); uint8_t *smallMaskV = (uint8_t *)malloc(nBlkX * nBlkY); if (kind == 0) { // vector length mask for (int j = 0; j < nBlkCount; j++) smallMask[j] = mvmaskLength(fgopGetBlock(&fgop, 0, j)->vector, nPel, fMaskNormFactor2, fHalfGamma); } else if (kind == 1) { // SAD mask MakeSADMaskTime(&fgop, nBlkX, nBlkY, 4.0 * fMaskNormFactor / (nBlkSizeX * nBlkSizeY), fGamma, nPel, smallMask, nBlkX, time256, nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY, bitsPerSample); } else if (kind == 2) { // occlusion mask MakeVectorOcclusionMaskTime(&fgop, d->vectors_data.isBackward, nBlkX, nBlkY, 1.0 / fMaskNormFactor, fGamma, nPel, smallMask, nBlkX, time256, nBlkSizeX - nOverlapX, nBlkSizeY - nOverlapY); } else if (kind == 3) { // vector x mask for (int j = 0; j < nBlkCount; j++) smallMask[j] = VSMAX(0, VSMIN(255, (int)(fgopGetBlock(&fgop, 0, j)->vector.x * fMaskNormFactor * 100 + 128))); // shited by 128 for signed support } else if (kind == 4) { // vector y mask for (int j = 0; j < nBlkCount; j++) smallMask[j] = VSMAX(0, VSMIN(255, (int)(fgopGetBlock(&fgop, 0, j)->vector.y * fMaskNormFactor * 100 + 128))); // shited by 128 for signed support } else if (kind == 5) { // vector x mask in U, y mask in V for (int j = 0; j < nBlkCount; j++) { VECTOR v = fgopGetBlock(&fgop, 0, j)->vector; smallMask[j] = VSMAX(0, VSMIN(255, (int)(v.x * fMaskNormFactor * 100 + 128))); // shited by 128 for signed support smallMaskV[j] = VSMAX(0, VSMIN(255, (int)(v.y * fMaskNormFactor * 100 + 128))); // shited by 128 for signed support } } if (kind == 5) { // do not change luma for kind=5 memcpy(pDst[0], pSrc[0], nSrcPitches[0] * nHeight); } else { upsizer->simpleResize_uint8_t(upsizer, pDst[0], nDstPitches[0], smallMask, nBlkX); if (nWidth > nWidthB) for (int h = 0; h < nHeight; h++) for (int w = nWidthB; w < nWidth; w++) *(pDst[0] + h * nDstPitches[0] + w) = *(pDst[0] + h * nDstPitches[0] + nWidthB - 1); if (nHeight > nHeightB) vs_bitblt(pDst[0] + nHeightB * nDstPitches[0], nDstPitches[0], pDst[0] + (nHeightB - 1) * nDstPitches[0], nDstPitches[0], nWidth, nHeight - nHeightB); } // chroma upsizerUV->simpleResize_uint8_t(upsizerUV, pDst[1], nDstPitches[1], smallMask, nBlkX); if (kind == 5) upsizerUV->simpleResize_uint8_t(upsizerUV, pDst[2], nDstPitches[2], smallMaskV, nBlkX); else memcpy(pDst[2], pDst[1], nHeightUV * nDstPitches[1]); if (nWidthUV > nWidthBUV) for (int h = 0; h < nHeightUV; h++) for (int w = nWidthBUV; w < nWidthUV; w++) { *(pDst[1] + h * nDstPitches[1] + w) = *(pDst[1] + h * nDstPitches[1] + nWidthBUV - 1); *(pDst[2] + h * nDstPitches[2] + w) = *(pDst[2] + h * nDstPitches[2] + nWidthBUV - 1); } if (nHeightUV > nHeightBUV) { vs_bitblt(pDst[1] + nHeightBUV * nDstPitches[1], nDstPitches[1], pDst[1] + (nHeightBUV - 1) * nDstPitches[1], nDstPitches[1], nWidthUV, nHeightUV - nHeightBUV); vs_bitblt(pDst[2] + nHeightBUV * nDstPitches[2], nDstPitches[2], pDst[2] + (nHeightBUV - 1) * nDstPitches[2], nDstPitches[2], nWidthUV, nHeightUV - nHeightBUV); } free(smallMask); free(smallMaskV); } else { // not usable if (kind == 5) memcpy(pDst[0], pSrc[0], nSrcPitches[0] * nHeight); else memset(pDst[0], nSceneChangeValue, nHeight * nDstPitches[0]); memset(pDst[1], nSceneChangeValue, nHeightUV * nDstPitches[1]); memset(pDst[2], nSceneChangeValue, nHeightUV * nDstPitches[2]); } fgopDeinit(&fgop); vsapi->freeFrame(src); return dst; } return 0; }