Skip to content

Commit

Permalink
Support 32 bit depth
Browse files Browse the repository at this point in the history
  • Loading branch information
HolyWu committed Apr 3, 2018
1 parent 25bea14 commit fa26097
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 11 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Usage

ttmpsm.TTempSmooth(clip clip[, int maxr=3, int[] thresh=[4, 5, 5], int[] mdiff=[2, 3, 3], int strength=2, float scthresh=12.0, bint fp=True, clip pfclip=None, int[] planes])

* clip: Clip to process. Any planar format with integer sample type of 8-16 bit depth is supported.
* clip: Clip to process. Any planar format with either integer sample type of 8-16 bit depth or float sample type of 32 bit depth is supported.

* maxr: This sets the maximum temporal radius. By the way it works TTempSmooth automatically varies the radius used... this sets the maximum boundary. Possible values are 1 through 7. At 1 TTempSmooth will be (at max) including pixels from 1 frame away in the average (3 frames total will be considered counting the current frame). At 7 it would be including pixels from up to 7 frames away (15 frames total will be considered). With the way it checks motion there isn't much danger in setting this high, it's basically a quality vs. speed option. Lower settings are faster while larger values tend to create a more stable image.

Expand Down
130 changes: 121 additions & 9 deletions TTempSmooth/TTempSmooth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <memory>
#include <string>
Expand All @@ -38,13 +39,14 @@ struct TTempSmoothData {
double scthresh;
bool fp, process[3];
int diameter, shift;
float threshF[3];
unsigned * weight[3], cw;
void (*filter[3])(const VSFrameRef *[15], const VSFrameRef *[15], VSFrameRef *, const int, const int, const int, const TTempSmoothData * const VS_RESTRICT, const VSAPI *);
};

template<typename T1, typename T2, bool useDiff>
static void filter(const VSFrameRef * src[15], const VSFrameRef * pf[15], VSFrameRef * dst, const int fromFrame, const int toFrame, const int plane,
const TTempSmoothData * const VS_RESTRICT d, const VSAPI * vsapi) noexcept {
static void filterI(const VSFrameRef * src[15], const VSFrameRef * pf[15], VSFrameRef * dst, const int fromFrame, const int toFrame, const int plane,
const TTempSmoothData * const VS_RESTRICT d, const VSAPI * vsapi) noexcept {
const int width = vsapi->getFrameWidth(dst, plane);
const int height = vsapi->getFrameHeight(dst, plane);
const int stride = vsapi->getStride(dst, plane) / sizeof(T1);
Expand Down Expand Up @@ -144,19 +146,125 @@ static void filter(const VSFrameRef * src[15], const VSFrameRef * pf[15], VSFram
}
}

template<bool useDiff>
static void filterF(const VSFrameRef * src[15], const VSFrameRef * pf[15], VSFrameRef * dst, const int fromFrame, const int toFrame, const int plane,
const TTempSmoothData * const VS_RESTRICT d, const VSAPI * vsapi) noexcept {
const int width = vsapi->getFrameWidth(dst, plane);
const int height = vsapi->getFrameHeight(dst, plane);
const int stride = vsapi->getStride(dst, plane) / sizeof(float);
const float * srcp[15] = {}, * pfp[15] = {};
for (int i = 0; i < d->diameter; i++) {
srcp[i] = reinterpret_cast<const float *>(vsapi->getReadPtr(src[i], plane));
pfp[i] = reinterpret_cast<const float *>(vsapi->getReadPtr(pf[i], plane));
}
float * VS_RESTRICT dstp = reinterpret_cast<float *>(vsapi->getWritePtr(dst, plane));

const float thresh = d->threshF[plane];
const unsigned * const weightSaved = d->weight[plane];

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
const float c = pfp[d->maxr][x];
unsigned weights = d->cw;
float sum = srcp[d->maxr][x] * d->cw;

int frameIndex = d->maxr - 1;

if (frameIndex > fromFrame) {
float t1 = pfp[frameIndex][x];
float diff = std::abs(c - t1);

if (diff < thresh) {
unsigned weight = weightSaved[useDiff ? static_cast<int>(diff * 255.f) : frameIndex];
weights += weight;
sum += srcp[frameIndex][x] * weight;

frameIndex--;
int v = 256;

while (frameIndex > fromFrame) {
const float t2 = t1;
t1 = pfp[frameIndex][x];
diff = std::abs(c - t1);

if (diff < thresh && std::abs(t1 - t2) < thresh) {
weight = weightSaved[useDiff ? static_cast<int>(diff * 255.f) + v : frameIndex];
weights += weight;
sum += srcp[frameIndex][x] * weight;

frameIndex--;
v += 256;
} else {
break;
}
}
}
}

frameIndex = d->maxr + 1;

if (frameIndex < toFrame) {
float t1 = pfp[frameIndex][x];
float diff = std::abs(c - t1);

if (diff < thresh) {
unsigned weight = weightSaved[useDiff ? static_cast<int>(diff * 255.f) : frameIndex];
weights += weight;
sum += srcp[frameIndex][x] * weight;

frameIndex++;
int v = 256;

while (frameIndex < toFrame) {
const float t2 = t1;
t1 = pfp[frameIndex][x];
diff = std::abs(c - t1);

if (diff < thresh && std::abs(t1 - t2) < thresh) {
weight = weightSaved[useDiff ? static_cast<int>(diff * 255.f) + v : frameIndex];
weights += weight;
sum += srcp[frameIndex][x] * weight;

frameIndex++;
v += 256;
} else {
break;
}
}
}
}

if (d->fp)
dstp[x] = (srcp[d->maxr][x] * (65536 - weights) + sum) / 65536.f;
else
dstp[x] = sum / weights;
}

for (int i = 0; i < d->diameter; i++) {
srcp[i] += stride;
pfp[i] += stride;
}
dstp += stride;
}
}

static void selectFunctions(TTempSmoothData * d) noexcept {
for (int plane = 0; plane < d->vi->format->numPlanes; plane++) {
if (d->process[plane]) {
if (d->thresh[plane] > d->mdiff[plane] + 1) {
if (d->vi->format->bytesPerSample == 1)
d->filter[plane] = filter<uint8_t, uint32_t, true>;
d->filter[plane] = filterI<uint8_t, uint32_t, true>;
else if (d->vi->format->bytesPerSample == 2)
d->filter[plane] = filterI<uint16_t, uint64_t, true>;
else
d->filter[plane] = filter<uint16_t, uint64_t, true>;
d->filter[plane] = filterF<true>;
} else {
if (d->vi->format->bytesPerSample == 1)
d->filter[plane] = filter<uint8_t, uint32_t, false>;
d->filter[plane] = filterI<uint8_t, uint32_t, false>;
else if (d->vi->format->bytesPerSample == 2)
d->filter[plane] = filterI<uint16_t, uint64_t, false>;
else
d->filter[plane] = filter<uint16_t, uint64_t, false>;
d->filter[plane] = filterF<false>;
}
}
}
Expand Down Expand Up @@ -253,8 +361,9 @@ static void VS_CC ttempsmoothCreate(const VSMap *in, VSMap *out, void *userData,
d->vi = vsapi->getVideoInfo(d->node);

try {
if (!isConstantFormat(d->vi) || d->vi->format->sampleType != stInteger || d->vi->format->bitsPerSample > 16)
throw std::string{ "only constant format 8-16 bit integer input supported" };
if (!isConstantFormat(d->vi) || (d->vi->format->sampleType == stInteger && d->vi->format->bitsPerSample > 16) ||
(d->vi->format->sampleType == stFloat && d->vi->format->bitsPerSample != 32))
throw std::string{ "only constant format 8-16 bit integer and 32 bit float input supported" };

d->maxr = int64ToIntS(vsapi->propGetInt(in, "maxr", 0, &err));
if (err)
Expand Down Expand Up @@ -408,7 +517,10 @@ static void VS_CC ttempsmoothCreate(const VSMap *in, VSMap *out, void *userData,
d->cw = d->weight[plane][d->maxr];
}

d->thresh[plane] <<= d->shift;
if (d->vi->format->sampleType == stInteger)
d->thresh[plane] <<= d->shift;
else
d->threshF[plane] = d->thresh[plane] / 256.f;
}
}

Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AC_INIT([TTempSmooth], [1], [https://github.com/HomeOfVapourSynthEvolution/VapourSynth-TTempSmooth/issues], [TTempSmooth], [https://github.com/HomeOfVapourSynthEvolution/VapourSynth-TTempSmooth/])
AC_INIT([TTempSmooth], [2], [https://github.com/HomeOfVapourSynthEvolution/VapourSynth-TTempSmooth/issues], [TTempSmooth], [https://github.com/HomeOfVapourSynthEvolution/VapourSynth-TTempSmooth/])

: ${CXXFLAGS=""}

Expand Down

0 comments on commit fa26097

Please sign in to comment.