Use pipe through ffmpeg, use glib to write output

This is intended to fix an issue with odd filenames on Windows,
particularly forward and backwards single quotes as part of a filename.

Previously the filename was passed as parameter to ffmpeg as
UTF-8 string to SystemExec::make_wargs, which is fragile on Windows
in absence of a execve() call.
This commit is contained in:
Robin Gareus 2023-01-04 17:26:43 +01:00
parent 16a476ee5f
commit bb4394b8a5
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 42 additions and 8 deletions

View File

@ -398,7 +398,11 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::CmdPip
argp[a++] = strdup ("-i");
argp[a++] = strdup ("pipe:0");
argp[a++] = strdup ("-y");
argp[a++] = strdup ("-f");
argp[a++] = strdup ("mp3");
argp[a++] = strdup ("-acodec");
argp[a++] = strdup ("mp3");
if (quality <= 0) {
/* variable rate, lower is better */
snprintf (tmp, sizeof(tmp), "%d", -quality);
@ -422,16 +426,14 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::CmdPip
argp[a++] = SystemExec::format_key_value_parameter (it->first.c_str(), it->second.c_str());
}
argp[a++] = strdup (writer_filename.c_str());
argp[a++] = strdup ("pipe:1");
argp[a] = (char *)0;
/* argp is free()d in ~SystemExec,
* SystemExec is deleted when writer is destroyed */
ARDOUR::SystemExec* exec = new ARDOUR::SystemExec (ffmpeg_exe, argp, true);
PBD::info << "Encode command: { " << exec->to_s () << "}" << endmsg;
if (exec->start (SystemExec::MergeWithStdin)) {
throw ExportFailed ("External encoder (ffmpeg) cannot be started.");
}
writer.reset (new AudioGrapher::CmdPipeWriter<T> (exec, writer_filename));
writer->FileWritten.connect_same_thread (copy_files_connection, boost::bind (&ExportGraphBuilder::Encoder::copy_files, this, _1));
}

View File

@ -3,14 +3,18 @@
#include <string>
#include <glib.h>
#include <boost/format.hpp>
#include "audiographer/flag_debuggable.h"
#include "audiographer/sink.h"
#include "audiographer/types.h"
#include "pbd/gstdio_compat.h"
#include "pbd/signals.h"
#include "pbd/system_exec.h"
#include "ardour/system_exec.h"
#include "ardour/export_failed.h"
namespace AudioGrapher
{
@ -25,16 +29,31 @@ class CmdPipeWriter
, public FlagDebuggable<>
{
public:
CmdPipeWriter (PBD::SystemExec* proc, std::string const& path)
CmdPipeWriter (ARDOUR::SystemExec* proc, std::string const& path)
: samples_written (0)
, _proc (proc)
, _path (path)
{
add_supported_flag (ProcessContext<T>::EndOfInput);
proc->ReadStdout.connect_same_thread (exec_connections, boost::bind (&CmdPipeWriter::write_ffile, this, _1, _2));
proc->Terminated.connect_same_thread (exec_connections, boost::bind (&CmdPipeWriter::close_ffile, this));
encoder_file = g_fopen (path.c_str(), "wb");
if (!encoder_file) {
throw ARDOUR::ExportFailed ("Output file cannot be written to.");
}
if (proc->start (ARDOUR::SystemExec::IgnoreAndClose)) {
fclose (encoder_file);
throw ARDOUR::ExportFailed ("External encoder (ffmpeg) cannot be started.");
}
}
virtual ~CmdPipeWriter () {
delete _proc;
assert (!encoder_file);
}
samplecnt_t get_samples_written() const { return samples_written; }
@ -65,7 +84,6 @@ public:
if (c.has_flag(ProcessContext<T>::EndOfInput)) {
_proc->close_stdin ();
FileWritten (_path);
}
}
@ -79,6 +97,20 @@ private:
samplecnt_t samples_written;
PBD::SystemExec* _proc;
std::string _path;
FILE* encoder_file;
void write_ffile (std::string d, size_t s) {
fwrite (d.c_str(), sizeof(char), s, encoder_file);
}
void close_ffile () {
fclose (encoder_file);
encoder_file = 0;
FileWritten (_path);
}
PBD::ScopedConnectionList exec_connections;
};
} // namespace