Skip to content

Commit

Permalink
Add quad filter demo. Rework how resizing works.
Browse files Browse the repository at this point in the history
  • Loading branch information
rectalogic committed Oct 9, 2023
1 parent a58d740 commit e5498be
Show file tree
Hide file tree
Showing 22 changed files with 101 additions and 57 deletions.
3 changes: 0 additions & 3 deletions demo/examples/filter-banner.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import QtQuick
import QtMultimedia

Rectangle {
width: webvfx.videoSize.width
height: webvfx.videoSize.height

VideoOutput {
id: video
anchors.fill: parent
Expand Down
2 changes: 0 additions & 2 deletions demo/examples/filter-demo.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import QtQuick
import QtMultimedia

Rectangle {
width: webvfx.videoSize.width
height: webvfx.videoSize.height
color: "lightgray"

VideoOutput {
Expand Down
44 changes: 44 additions & 0 deletions demo/examples/filter-quad.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import QtQuick
import QtQuick.Layouts
import QtMultimedia

GridLayout {
id: grid
columns: 2

VideoOutput {
id: tlVideo
Layout.column: 0
Layout.row: 0
Layout.fillWidth: true
Layout.fillHeight: true
}
VideoOutput {
id: trVideo
Layout.column: 1
Layout.row: 0
Layout.fillWidth: true
Layout.fillHeight: true
}
VideoOutput {
id: blVideo
Layout.column: 0
Layout.row: 1
Layout.fillWidth: true
Layout.fillHeight: true
}
VideoOutput {
id: brVideo
Layout.column: 1
Layout.row: 1
Layout.fillWidth: true
Layout.fillHeight: true
}
Component.onCompleted: {
var videoSource = webvfx.addVideoSource();
webvfx.appendVideoSink(videoSource, tlVideo.videoSink);
webvfx.appendVideoSink(videoSource, trVideo.videoSink);
webvfx.appendVideoSink(videoSource, blVideo.videoSink);
webvfx.appendVideoSink(videoSource, brVideo.videoSink);
}
}
2 changes: 0 additions & 2 deletions demo/examples/producer-demo.qml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import QtQuick.Shapes 1.0

Shape {
id: shape
width: webvfx.videoSize.width
height: webvfx.videoSize.height
anchors.centerIn: parent
ShapePath {
fillGradient: RadialGradient {
Expand Down
2 changes: 0 additions & 2 deletions demo/examples/transition-demo3d.qml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import stream.webvfx.WebVfx

View3D {
id: view
width: webvfx.videoSize.width
height: webvfx.videoSize.height

environment: SceneEnvironment {
clearColor: "skyblue"
Expand Down
3 changes: 0 additions & 3 deletions demo/examples/transition-shader-crosszoom.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import QtQuick 2.0
import QtMultimedia

Rectangle {
width: webvfx.videoSize.width
height: webvfx.videoSize.height

VideoOutput {
id: sourceVideo
anchors.fill: parent
Expand Down
9 changes: 3 additions & 6 deletions demo/examples/transition-shader-pagecurl.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ import QtQuick 2.0
import QtMultimedia

Rectangle {
width: webvfx.videoSize.width
height: webvfx.videoSize.height

VideoOutput {
VideoOutput {
id: sourceVideo
anchors.fill: parent
visible: false
layer.enabled: true
}
VideoOutput {
}
VideoOutput {
id: targetVideo
anchors.fill: parent
visible: false
Expand Down
15 changes: 10 additions & 5 deletions demo/examples/transition-simple.qml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import QtQuick
import QtMultimedia

Rectangle {
width: webvfx.videoSize.width
height: webvfx.videoSize.height
id: root
color: "lightgray"

VideoOutput {
Expand Down Expand Up @@ -37,6 +36,15 @@ Rectangle {
id: animationController
animation: animation
}
Connections {
target: root
function onWidthChanged(w) {
animationController.reload();
}
function onHeightChanged(h) {
animationController.reload();
}
}
Component.onCompleted: {
webvfx.appendVideoSink(webvfx.addVideoSource(), sourceVideo.videoSink);
webvfx.appendVideoSink(webvfx.addVideoSource(), targetVideo.videoSink);
Expand All @@ -46,8 +54,5 @@ Rectangle {
function onRenderRequested(time) {
animationController.progress = time;
}
function onVideoSizeChanged(size) {
animationController.reload();
}
}
}
16 changes: 16 additions & 0 deletions demo/mlt/mlt_filter_quad
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

BASEDIR=$(dirname "${BASH_SOURCE[0]}")
export DISPLAY=${DISPLAY:-:0}
case ${PLUGIN:-frei0r} in
frei0r)
FILTER=("frei0r.webvfx_filter" "0=\"\"${BASEDIR}/../examples/filter-quad.qml?webvfx_duration=300/30\"\"")
;;
mlt)
FILTER=(mltwebvfx:"${BASEDIR}/../examples/filter-quad.qml")
;;
esac
REDTESTSRC=lavfi:$(COLOR=red ${BASEDIR}/tests/testsrc)
melt -verbose "${VFX_SOURCE:-${REDTESTSRC}}" out=299 \
-filter "${FILTER[@]}" out=299 \
$(eval echo $(< "${VFX_CONSUMER:-${BASEDIR}/consumer_sdl}")) mlt_profile=${BASEDIR}/webvfx_profile
1 change: 1 addition & 0 deletions demo/mlt/tests/extract_frames
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ OUTPUT_DIR=${1:?Usage: $(basename $0) OUTPUT_DIR}

${BASEDIR}/extract_frame -s 00:00:04 "${BASEDIR}/../mlt_filter_banner" "${OUTPUT_DIR}/filter_banner.png"
${BASEDIR}/extract_frame -s 00:00:04 "${BASEDIR}/../mlt_filter_demo" "${OUTPUT_DIR}/filter_demo.png"
${BASEDIR}/extract_frame -s 00:00:04 "${BASEDIR}/../mlt_filter_quad" "${OUTPUT_DIR}/filter_quad.png"
${BASEDIR}/extract_frame -s 00:00:04 "${BASEDIR}/../mlt_producer_demo" "${OUTPUT_DIR}/producer_demo.png"
${BASEDIR}/extract_frame -s 00:00:09 "${BASEDIR}/../mlt_transition_demo3d" "${OUTPUT_DIR}/transition_demo3d.png"
${BASEDIR}/extract_frame -s 00:00:09 "${BASEDIR}/../mlt_transition_shader_crosszoom_extra" "${OUTPUT_DIR}/transition_shader_crosszoom.png"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/mlt/tests/fixtures/linux/mlt/filter_quad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demo/mlt/tests/fixtures/macos/mlt/filter_quad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 17 additions & 6 deletions vfxpipe/vfxpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace VfxPipe {

std::tuple<int, uint32_t> spawnProcess(int* pipeReadStdout, int* pipeWriteStdin, int* pipeReadStderr, const std::string& url, ErrorHandler errorHandler)
std::tuple<int, uint32_t> spawnProcess(int* pipeReadStdout, int* pipeWriteStdin, int* pipeReadStderr, const std::string& url, uint32_t width, uint32_t height, ErrorHandler errorHandler)
{
int fdsToChildStdin[2];
int fdsFromChildStdout[2];
Expand Down Expand Up @@ -70,7 +70,7 @@ std::tuple<int, uint32_t> spawnProcess(int* pipeReadStdout, int* pipeWriteStdin,
exit(1);
}
} else {
errorHandler(std::string("vfxpipe unable to determine library path"));
errorHandler("vfxpipe unable to determine library path");
exit(1);
}
}
Expand All @@ -86,8 +86,19 @@ std::tuple<int, uint32_t> spawnProcess(int* pipeReadStdout, int* pipeWriteStdin,
close(fdsFromChildStderr[1]);
}

VideoFrameFormat format(VideoFrameFormat::RGBA32, width, height);
uint32_t sinkCount = 0;
if (!dataIO(*pipeReadStdout, reinterpret_cast<std::byte*>(&sinkCount), sizeof(sinkCount), read, errorHandler)) {
if (!(writeVideoFrameFormat(*pipeWriteStdin, format, errorHandler)
&& dataIO(*pipeReadStdout, reinterpret_cast<std::byte*>(&sinkCount), sizeof(sinkCount), read, errorHandler))) {
errorHandler("vfxpipe failed to read sink count");
close(*pipeReadStdout);
*pipeReadStdout = -1;
close(*pipeWriteStdin);
*pipeWriteStdin = -1;
if (pipeReadStderr) {
close(*pipeReadStderr);
*pipeReadStderr = -1;
}
return { -1, 0 };
}

Expand All @@ -110,10 +121,10 @@ FrameServer::~FrameServer()
close(pipeWriteStdin);
}

bool FrameServer::initialize(ErrorHandler errorHandler, int* pipeReadStderr)
bool FrameServer::initialize(ErrorHandler errorHandler, uint32_t width, uint32_t height, int* pipeReadStderr)
{
if (!pid) {
std::tie(pid, sinkCount) = spawnProcess(&pipeReadStdout, &pipeWriteStdin, pipeReadStderr, url, errorHandler);
std::tie(pid, sinkCount) = spawnProcess(&pipeReadStdout, &pipeWriteStdin, pipeReadStderr, url, width, height, errorHandler);
if (pid == -1) {
errorHandler("vfxpipe failed to spawn process");
return false;
Expand All @@ -128,7 +139,7 @@ bool FrameServer::renderFrame(double time, const std::vector<SourceVideoFrame>&
if (pid == -1)
return false;
if (!pid) {
if (!initialize(errorHandler))
if (!initialize(errorHandler, outputFrame.format.width, outputFrame.format.height))
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion vfxpipe/vfxpipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class FrameServer {
public:
FrameServer(const std::string& url);
~FrameServer();
bool initialize(ErrorHandler errorHandler, int* pipeReadStderr = nullptr);
bool initialize(ErrorHandler errorHandler, uint32_t width, uint32_t height, int* pipeReadStderr = nullptr);
bool renderFrame(double time, const std::vector<SourceVideoFrame>& sourceFrames, RenderedVideoFrame& outputFrame, ErrorHandler errorHandler);
std::string& getUrl() { return url; }
uint32_t getSinkCount() { return sinkCount; }
Expand Down
2 changes: 1 addition & 1 deletion viewer/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ void Viewer::createContent(const QString& fileName)

delete errorNotifier;
int pipeReadStderr = 0;
if (frameServer->initialize(errorHandler, &pipeReadStderr)) {
if (frameServer->initialize(errorHandler, size.width(), size.height(), &pipeReadStderr)) {
errorNotifier = new QSocketNotifier(pipeReadStderr, QSocketNotifier::Read, this);
connect(errorNotifier, &QSocketNotifier::activated, this, &Viewer::onErrorReadyRead);
setContentUIEnabled(true);
Expand Down
8 changes: 0 additions & 8 deletions webvfx/content_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ QString ContentContext::getStringParameter(const QString& name)
return QString();
}

void ContentContext::setVideoSize(QSize size)
{
if (videoSize == size)
return;
videoSize = size;
emit videoSizeChanged(size);
}

qsizetype ContentContext::addVideoSource()
{
videoSinks.resize(videoSinks.size() + 1);
Expand Down
5 changes: 0 additions & 5 deletions webvfx/content_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ namespace WebVfx {
class ContentContext : public QObject {
Q_OBJECT

Q_PROPERTY(QSize videoSize READ getVideoSize WRITE setVideoSize NOTIFY videoSizeChanged)
// QML contents can set this if it requires async rendering.
// It should invoke emitAsyncRenderComplete when ready
Q_PROPERTY(bool asyncRenderRequired READ isAsyncRenderRequired WRITE setAsyncRenderRequired)
Expand Down Expand Up @@ -57,8 +56,6 @@ class ContentContext : public QObject {
// webvfx.emitAsyncRenderComplete()
Q_INVOKABLE void emitAsyncRenderComplete();

QSize getVideoSize() const { return videoSize; };
void setVideoSize(QSize size);
bool isAsyncRenderRequired() { return asyncRenderRequired; };
void setAsyncRenderRequired(bool asyncRender) { asyncRenderRequired = asyncRender; };
const QList<QList<QVideoSink*>>& getVideoSinks() { return videoSinks; }
Expand All @@ -68,14 +65,12 @@ class ContentContext : public QObject {
// time is normalized 0..1.0
// JS: webvfx.renderRequested.connect(function (time) { doSomething(); })
void renderRequested(double time);
void videoSizeChanged(QSize size);

void asyncRenderComplete();

private:
Parameters* parameters;
QList<QList<QVideoSink*>> videoSinks;
QSize videoSize;
bool asyncRenderRequired;
};

Expand Down
8 changes: 6 additions & 2 deletions webvfx/frameserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ FrameServer::FrameServer(QUrl& qmlUrl, QObject* parent)
urlQuery.removeQueryItem("webvfx_duration");

content = new WebVfx::QmlContent(new FrameServerParameters(urlQuery));
if (!VfxPipe::readVideoFrameFormat(STDIN_FILENO, outputFrame.format, ioErrorHandler)) {
return;
}
content->resize(outputFrame.format.width, outputFrame.format.height);

qmlUrl.setQuery(QString());

connect(content, &WebVfx::QmlContent::contentLoadFinished, this, &FrameServer::onContentLoadFinished);
Expand All @@ -119,7 +124,6 @@ FrameServer::~FrameServer()
void FrameServer::onContentLoadFinished(bool result)
{
if (result) {
auto size = content->getContentSize();
auto videoSinks = content->getVideoSinks();
for (const auto videoSink : videoSinks) {
frameSinks.append(FrameSink(videoSink));
Expand Down Expand Up @@ -161,7 +165,7 @@ void FrameServer::readFrames()

if (!VfxPipe::readVideoFrameFormat(STDIN_FILENO, outputFrame.format, ioErrorHandler))
return;
content->setContentSize(QSize(outputFrame.format.width, outputFrame.format.height));
content->resize(outputFrame.format.width, outputFrame.format.height);

uint32_t frameCount;
if (!VfxPipe::dataIO(STDIN_FILENO, reinterpret_cast<std::byte*>(&frameCount), sizeof(frameCount), read, ioErrorHandler))
Expand Down
11 changes: 2 additions & 9 deletions webvfx/qml_content.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ QmlContent::QmlContent(RenderControl* renderControl, Parameters* parameters)
, renderControl(renderControl)
, renderExpected(false)
{
setResizeMode(ResizeMode::SizeViewToRootObject);
setResizeMode(ResizeMode::SizeRootObjectToView);

// Expose context to the QML
rootContext()->setContextProperty("webvfx", contentContext);
Expand Down Expand Up @@ -60,13 +60,6 @@ void QmlContent::loadContent(const QUrl& url)
setSource(url);
}

void QmlContent::setContentSize(const QSize& size)
{
if (contentContext->getVideoSize() != size) {
contentContext->setVideoSize(size);
}
}

void QmlContent::contextAsyncRenderComplete()
{
if (!renderExpected) {
Expand All @@ -83,7 +76,7 @@ void QmlContent::contextAsyncRenderComplete()

void QmlContent::renderContent(double time)
{
if (!renderControl->install(this, contentContext->getVideoSize())) {
if (!renderControl->install(this, size())) {
emit renderComplete(QImage());
}

Expand Down
2 changes: 0 additions & 2 deletions webvfx/qml_content.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ class QmlContent : public QQuickView {
~QmlContent() override;

void loadContent(const QUrl& url);
void setContentSize(const QSize& size);
QSize getContentSize() { return contentContext->getVideoSize(); }
const QList<QList<QVideoSink*>>& getVideoSinks() { return contentContext->getVideoSinks(); }
void renderContent(double time);

Expand Down

0 comments on commit e5498be

Please sign in to comment.