|
| 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 | +} |
0 commit comments