template <typename T> class SampleFormatConverter;
template <typename T> class Interleaver;
template <typename T> class SndfileWriter;
+ template <typename T> class CmdPipeWriter;
template <typename T> class SilenceTrimmer;
template <typename T> class TmpFile;
template <typename T> class Threader;
typedef boost::shared_ptr<AudioGrapher::SndfileWriter<int> > IntWriterPtr;
typedef boost::shared_ptr<AudioGrapher::SndfileWriter<short> > ShortWriterPtr;
+ typedef boost::shared_ptr<AudioGrapher::CmdPipeWriter<Sample> > FloatPipePtr;
+
template<typename T> void init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer);
+ template<typename T> void init_writer (boost::shared_ptr<AudioGrapher::CmdPipeWriter<T> > & writer);
+
void copy_files (std::string orig_path);
FileSpec config;
FloatWriterPtr float_writer;
IntWriterPtr int_writer;
ShortWriterPtr short_writer;
+ FloatPipePtr pipe_writer;
};
// sample format converter
REGISTER_CLASS_ENUM (ExportFormatBase, T_None);
REGISTER_CLASS_ENUM (ExportFormatBase, T_Sndfile);
+ REGISTER_CLASS_ENUM (ExportFormatBase, T_FFMPEG);
REGISTER (_ExportFormatBase_Type);
REGISTER_CLASS_ENUM (ExportFormatBase, F_None);
REGISTER_CLASS_ENUM (ExportFormatBase, F_FLAC);
REGISTER_CLASS_ENUM (ExportFormatBase, F_Ogg);
REGISTER_CLASS_ENUM (ExportFormatBase, F_CAF);
+ REGISTER_CLASS_ENUM (ExportFormatBase, F_FFMPEG);
REGISTER (_ExportFormatBase_FormatId);
REGISTER_CLASS_ENUM (ExportFormatBase, E_FileDefault);
return compatible;
}
+
+/*** FFMPEG Pipe ***/
+
+ExportFormatFFMPEG::ExportFormatFFMPEG (std::string const& name, std::string const& ext)
+{
+ set_name (name);
+ set_format_id (F_FFMPEG);
+ sample_formats.insert (SF_Float);
+
+ add_sample_rate (SR_22_05);
+ add_sample_rate (SR_44_1);
+ add_sample_rate (SR_48);
+ add_sample_rate (SR_88_2);
+ add_sample_rate (SR_96);
+ add_sample_rate (SR_176_4);
+ add_sample_rate (SR_192);
+ add_sample_rate (SR_Session);
+
+ add_endianness (E_Little);
+
+ set_extension (ext);
+ set_quality (Q_LossyCompression);
+}
+
+bool
+ExportFormatFFMPEG::set_compatibility_state (ExportFormatCompatibility const & compatibility)
+{
+ bool compatible = compatibility.has_format (F_FFMPEG);
+ set_compatible (compatible);
+ return compatible;
+}
+
+
}; // namespace ARDOUR
#include "audiographer/process_context.h"
#include "audiographer/general/chunker.h"
+#include "audiographer/general/cmdpipe_writer.h"
#include "audiographer/general/interleaver.h"
#include "audiographer/general/normalizer.h"
#include "audiographer/general/analyser.h"
#include "ardour/audioengine.h"
#include "ardour/export_channel_configuration.h"
+#include "ardour/export_failed.h"
#include "ardour/export_filename.h"
#include "ardour/export_format_specification.h"
#include "ardour/export_timespan.h"
+#include "ardour/filesystem_paths.h"
#include "ardour/session_directory.h"
#include "ardour/sndfile_helpers.h"
+#include "ardour/system_exec.h"
#include "pbd/file_utils.h"
#include "pbd/cpus.h"
ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
{
config = new_config;
- init_writer (float_writer);
- return float_writer;
+ if (config.format->format_id() == ExportFormatBase::F_FFMPEG) {
+ init_writer (pipe_writer);
+ return pipe_writer;
+ } else {
+ init_writer (float_writer);
+ return float_writer;
+ }
}
template <>
short_writer->close ();
}
+ if (pipe_writer) {
+ pipe_writer->close ();
+ }
+
if (std::remove(writer_filename.c_str() ) != 0) {
std::cout << "Encoder::destroy_writer () : Error removing file: " << strerror(errno) << std::endl;
}
float_writer.reset ();
int_writer.reset ();
short_writer.reset ();
+ pipe_writer.reset ();
}
bool
writer->FileWritten.connect_same_thread (copy_files_connection, boost::bind (&ExportGraphBuilder::Encoder::copy_files, this, _1));
}
+template<typename T>
+void
+ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::CmdPipeWriter<T> > & writer)
+{
+ unsigned channels = config.channel_config->get_n_chans();
+ config.filename->set_channel_config(config.channel_config);
+ writer_filename = config.filename->get_path (config.format);
+
+ std::string ffmpeg_exe;
+ std::string unused;
+
+ if (!ArdourVideoToolPaths::transcoder_exe (ffmpeg_exe, unused)) {
+ throw ExportFailed ("External encoder (ffmpeg) is not available.");
+ }
+
+ int quality = 3; // TODO get from config.format
+
+ int a=0;
+ char **argp = (char**) calloc (100, sizeof(char*));
+ char tmp[64];
+ argp[a++] = strdup(ffmpeg_exe.c_str());
+ argp[a++] = strdup ("-f");
+ argp[a++] = strdup ("f32le");
+ argp[a++] = strdup ("-acodec");
+ argp[a++] = strdup ("pcm_f32le");
+ argp[a++] = strdup ("-ac");
+ snprintf (tmp, sizeof(tmp), "%d", channels);
+ argp[a++] = strdup (tmp);
+ argp[a++] = strdup ("-ar");
+ snprintf (tmp, sizeof(tmp), "%d", config.format->sample_rate());
+ argp[a++] = strdup (tmp);
+ argp[a++] = strdup ("-i");
+ argp[a++] = strdup ("pipe:0");
+
+ argp[a++] = strdup ("-y");
+ if (quality < 10) {
+ /* variable rate, lower is better */
+ snprintf (tmp, sizeof(tmp), "%d", quality);
+ argp[a++] = strdup ("-q:a"); argp[a++] = strdup (tmp);
+ } else {
+ /* fixed bitrate, higher is better */
+ snprintf (tmp, sizeof(tmp), "%dk", quality); // eg. "192k"
+ argp[a++] = strdup ("-b:a"); argp[a++] = strdup (tmp);
+ }
+
+ /* TODO: add SessionMetadata::Metadata()
+ * see gtk2_ardour/export_video_dialog.cc
+ * and gtk2_ardour/transcode_ffmpeg.cc
+ */
+
+ argp[a++] = strdup (writer_filename.c_str());
+ 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);
+ if (exec->start(0)) {
+ 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));
+}
+
void
ExportGraphBuilder::Encoder::copy_files (std::string orig_path)
{