Skip to content

Commit 96aae39

Browse files
committed
RFF Support
Support apply RFF flags to arbitrart clips. Signed-off-by: Derek Buitenhuis <[email protected]>
1 parent be7384d commit 96aae39

File tree

5 files changed

+304
-3
lines changed

5 files changed

+304
-3
lines changed

README

+29-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ There's not much else to say, so let's get right to an example:
1111
core.std.LoadPlugin(path=r'C:\path\to\d2vsource.dll')
1212

1313
ret = core.d2v.Source(input=r'C:\path\to\my.d2v')
14+
ret = core.d2v.ApplyRFF(ret, d2v=r'C:\path\to\my.d2v')
1415

1516
last = ret
1617

@@ -20,7 +21,32 @@ Parameters:
2021
Provides a speedup when you know you need to crop your image
2122
anyway, by avoiding extra memcpy calls.
2223

23-
There's not much else to it!
24+
25+
About RFF Flags
26+
---------------
27+
28+
Unlike DGDecode, it's up to the user to apply RFF flags as they see fit
29+
using core.d2v.ApplyRFF(clip, d2v=r'C:\path\to\my.d2v') after calling
30+
the source function. Unless you know your source is 100% FILM, you
31+
probably want to apply these. DGDecode's traditional "Force FILM" mode
32+
isn't really present in this plugin, but if your source or part of it
33+
is 100% FILM, which is the only time you should be Force FILMing anyway,
34+
you can simply set Force FILM in DGIndex, which will set the framerate
35+
properly in the D2V file, and then not apply RFF flags. It's also
36+
feasible to trim away any non-FILM frames and still Force FILM.
37+
38+
A simple convenience function is:
39+
40+
def D2VSource(d2vfile, cropping):
41+
clip = core.d2v.Source(input=d2vfile, nocrop=cropping)
42+
clip = core.d2v.ApplyRFF(clip, d2v=d2vfile)
43+
return clip
44+
45+
Parameters:
46+
clip - Input clip.
47+
d2v - D2V file for parsing RFF flags. This will be optional
48+
in the future, once VapourSynth gets global metadata
49+
support.
2450

2551

2652
Known Limitations & Bugs
@@ -53,8 +79,8 @@ On Windows (Visual Studio):
5379
This assumes that you have the proper dependency paths in %INCLUDE% and %LIB%,
5480
and that you have built FFmpeg with Visual Studio as well.
5581

56-
cl /c /O2 /MT /EHsc /Icore /Ivs core/d2v.cpp core/compat.cpp core/decode.cpp vs/directrender.cpp vs/d2vsource.cpp
57-
link /dll /out:d2vsource.dll directrender.obj d2vsource.obj d2v.obj compat.obj decode.obj libavutil.a libavformat.a libavcodec.a advapi32.lib ws2_32.lib
82+
cl /c /O2 /MT /EHsc /Icore /Ivs core/d2v.cpp core/compat.cpp core/decode.cpp vs/directrender.cpp vs/applyrff.cpp vs/d2vsource.cpp
83+
link /dll /out:d2vsource.dll directrender.obj applyrff.obj d2vsource.obj d2v.obj compat.obj decode.obj libavutil.a libavformat.a libavcodec.a advapi32.lib ws2_32.lib
5884

5985
Please note that MinGW-build FFmpeg will be faster than one build with Visual
6086
Studio, due to its use of inline assembly. Also note that only MinGW-w64 is

core/gop.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extern "C" {
3131

3232
#define GOP_FLAG_CLOSED 0x400
3333

34+
#define FRAME_FLAG_RFF 0x01
35+
3436
using namespace std;
3537

3638
typedef struct frame {

vs/applyrff.cpp

+222
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* VapourSynth D2V Plugin
3+
*
4+
* Copyright (c) 2012 Derek Buitenhuis
5+
*
6+
* This file is part of d2vsource.
7+
*
8+
* d2vsource is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* d2vsource is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with d2vsource; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
23+
extern "C" {
24+
#include <stdint.h>
25+
#include <stdlib.h>
26+
}
27+
28+
#include <VapourSynth.h>
29+
#include <VSHelper.h>
30+
31+
#include "applyrff.hpp"
32+
#include "d2v.hpp"
33+
#include "gop.hpp"
34+
35+
void VS_CC rffInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi)
36+
{
37+
rffData *d = (rffData *) *instanceData;
38+
vsapi->setVideoInfo(&d->vi, 1, node);
39+
}
40+
41+
const VSFrameRef *VS_CC rffGetFrame(int n, int activationReason, void **instanceData, void **frameData,
42+
VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi)
43+
{
44+
rffData *d = (rffData *) *instanceData;
45+
VSFrameRef *st, *sb, *f;
46+
string msg;
47+
int top, bottom;
48+
int dst_stride[3], srct_stride[3], srcb_stride[3];
49+
int i;
50+
bool samefields;
51+
52+
/* What frames to use for fields. */
53+
top = d->frames[n].top;
54+
bottom = d->frames[n].bottom;
55+
56+
samefields = top == bottom;
57+
58+
/* Request out source frames. */
59+
if (activationReason == arInitial) {
60+
if (samefields) {
61+
vsapi->requestFrameFilter(top, d->node, frameCtx);
62+
} else {
63+
vsapi->requestFrameFilter(top, d->node, frameCtx);
64+
vsapi->requestFrameFilter(bottom, d->node, frameCtx);
65+
}
66+
return NULL;
67+
}
68+
69+
/* Check if we're ready yet. */
70+
if (activationReason != arAllFramesReady)
71+
return NULL;
72+
73+
/* Source and destination frames. */
74+
st = (VSFrameRef *) vsapi->getFrameFilter(top, d->node, frameCtx);
75+
sb = samefields ? NULL : (VSFrameRef *) vsapi->getFrameFilter(bottom, d->node, frameCtx);
76+
f = vsapi->newVideoFrame(d->vi.format, d->vi.width, d->vi.height, NULL, core);
77+
78+
/* Stash our strides for convenience. */
79+
for(i = 0; i < 3; i++) {
80+
dst_stride[i] = vsapi->getStride(f, i);
81+
srct_stride[i] = vsapi->getStride(st, i);
82+
srcb_stride[i] = samefields ? 0 : vsapi->getStride(sb, i);
83+
}
84+
85+
/* Copy into VS's buffers. */
86+
if (samefields) {
87+
/* Luma. */
88+
vs_bitblt(vsapi->getWritePtr(f, 0), dst_stride[0], vsapi->getWritePtr(st, 0), srct_stride[0],
89+
d->vi.width, d->vi.height);
90+
91+
/* Chroma. */
92+
vs_bitblt(vsapi->getWritePtr(f, 1), dst_stride[1], vsapi->getWritePtr(st, 1), srct_stride[1],
93+
d->vi.width >> d->vi.format->subSamplingW, d->vi.height >> d->vi.format->subSamplingH);
94+
vs_bitblt(vsapi->getWritePtr(f, 2), dst_stride[2], vsapi->getWritePtr(st, 2), srct_stride[2],
95+
d->vi.width >> d->vi.format->subSamplingW, d->vi.height >> d->vi.format->subSamplingH);
96+
} else {
97+
/* Luma. */
98+
vs_bitblt(vsapi->getWritePtr(f, 0), dst_stride[0] * 2,
99+
vsapi->getWritePtr(st, 0), srct_stride[0] * 2,
100+
d->vi.width, d->vi.height / 2);
101+
vs_bitblt(vsapi->getWritePtr(f, 0) + dst_stride[0], dst_stride[0] * 2,
102+
vsapi->getWritePtr(sb, 0) + srcb_stride[0], srcb_stride[0] * 2,
103+
d->vi.width, d->vi.height / 2);
104+
105+
/* Chroma. */
106+
vs_bitblt(vsapi->getWritePtr(f, 1), dst_stride[1] * 2,
107+
vsapi->getWritePtr(st, 1), srct_stride[1] * 2,
108+
d->vi.width >> d->vi.format->subSamplingW, (d->vi.height >> d->vi.format->subSamplingH) / 2);
109+
vs_bitblt(vsapi->getWritePtr(f, 1) + dst_stride[1], dst_stride[1] * 2,
110+
vsapi->getWritePtr(sb, 1) + srcb_stride[1], srcb_stride[1] * 2,
111+
d->vi.width >> d->vi.format->subSamplingW, (d->vi.height >> d->vi.format->subSamplingH) / 2);
112+
113+
vs_bitblt(vsapi->getWritePtr(f, 2), dst_stride[2] * 2,
114+
vsapi->getWritePtr(st, 2), srct_stride[2] * 2,
115+
d->vi.width >> d->vi.format->subSamplingW, (d->vi.height >> d->vi.format->subSamplingH) / 2);
116+
vs_bitblt(vsapi->getWritePtr(f, 2) + dst_stride[2], dst_stride[2] * 2,
117+
vsapi->getWritePtr(sb, 2) + srcb_stride[2], srcb_stride[2] * 2,
118+
d->vi.width >> d->vi.format->subSamplingW, (d->vi.height >> d->vi.format->subSamplingH) / 2);
119+
}
120+
121+
vsapi->freeFrame(st);
122+
if (!samefields)
123+
vsapi->freeFrame(sb);
124+
125+
return f;
126+
}
127+
128+
void VS_CC rffFree(void *instanceData, VSCore *core, const VSAPI *vsapi)
129+
{
130+
rffData *d = (rffData *) instanceData;
131+
vsapi->freeNode(d->node);
132+
d2vfreep(&d->d2v);
133+
d->frames.clear();
134+
delete d;
135+
}
136+
137+
void VS_CC rffCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi)
138+
{
139+
rffData *data;
140+
VSVideoInfo *vi;
141+
fieldFrame ff = { -1, -1 };
142+
string msg;
143+
int total_fields;
144+
int i;
145+
146+
/* Allocate our private data. */
147+
data = new rffData;
148+
if (!data) {
149+
vsapi->setError(out, "Cannot allocate private data.");
150+
return;
151+
}
152+
153+
/* Parse the D2V to get flags. */
154+
data->d2v = d2vparse((char *) vsapi->propGetData(in, "d2v", 0, 0), msg);
155+
if (!data->d2v) {
156+
vsapi->setError(out, msg.c_str());
157+
return;
158+
}
159+
160+
/* Get our frame info and copy it, so we can modify it after. */
161+
data->node = vsapi->propGetNode(in, "clip", 0, 0);
162+
vi = (VSVideoInfo *) vsapi->getVideoInfo(data->node);
163+
data->vi = *vi;
164+
165+
/*
166+
* Parse all the RFF flags to figure out which fields go
167+
* with which frames, and out total number of frames after
168+
* apply the RFF flags.
169+
*/
170+
total_fields = 0;
171+
data->frames.push_back(ff);
172+
for(i = 0; i < data->vi.numFrames; i++) {
173+
frame f = data->d2v->frames[i];
174+
int rff = data->d2v->gops[f.gop].flags[f.offset] & FRAME_FLAG_RFF;
175+
int pos = data->frames.size() - 1;
176+
177+
if (rff) {
178+
if (data->frames[pos].top == -1) {
179+
data->frames[pos].top = i;
180+
data->frames[pos].bottom = i;
181+
182+
ff.top = i;
183+
ff.bottom = -1;
184+
} else if (data->frames[pos].bottom == -1) {
185+
data->frames[pos].bottom = i;
186+
187+
ff.top = i;
188+
ff.bottom = i;
189+
} else {
190+
ff.top = i;
191+
ff.bottom = i;
192+
193+
data->frames.push_back(ff);
194+
195+
ff.bottom = -1;
196+
}
197+
} else {
198+
if (data->frames[pos].top == -1) {
199+
data->frames[pos].top = i;
200+
data->frames[pos].bottom = i;
201+
202+
ff.top = -1;
203+
ff.bottom = -1;
204+
} else if (data->frames[pos].bottom == -1) {
205+
data->frames[pos].bottom = i;
206+
207+
ff.top = i;
208+
ff.bottom = -1;
209+
} else {
210+
ff.top = i;
211+
ff.bottom = i;
212+
}
213+
}
214+
data->frames.push_back(ff);
215+
216+
total_fields += 2 + rff;
217+
}
218+
219+
data->vi.numFrames = total_fields / 2;
220+
221+
vsapi->createFilter(in, out, "applyrff", rffInit, rffGetFrame, rffFree, fmSerial, 0, data, core);
222+
}

vs/applyrff.hpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* VapourSynth D2V Plugin
3+
*
4+
* Copyright (c) 2012 Derek Buitenhuis
5+
*
6+
* This file is part of d2vsource.
7+
*
8+
* d2vsource is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* d2vsource is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with d2vsource; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
23+
#ifndef APPLYRFF_H
24+
#define APPLYRFF_H
25+
26+
#include <VapourSynth.h>
27+
#include <VSHelper.h>
28+
29+
#include "d2v.hpp"
30+
31+
typedef struct fieldFrame {
32+
int top;
33+
int bottom;
34+
} fieldFrame;
35+
36+
typedef struct rffData {
37+
d2vcontext *d2v;
38+
vector<fieldFrame> frames;
39+
40+
VSVideoInfo vi;
41+
VSNodeRef *node;
42+
} rffData;
43+
44+
void VS_CC rffInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi);
45+
void VS_CC rffFree(void *instanceData, VSCore *core, const VSAPI *vsapi);
46+
void VS_CC rffCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi);
47+
const VSFrameRef *VS_CC rffGetFrame(int n, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi);
48+
49+
#endif

vs/vapoursynth.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ extern "C" {
2828
#include <VapourSynth.h>
2929
#include <VSHelper.h>
3030

31+
#include "applyrff.hpp"
3132
#include "d2vsource.hpp"
3233

3334
VS_EXTERNAL_API(void) VapourSynthPluginInit(VSConfigPlugin configFunc, VSRegisterFunction registerFunc, VSPlugin *plugin)
3435
{
3536
configFunc("com.sources.d2vsource", "d2v", "D2V Source", VAPOURSYNTH_API_VERSION, 1, plugin);
3637
registerFunc("Source", "input:data;nocrop:int:opt;", d2vCreate, 0, plugin);
38+
registerFunc("ApplyRFF", "clip:clip;d2v:data;", rffCreate, 0, plugin);
3739
}

0 commit comments

Comments
 (0)