Skip to content

Commit

Permalink
communicate sink count from frameserver
Browse files Browse the repository at this point in the history
  • Loading branch information
rectalogic committed Oct 7, 2023
1 parent 1f682ad commit 1ec7e10
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 32 deletions.
42 changes: 33 additions & 9 deletions vfxpipe/vfxpipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@
// found in the LICENSE file.

#include "vfxpipe.h"
#include <algorithm>
#include <dlfcn.h> // for dladdr, Dl_info
#include <filesystem> // for path
#include <functional> // for function
#include <limits.h> // for PATH_MAX
#include <signal.h> // for signal, SIGCHLD, SIG_IGN
#include <stdlib.h> // for exit, realpath
#include <string> // for allocator, operator+, char_traits, string
#include <tuple>
#include <unistd.h> // for close, dup2, pipe, write, execv, fork, read, STDIN_FILENO, STDOUT_FILENO

namespace VfxPipe {

int spawnProcess(int* pipeRead, int* pipeWrite, const std::string& url, ErrorHandler errorHandler)
std::tuple<int, uint32_t> spawnProcess(int* pipeRead, int* pipeWrite, const std::string& url, ErrorHandler errorHandler)
{
int fdsToChild[2];
int fdsFromChild[2];

if (pipe(fdsToChild) == -1 || pipe(fdsFromChild) == -1) {
errorHandler(std::string("vfxpipe pipe failed: ") + strerror(errno));
return -1;
return { -1, 0 };
}

// Ignore child exit so we don't have to waitpid, and to avoid zombie processes
Expand All @@ -30,7 +32,7 @@ int spawnProcess(int* pipeRead, int* pipeWrite, const std::string& url, ErrorHan
int pid = fork();
if (pid == -1) {
errorHandler(std::string("vfxpipe fork failed: ") + strerror(errno));
return -1;
return { -1, 0 };
}
// In the child
if (pid == 0) {
Expand Down Expand Up @@ -74,7 +76,13 @@ int spawnProcess(int* pipeRead, int* pipeWrite, const std::string& url, ErrorHan

close(fdsFromChild[1]);
close(fdsToChild[0]);
return pid;

uint32_t sinkCount = 0;
if (!dataIO(*pipeRead, reinterpret_cast<std::byte*>(&sinkCount), sizeof(sinkCount), read, errorHandler)) {
return { -1, 0 };
}

return { pid, sinkCount };
}

FrameServer::FrameServer(const std::string& url)
Expand All @@ -93,14 +101,26 @@ FrameServer::~FrameServer()
close(pipeWrite);
}

bool FrameServer::renderFrame(double time, const std::vector<SourceVideoFrame>& sourceFrames, RenderedVideoFrame& outputFrame, ErrorHandler errorHandler)
bool FrameServer::initialize(ErrorHandler errorHandler)
{
if (!pid) {
pid = spawnProcess(&pipeRead, &pipeWrite, url, errorHandler);
std::tie(pid, sinkCount) = spawnProcess(&pipeRead, &pipeWrite, url, errorHandler);
if (pid == -1) {
errorHandler("vfxpipe failed to spawn process");
return false;
}
return true;
}
if (pid == -1) {
errorHandler("vfxpipe failed to spawn process");
return pid != -1;
}

bool FrameServer::renderFrame(double time, const std::vector<SourceVideoFrame>& sourceFrames, RenderedVideoFrame& outputFrame, ErrorHandler errorHandler)
{
if (pid == -1)
return false;
if (!pid) {
if (!initialize(errorHandler))
return false;
}

auto ioErrorHandler = [this, errorHandler](std::string msg) {
Expand All @@ -121,11 +141,15 @@ bool FrameServer::renderFrame(double time, const std::vector<SourceVideoFrame>&
return false;
}

uint32_t frameCount = sourceFrames.size();
uint32_t frameCount = std::min(sinkCount, static_cast<uint32_t>(sourceFrames.size()));
if (!dataIO(pipeWrite, reinterpret_cast<const std::byte*>(&frameCount), sizeof(frameCount), write, ioErrorHandler)) {
return false;
}
int index = 0;
for (const auto& sourceFrame : sourceFrames) {
++index;
if (index > frameCount)
break;
if (!writeVideoFrame(pipeWrite, sourceFrame, ioErrorHandler)) {
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions vfxpipe/vfxpipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,17 @@ class FrameServer {
public:
FrameServer(const std::string& url);
~FrameServer();
bool initialize(ErrorHandler errorHandler);
bool renderFrame(double time, const std::vector<SourceVideoFrame>& sourceFrames, RenderedVideoFrame& outputFrame, ErrorHandler errorHandler);
std::string& getUrl() { return url; }
uint32_t getSinkCount() { return sinkCount; }

private:
std::string url;
int pid;
int pipeWrite;
int pipeRead;
uint32_t sinkCount;
};

template <typename D, typename IO>
Expand Down
17 changes: 9 additions & 8 deletions viewer/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <string> // for string
#include <vector> // for vector

void errorHandler(std::string msg)
{
qCritical() << msg;
};

Viewer::Viewer()
: QMainWindow(0)
, sizeLabel(0)
Expand Down Expand Up @@ -111,10 +116,6 @@ void Viewer::renderContent()
}
}

auto errorHandler = [](std::string msg) {
qCritical() << msg;
};

if (renderImage.size() != scrollArea->widget()->size())
renderImage = QImage(scrollArea->widget()->size(), QImage::Format_RGBA8888);
VfxPipe::VideoFrame outputImage(VfxPipe::VideoFrameFormat::PixelFormat::RGBA32, renderImage.width(), renderImage.height(), reinterpret_cast<std::byte*>(renderImage.bits()));
Expand Down Expand Up @@ -221,15 +222,15 @@ void Viewer::createContent(const QString& fileName)

logTextEdit->clear();

setContentUIEnabled(true); // XXX need UI enabled all the time now?
if (frameServer->initialize(errorHandler))
setContentUIEnabled(true);

setupImages(scrollArea->widget()->size());
setupImages(frameServer->getSinkCount(), scrollArea->widget()->size());
renderContent();
}

void Viewer::setupImages(const QSize& size)
void Viewer::setupImages(uint32_t imageCount, const QSize& size)
{
int imageCount = 0; // XXX need a count, make frameserver return count
imagesTable->setRowCount(imageCount);
for (qsizetype row = 0; row < imageCount; ++row) {
imagesTable->insertRow(row);
Expand Down
2 changes: 1 addition & 1 deletion viewer/viewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private slots:
void renderContent();
void setContentUIEnabled(bool enable);
void handleResize();
void setupImages(const QSize& size);
void setupImages(uint32_t imageCount, const QSize& size);
double sliderTimeValue(int value);
QLabel* sizeLabel;
QDoubleSpinBox* timeSpinBox;
Expand Down
33 changes: 19 additions & 14 deletions webvfx/frameserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ double parseDuration(QString durationValue)

QEvent::Type FrameServer::renderEventType = static_cast<QEvent::Type>(QEvent::registerEventType());

void ioErrorHandler(std::string msg)
{
// EOF
if (msg.empty()) {
QCoreApplication::exit(0);
} else {
qCritical() << "WebVfx frameserver: " << msg.c_str();
QCoreApplication::exit(1);
}
};

FrameServer::FrameServer(QUrl& qmlUrl, QObject* parent)
: QObject(parent)
, duration(0)
Expand Down Expand Up @@ -110,9 +121,13 @@ void FrameServer::onContentLoadFinished(bool result)
if (result) {
auto size = content->getContentSize();
auto videoSinks = content->getVideoSinks();
for (qsizetype i = 0; i < videoSinks.size(); ++i) {
frameSinks.append(FrameSink(videoSinks.at(i)));
for (const auto videoSink : videoSinks) {
frameSinks.append(FrameSink(videoSink));
}
// Write sink count
uint32_t sinkCount = videoSinks.size();
if (!VfxPipe::dataIO(STDOUT_FILENO, reinterpret_cast<std::byte*>(&sinkCount), sizeof(sinkCount), write, ioErrorHandler))
return;
QCoreApplication::postEvent(this, new QEvent(renderEventType));
} else {
qCritical() << "QML content failed to load.";
Expand All @@ -132,19 +147,8 @@ bool FrameServer::event(QEvent* event)

void FrameServer::readFrames()
{
auto f = __FUNCTION__;
auto ioErrorHandler = [f](std::string msg) {
// EOF
if (msg.empty()) {
QCoreApplication::exit(0);
} else {
qCritical() << f << ": WebVfx frameserver: " << msg.c_str();
QCoreApplication::exit(1);
}
};

double time;
if (!VfxPipe::dataIO(STDIN_FILENO, reinterpret_cast<uchar*>(&time), sizeof(time), read, ioErrorHandler))
if (!VfxPipe::dataIO(STDIN_FILENO, reinterpret_cast<std::byte*>(&time), sizeof(time), read, ioErrorHandler))
return;

if (initialTime == -1) {
Expand All @@ -162,6 +166,7 @@ void FrameServer::readFrames()
uint32_t frameCount;
if (!VfxPipe::dataIO(STDIN_FILENO, reinterpret_cast<std::byte*>(&frameCount), sizeof(frameCount), read, ioErrorHandler))
return;

if (frameCount > frameSinks.size()) {
qCritical() << "Frame count " << frameCount << " does not match video sink count " << frameSinks.size();
QCoreApplication::exit(1);
Expand Down

0 comments on commit 1ec7e10

Please sign in to comment.