Ardour  8.12
cmdpipe_writer.h
Go to the documentation of this file.
1 #ifndef AUDIOGRAPHER_CMDPIPE_WRITER_H
2 #define AUDIOGRAPHER_CMDPIPE_WRITER_H
3 
4 #include <string>
5 
6 #include <glib.h>
7 #include <boost/format.hpp>
8 
10 #include "audiographer/sink.h"
11 #include "audiographer/types.h"
12 
13 #include "pbd/gstdio_compat.h"
14 #include "pbd/signals.h"
15 
16 #include "ardour/system_exec.h"
17 #include "ardour/export_failed.h"
18 
19 namespace AudioGrapher
20 {
21 
25 template <typename T = DefaultSampleType>
27  : public Sink<T>
28  , public Throwing<>
29  , public FlagDebuggable<>
30 {
31 public:
32  CmdPipeWriter (ARDOUR::SystemExec* proc, std::string const& path, int tmp_fd = -1, gchar* tmp_file = 0)
33  : samples_written (0)
34  , _proc (proc)
35  , _path (path)
36  , _tmp_fd (tmp_fd)
37  , _tmp_file (tmp_file)
38  {
40 
41  if (tmp_fd >= 0) {
42  ;
43  } else if (proc->start (ARDOUR::SystemExec::ShareWithParent)) {
44  throw ARDOUR::ExportFailed ("External encoder (ffmpeg) cannot be started.");
45  }
46  proc->Terminated.connect_same_thread (exec_connections, boost::bind (&CmdPipeWriter::encode_complete, this));
47  }
48 
49  virtual ~CmdPipeWriter () {
50  delete _proc;
51  if (_tmp_fd >= 0) {
52  ::close (_tmp_fd);
53  }
54  if (_tmp_file) {
55  g_unlink (_tmp_file);
56  g_free (_tmp_file);
57  }
58  }
59 
62 
63  void close (void)
64  {
65  _proc->terminate ();
66  }
67 
68  virtual void process (ProcessContext<T> const & c)
69  {
70  check_flags (*this, c);
71 
72  if (_tmp_fd < 0 && (!_proc || !_proc->is_running())) {
73  throw Exception (*this, boost::str (boost::format
74  ("Target encoder process is not running")));
75  }
76 
77  const size_t bytes_per_sample = sizeof (T);
78  samplecnt_t written;
79  if (_tmp_fd >= 0) {
80  written = write (_tmp_fd, (const void*) c.data(), c.samples() * bytes_per_sample) / bytes_per_sample;
81  } else {
82  written = _proc->write_to_stdin ((const void*) c.data(), c.samples() * bytes_per_sample) / bytes_per_sample;
83  }
84 
85  samples_written += written;
86 
87  if (throw_level (ThrowProcess) && written != c.samples()) {
88  throw Exception (*this, boost::str (boost::format
89  ("Could not write data to output file")));
90  }
91 
93  if (_tmp_fd >= 0) {
94  ::close (_tmp_fd);
95  _tmp_fd = -1;
97  throw ARDOUR::ExportFailed ("External encoder (ffmpeg) cannot be started.");
98  }
99  } else {
100  _proc->close_stdin ();
101  }
102  _proc->wait ();
103  }
104  }
105 
106  using Sink<T>::process;
107 
108  PBD::Signal1<void, std::string> FileWritten;
109 
110 private:
111  CmdPipeWriter (CmdPipeWriter const & other) {}
112 
115  std::string _path;
116  int _tmp_fd;
117  gchar* _tmp_file;
118 
119  void encode_complete () {
120  if (_tmp_file) {
121  g_unlink (_tmp_file);
122  g_free (_tmp_file);
123  _tmp_file = NULL;
124  }
125  FileWritten (_path);
126  }
127 
129 };
130 
131 } // namespace
132 
133 #endif
134 
int start(StdErrMode stderr_mode=IgnoreAndClose)
samplecnt_t get_samples_written() const
CmdPipeWriter(CmdPipeWriter const &other)
virtual void process(ProcessContext< T > const &c)
CmdPipeWriter(ARDOUR::SystemExec *proc, std::string const &path, int tmp_fd=-1, gchar *tmp_file=0)
PBD::Signal1< void, std::string > FileWritten
PBD::ScopedConnectionList exec_connections
ARDOUR::SystemExec * _proc
A debugging class for nodes that support a certain set of flags.
void check_flags(SelfType &self, ProcessContext< ContextType > context)
Prints debug output if context contains flags that are not supported by this class.
void add_supported_flag(Flag flag)
Adds a flag to the set of flags supported.
bool has_flag(Flag flag) const
T const * data() const
data points to the array of data to process
samplecnt_t const & samples() const
samples tells how many samples the array pointed by data contains
bool throw_level(ThrowLevel level)
Definition: throwing.h:47
int wait(int options=0)
size_t write_to_stdin(std::string const &d, size_t len=0)
PBD::Signal0< void > Terminated
@ ThrowProcess
Process cycle level stuff.
Definition: throwing.h:23