From bb4394b8a521a544861ddccbf7f0208dc4c5943f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Wed, 4 Jan 2023 17:26:43 +0100 Subject: [PATCH] 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. --- libs/ardour/export_graph_builder.cc | 12 +++--- .../audiographer/general/cmdpipe_writer.h | 38 +++++++++++++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc index 578432857c..d000c6ac82 100644 --- a/libs/ardour/export_graph_builder.cc +++ b/libs/ardour/export_graph_builder.cc @@ -398,7 +398,11 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptrfirst.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 (exec, writer_filename)); writer->FileWritten.connect_same_thread (copy_files_connection, boost::bind (&ExportGraphBuilder::Encoder::copy_files, this, _1)); } diff --git a/libs/audiographer/audiographer/general/cmdpipe_writer.h b/libs/audiographer/audiographer/general/cmdpipe_writer.h index 74dc604b8b..d88eab2d60 100644 --- a/libs/audiographer/audiographer/general/cmdpipe_writer.h +++ b/libs/audiographer/audiographer/general/cmdpipe_writer.h @@ -3,14 +3,18 @@ #include +#include #include #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::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::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