Add pop-up to download ffmpeg if not already downloaded

pull/261/head
James H Ball 2024-11-29 22:28:38 +01:00 zatwierdzone przez James H Ball
rodzic 157676439e
commit 7b98b34b04
8 zmienionych plików z 150 dodań i 10 usunięć

Wyświetl plik

@ -45,6 +45,9 @@ private:
OscirenderAudioProcessor& audioProcessor;
juce::File applicationFolder = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userApplicationDataDirectory)
#if JUCE_MAC
.getChildFile("Application Support")
#endif
.getChildFile("osci-render");
public:

Wyświetl plik

@ -28,6 +28,9 @@ private:
SosciAudioProcessor& audioProcessor;
juce::File applicationFolder = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userApplicationDataDirectory)
#if JUCE_MAC
.getChildFile("Application Support")
#endif
.getChildFile("osci-render");
public:
OscirenderLookAndFeel lookAndFeel;

Wyświetl plik

@ -0,0 +1,50 @@
#include "DownloaderComponent.h"
DownloaderComponent::DownloaderComponent(juce::URL url, juce::File file, juce::String title, juce::Component* parent) : juce::ThreadWithProgressWindow(title, true, true, 1000, juce::String(), parent), url(url), file(file) {
if (url.toString(false).endsWithIgnoreCase(".gz")) {
uncompressOnFinish = true;
this->file = file.getSiblingFile(file.getFileName() + ".gz");
}
}
void DownloaderComponent::run() {
downloader = std::make_unique<DownloaderThread>(url, file, this, taskLock, task);
downloader->startThread();
while (!threadShouldExit()) {
{
juce::CriticalSection::ScopedTryLockType lock(taskLock);
if (lock.isLocked() && task != nullptr) {
if (task->isFinished()) {
return;
}
}
}
wait(100);
}
}
void DownloaderComponent::threadComplete(bool userPressedCancel) {
if (!userPressedCancel && uncompressOnFinish && task->isFinished() && !task->hadError()) {
juce::FileInputStream input(file);
juce::GZIPDecompressorInputStream decompressedInput(&input, false, juce::GZIPDecompressorInputStream::gzipFormat);
juce::File uncompressedFile = file.getSiblingFile(file.getFileNameWithoutExtension());
juce::FileOutputStream output(uncompressedFile);
if (output.writeFromInputStream(decompressedInput, -1) < 1) {
uncompressedFile.deleteFile();
} else {
uncompressedFile.setExecutePermission(true);
}
}
}
void DownloaderComponent::finished(juce::URL::DownloadTask* task, bool success) {
notify();
}
void DownloaderComponent::progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) {
setProgress((float)bytesDownloaded / (float)totalLength);
}
void DownloaderComponent::download() {
launchThread();
}

Wyświetl plik

@ -0,0 +1,43 @@
#pragma once
#include <JuceHeader.h>
class DownloaderThread : public juce::Thread {
public:
DownloaderThread(juce::URL url, juce::File file, juce::URL::DownloadTaskListener* listener, juce::CriticalSection& taskLock, std::unique_ptr<juce::URL::DownloadTask>& task) : juce::Thread("Downloader Thread"), url(url), file(file), listener(listener), taskLock(taskLock), task(task) {};
void run() override {
juce::CriticalSection::ScopedLockType lock(taskLock);
task = url.downloadToFile(file, juce::URL::DownloadTaskOptions().withListener(listener));
};
private:
juce::URL url;
juce::File file;
juce::CriticalSection& taskLock;
juce::URL::DownloadTaskListener* listener;
std::unique_ptr<juce::URL::DownloadTask>& task;
};
class DownloaderComponent : public juce::ThreadWithProgressWindow, public juce::URL::DownloadTaskListener {
public:
DownloaderComponent(juce::URL url, juce::File file, juce::String title, juce::Component* parent);
void download();
void run() override;
void threadComplete(bool userPressedCancel) override;
void finished(juce::URL::DownloadTask* task, bool success) override;
void progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) override;
private:
juce::URL url;
juce::File file;
juce::CriticalSection taskLock;
std::unique_ptr<juce::URL::DownloadTask> task;
std::unique_ptr<DownloaderThread> downloader;
bool uncompressOnFinish = false;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DownloaderComponent)
};

Wyświetl plik

@ -11,7 +11,7 @@
#include "TexturedFragmentShader.glsl"
#include "TexturedVertexShader.glsl"
VisualiserComponent::VisualiserComponent(juce::File ffmpegPath, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent, bool visualiserOnly) : ffmpegPath(ffmpegPath), haltRecording(haltRecording), settings(settings), threadManager(threadManager), visualiserOnly(visualiserOnly), AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), threadManager), parent(parent) {
VisualiserComponent::VisualiserComponent(juce::File ffmpegFile, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent, bool visualiserOnly) : ffmpegFile(ffmpegFile), haltRecording(haltRecording), settings(settings), threadManager(threadManager), visualiserOnly(visualiserOnly), AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), threadManager), parent(parent) {
haltRecording = [this] {
setRecording(false);
@ -170,20 +170,25 @@ void VisualiserComponent::setFullScreen(bool fullScreen) {}
void VisualiserComponent::setRecording(bool recording) {
if (recording) {
if (!ffmpegFile.exists()) {
ffmpegDownloader.download();
record.setToggleState(false, juce::NotificationType::sendNotification);
return;
}
juce::TemporaryFile tempFile = juce::TemporaryFile(".mp4");
juce::String resolution = std::to_string(renderTexture.width) + "x" + std::to_string(renderTexture.height);
juce::String cmd = ffmpegPath.getFullPathName() +
" -r " + juce::String(FRAME_RATE) + " -f rawvideo -pix_fmt rgba -s " + resolution + " -i - -threads 0 -preset fast -y -pix_fmt yuv420p -crf " + juce::String(21) + " -vf vflip " + tempFile.getFile().getFullPathName();
juce::String cmd = "\"" + ffmpegFile.getFullPathName() +
"\" -r " + juce::String(FRAME_RATE) + " -f rawvideo -pix_fmt rgba -s " + resolution + " -i - -threads 0 -preset fast -y -pix_fmt yuv420p -crf " + juce::String(21) + " -vf vflip \"" + tempFile.getFile().getFullPathName() + "\"";
// open pipe to ffmpeg's stdin in binary write mode
#if JUCE_WINDOWS
ffmpeg = _popen(cmd.toStdString().c_str(), "wb");
#else
ffmpeg = popen(cmd.toStdString().c_str(), "w");
#endif
if (ffmpeg == nullptr) {
DBG("popen failed: " + juce::String(std::strerror(errno)));
}
#endif
framePixels.resize(renderTexture.width * renderTexture.height * 4);
setPaused(false);
} else if (ffmpeg != nullptr) {
@ -223,7 +228,7 @@ void VisualiserComponent::resized() {
void VisualiserComponent::popoutWindow() {
setRecording(false);
record.setEnabled(false);
auto visualiser = new VisualiserComponent(ffmpegPath, haltRecording, threadManager, settings, this);
auto visualiser = new VisualiserComponent(ffmpegFile, haltRecording, threadManager, settings, this);
visualiser->settings.setLookAndFeel(&getLookAndFeel());
visualiser->openSettings = openSettings;
visualiser->closeSettings = closeSettings;

Wyświetl plik

@ -8,6 +8,7 @@
#include "VisualiserSettings.h"
#include "../components/StopwatchComponent.h"
#include "../img/qoixx.hpp"
#include "../components/DownloaderComponent.h"
#define FILE_RENDER_DUMMY 0
#define FILE_RENDER_PNG 1
@ -28,7 +29,7 @@ struct Texture {
class VisualiserWindow;
class VisualiserComponent : public juce::Component, public AudioBackgroundThread, public juce::MouseListener, public juce::OpenGLRenderer, public juce::AsyncUpdater {
public:
VisualiserComponent(juce::File ffmpegPath, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent = nullptr, bool visualiserOnly = false);
VisualiserComponent(juce::File ffmpegFile, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent = nullptr, bool visualiserOnly = false);
~VisualiserComponent() override;
std::function<void()> openSettings;
@ -81,7 +82,37 @@ private:
long numFrames = 0;
std::vector<unsigned char> framePixels;
FILE* ffmpeg = nullptr;
juce::File ffmpegPath;
juce::File ffmpegFile;
juce::String ffmpegURL = juce::String("https://github.com/eugeneware/ffmpeg-static/releases/download/b6.0/") +
#if JUCE_WINDOWS
#if JUCE_64BIT
"ffmpeg-win32-x64"
#elif JUCE_32BIT
"ffmpeg-win32-ia32"
#endif
#elif JUCE_MAC
#if JUCE_ARM
"ffmpeg-darwin-arm64"
#elif JUCE_INTEL
"ffmpeg-darwin-x64"
#endif
#elif JUCE_LINUX
#if JUCE_ARM
#if JUCE_64BIT
"ffmpeg-linux-arm64"
#elif JUCE_32BIT
"ffmpeg-linux-arm"
#endif
#elif JUCE_INTEL
#if JUCE_64BIT
"ffmpeg-linux-x64"
#elif JUCE_32BIT
"ffmpeg-linux-ia32"
#endif
#endif
#endif
+ ".gz";
DownloaderComponent ffmpegDownloader{ffmpegURL, ffmpegFile, "Downloading ffmpeg...", this};
Semaphore renderingSemaphore{0};

Wyświetl plik

@ -5,7 +5,8 @@
pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender"
cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include"
version="2.3.0" companyName="James H Ball" companyWebsite="https://osci-render.com"
companyEmail="james@ball.sh" defines="NOMINMAX=1" pluginAUMainType="'aumf'">
companyEmail="james@ball.sh" defines="NOMINMAX=1&#10;INTERNET_FLAG_NO_AUTO_REDIRECT=0"
pluginAUMainType="'aumf'">
<MAINGROUP id="j5Ge2T" name="osci-render">
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
<GROUP id="{8930EC48-30FD-646B-9DC5-0861171F8B2E}" name="fonts">

Wyświetl plik

@ -5,8 +5,8 @@
aaxIdentifier="sh.ball.sosci" cppLanguageStandard="20" projectLineFeed="&#10;"
headerPath="./include" version="1.0.0" companyName="James H Ball"
companyWebsite="https://osci-render.com" companyEmail="james@ball.sh"
defines="NOMINMAX=1" pluginManufacturerCode="Jhba" pluginCode="Sosc"
pluginAUMainType="'aufx'">
defines="NOMINMAX=1&#10;INTERNET_FLAG_NO_AUTO_REDIRECT=0" pluginManufacturerCode="Jhba"
pluginCode="Sosc" pluginAUMainType="'aufx'">
<MAINGROUP id="j5Ge2T" name="sosci">
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
<GROUP id="{1C0FC3AA-01F6-8768-381C-200ED18AB5F2}" name="fonts">
@ -67,6 +67,10 @@
file="Source/components/AboutComponent.cpp"/>
<FILE id="FtOv3F" name="AboutComponent.h" compile="0" resource="0"
file="Source/components/AboutComponent.h"/>
<FILE id="aihIvJ" name="DownloaderComponent.cpp" compile="1" resource="0"
file="Source/components/DownloaderComponent.cpp"/>
<FILE id="wBQEfb" name="DownloaderComponent.h" compile="0" resource="0"
file="Source/components/DownloaderComponent.h"/>
<FILE id="xLAEHK" name="EffectComponent.cpp" compile="1" resource="0"
file="Source/components/EffectComponent.cpp"/>
<FILE id="u4UCwb" name="EffectComponent.h" compile="0" resource="0"