Implement multi-input OFX clip wiring and texture handling
Store PluginJob input values for lookup Add per-clip texture inputs on plugin nodes Map input clips to textures during render (with Source fallback)
This commit is contained in:
+151
-16
@@ -24,6 +24,18 @@
|
||||
#include "OliveClip.h"
|
||||
|
||||
#include "common/Current.h"
|
||||
#include "common/ffmpegutils.h"
|
||||
#include "ofxCore.h"
|
||||
#include "ofxhClip.h"
|
||||
#include "pluginSupport/image.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
extern "C" {
|
||||
#include <libswscale/swscale.h>
|
||||
}
|
||||
const std::string &olive::plugin::OliveClipInstance::getUnmappedBitDepth() const
|
||||
{
|
||||
switch (params_.format()) {
|
||||
@@ -65,9 +77,7 @@ const std::string &olive::plugin::OliveClipInstance::getPremult() const
|
||||
}
|
||||
double olive::plugin::OliveClipInstance::getAspectRatio() const
|
||||
{
|
||||
return params_
|
||||
.pixel_aspect_ratio()
|
||||
.toDouble();
|
||||
return params_.pixel_aspect_ratio().toDouble();
|
||||
}
|
||||
double olive::plugin::OliveClipInstance::getFrameRate() const
|
||||
{
|
||||
@@ -76,13 +86,9 @@ double olive::plugin::OliveClipInstance::getFrameRate() const
|
||||
void olive::plugin::OliveClipInstance::getFrameRange(double &startFrame,
|
||||
double &endFrame) const
|
||||
{
|
||||
startFrame =
|
||||
params_.frame_rate().toDouble() *
|
||||
params_.start_time();
|
||||
startFrame = params_.frame_rate().toDouble() * params_.start_time();
|
||||
endFrame =
|
||||
startFrame +
|
||||
params_.frame_rate().toDouble() *
|
||||
params_.duration();
|
||||
startFrame + params_.frame_rate().toDouble() * params_.duration();
|
||||
}
|
||||
const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const
|
||||
{
|
||||
@@ -98,8 +104,7 @@ const std::string &olive::plugin::OliveClipInstance::getFieldOrder() const
|
||||
}
|
||||
bool olive::plugin::OliveClipInstance::getConnected() const
|
||||
{
|
||||
return params_.format() ==
|
||||
PixelFormat::INVALID;
|
||||
return params_.format() == PixelFormat::INVALID;
|
||||
}
|
||||
double olive::plugin::OliveClipInstance::getUnmappedFrameRate() const
|
||||
{
|
||||
@@ -118,7 +123,54 @@ OFX::Host::ImageEffect::Image *
|
||||
olive::plugin::OliveClipInstance::getImage(OfxTime time,
|
||||
const OfxRectD *optionalBounds)
|
||||
{
|
||||
return &image_;
|
||||
OfxRectI bounds = {0, 0, params_.width(), params_.height()};
|
||||
if (optionalBounds) {
|
||||
bounds.x1 = static_cast<int>(std::floor(optionalBounds->x1));
|
||||
bounds.y1 = static_cast<int>(std::floor(optionalBounds->y1));
|
||||
bounds.x2 = static_cast<int>(std::ceil(optionalBounds->x2));
|
||||
bounds.y2 = static_cast<int>(std::ceil(optionalBounds->y2));
|
||||
}
|
||||
|
||||
OfxRectD rod_d = getRegionOfDefinition(time);
|
||||
OfxRectI rod = { static_cast<int>(std::floor(rod_d.x1)),
|
||||
static_cast<int>(std::floor(rod_d.y1)),
|
||||
static_cast<int>(std::ceil(rod_d.x2)),
|
||||
static_cast<int>(std::ceil(rod_d.y2)) };
|
||||
|
||||
if (name_ == "Output") {
|
||||
if (!images_.contains(time)) {
|
||||
// make a new ref counted image
|
||||
images_.insert(time, std::make_shared<Image>(*const_cast<OliveClipInstance *>(this),
|
||||
params_, bounds, rod, true));
|
||||
}
|
||||
|
||||
// add another reference to the member image for this fetch
|
||||
// as we have a ref count of 1 due to construction, this will
|
||||
// cause the output image never to delete by the plugin
|
||||
// when it releases the image
|
||||
images_[time]->addReference();
|
||||
|
||||
images_[time]->EnsureAllocatedFromParams(params_, bounds, rod, true);
|
||||
|
||||
// return it
|
||||
return images_[time].get();
|
||||
} else {
|
||||
if (images_.contains(time)) {
|
||||
std::shared_ptr<Image> image = images_.value(time);
|
||||
image->EnsureAllocatedFromParams(params_, bounds, rod, false);
|
||||
image->addReference();
|
||||
return image.get();
|
||||
}
|
||||
|
||||
// Fetch on demand for the input clip.
|
||||
// It does get deleted after the plugin is done with it as we
|
||||
// have not incremented the auto ref
|
||||
//
|
||||
// You should do somewhat more sophisticated image management
|
||||
// than this.
|
||||
Image *image = new Image(*this, params_, bounds, rod, true);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
OfxRectD
|
||||
olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
||||
@@ -127,9 +179,9 @@ olive::plugin::OliveClipInstance::getRegionOfDefinition(OfxTime time) const
|
||||
return regionOfDefinitions_[time];
|
||||
}
|
||||
OfxRectD regionOfDefinition;
|
||||
regionOfDefinition.x1=regionOfDefinition.y1=0;
|
||||
regionOfDefinition.x2=params_.width();
|
||||
regionOfDefinition.y2=params_.height();
|
||||
regionOfDefinition.x1 = regionOfDefinition.y1 = 0;
|
||||
regionOfDefinition.x2 = params_.width();
|
||||
regionOfDefinition.y2 = params_.height();
|
||||
return regionOfDefinition;
|
||||
}
|
||||
void olive::plugin::OliveClipInstance::setRegionOfDefinition(
|
||||
@@ -142,4 +194,87 @@ void olive::plugin::OliveClipInstance::setDefaultRegionOfDefinition(
|
||||
OfxRectD regionOfDefinition)
|
||||
{
|
||||
defaultRegionOfDefinitions_ = regionOfDefinition;
|
||||
}
|
||||
}
|
||||
void olive::plugin::OliveClipInstance::setInputTexture(TexturePtr texture, OfxTime time){
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
AVFramePtr frame = texture->frame();
|
||||
if (!frame || !frame->data[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->params_=texture->params();
|
||||
AVPixelFormat expected_fmt =
|
||||
FFmpegUtils::GetFFmpegPixelFormat(params_.format(),
|
||||
params_.channel_count());
|
||||
if (expected_fmt == AV_PIX_FMT_NONE) {
|
||||
return;
|
||||
}
|
||||
OfxRectI bounds = { 0, 0, params_.width(), params_.height() };
|
||||
OfxRectD rod_d = getRegionOfDefinition(time);
|
||||
OfxRectI regionOfDefinition = { static_cast<int>(std::floor(rod_d.x1)),
|
||||
static_cast<int>(std::floor(rod_d.y1)),
|
||||
static_cast<int>(std::ceil(rod_d.x2)),
|
||||
static_cast<int>(std::ceil(rod_d.y2)) };
|
||||
|
||||
std::shared_ptr<Image> image;
|
||||
if (images_.contains(time)) {
|
||||
image = images_.value(time);
|
||||
image->EnsureAllocatedFromParams(params_, bounds, regionOfDefinition,
|
||||
false);
|
||||
} else {
|
||||
image = std::make_shared<Image>(*this, params_, bounds,
|
||||
regionOfDefinition, false);
|
||||
images_.insert(time, image);
|
||||
}
|
||||
|
||||
uint8_t *dst = image->data();
|
||||
if (!dst) {
|
||||
return;
|
||||
}
|
||||
|
||||
AVFramePtr src_frame = frame;
|
||||
if (frame->format != expected_fmt ||
|
||||
frame->width != params_.width() ||
|
||||
frame->height != params_.height()) {
|
||||
AVFramePtr converted = CreateAVFramePtr();
|
||||
converted->format = expected_fmt;
|
||||
converted->width = params_.width();
|
||||
converted->height = params_.height();
|
||||
if (av_frame_get_buffer(converted.get(), 0) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwsContext *sws_ctx = sws_getContext(
|
||||
frame->width, frame->height,
|
||||
static_cast<AVPixelFormat>(frame->format),
|
||||
converted->width, converted->height,
|
||||
static_cast<AVPixelFormat>(converted->format),
|
||||
SWS_POINT, nullptr, nullptr, nullptr);
|
||||
if (!sws_ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height,
|
||||
converted->data, converted->linesize);
|
||||
sws_freeContext(sws_ctx);
|
||||
|
||||
src_frame = converted;
|
||||
}
|
||||
|
||||
int bytes_per_component = params_.format().byte_count();
|
||||
int bytes_per_row = params_.width() * params_.channel_count() *
|
||||
bytes_per_component;
|
||||
int src_row_bytes = src_frame->linesize[0];
|
||||
int dst_row_bytes = image->row_bytes();
|
||||
int copy_bytes = std::min(bytes_per_row,
|
||||
std::min(src_row_bytes, dst_row_bytes));
|
||||
int copy_height = std::min(image->height(), src_frame->height);
|
||||
|
||||
const uint8_t *src = src_frame->data[0];
|
||||
for (int y = 0; y < copy_height; ++y) {
|
||||
std::memcpy(dst + y * dst_row_bytes, src + y * src_row_bytes,
|
||||
copy_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user