ardour
export_video_dialog.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 Paul Davis
3  Author: Robin Gareus <robin@gareus.org>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 #include <cstdio>
21 #include <string>
22 #include <sstream>
23 #include <iomanip>
24 
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 
30 #include <sigc++/bind.h>
31 
32 #include <glib/gstdio.h>
33 
34 #include "pbd/error.h"
35 #include "pbd/convert.h"
36 #include "gtkmm2ext/keyboard.h"
37 #include "gtkmm2ext/utils.h"
39 #include "ardour/profile.h"
40 #include "ardour/template_utils.h"
41 #include "ardour/session.h"
42 #include "ardour_ui.h"
43 #include "gui_thread.h"
44 
45 #include "ardour/export_handler.h"
46 #include "ardour/export_status.h"
47 #include "ardour/export_timespan.h"
50 #include "ardour/export_filename.h"
51 #include "ardour/route.h"
53 #include "ardour/broadcast_info.h"
54 
55 #include "opts.h"
56 #include "export_video_dialog.h"
57 #include "utils_videotl.h"
58 #include "i18n.h"
59 
60 using namespace Gtk;
61 using namespace std;
62 using namespace PBD;
63 using namespace ARDOUR;
64 using namespace VideoUtils;
65 
67  : ArdourDialog (_("Export Video File "))
68  , _aborted(false)
69  , _twopass(false)
70  , _firstpass(false)
71  , _normalize(false)
72  , _previous_progress(0)
73  , _transcoder(0)
74  , _video_source_aspect_ratio(-1)
75  , _suspend_signals(false)
76  , outfn_path_label (_("File:"), Gtk::ALIGN_LEFT)
77  , outfn_browse_button (_("Browse"))
78  , invid_path_label (_("Video:"), Gtk::ALIGN_LEFT)
79  , invid_browse_button (_("Browse"))
80  , transcode_button (_("Export"))
81  , abort_button (_("Abort"))
82  , progress_box (0)
83  , scale_checkbox (_("Scale Video (W x H):"))
84  , scale_aspect (_("Retain Aspect"))
85  , width_adjustment (768, 128, 1920, 1, 16, 0)
86  , width_spinner (width_adjustment)
87  , height_adjustment (576, 128, 1920, 1, 16, 0)
88  , height_spinner (height_adjustment)
89  , aspect_checkbox (_("Set Aspect Ratio:"))
90  , normalize_checkbox (_("Normalize Audio"))
91  , twopass_checkbox (_("2 Pass Encoding"))
92  , optimizations_checkbox (_("Codec Optimizations:"))
93  , optimizations_label ("-")
94  , deinterlace_checkbox (_("Deinterlace"))
95  , bframes_checkbox (_("Use [2] B-frames (MPEG 2 or 4 only)"))
96  , fps_checkbox (_("Override FPS (Default is to retain FPS from the input video file):"))
97  , meta_checkbox (_("Include Session Metadata"))
98 #if 1 /* tentative debug mode */
99  , debug_checkbox (_("Debug Mode: Print ffmpeg command and output to stdout."))
100 #endif
101 {
102  set_name ("ExportVideoDialog");
103  set_modal (true);
104  set_skip_taskbar_hint (true);
105  set_resizable (false);
106 
107  Gtk::Label* l;
108  vbox = manage (new VBox);
109  VBox* options_box = manage (new VBox);
110  HBox* path_hbox;
111 
112  /* check if ffmpeg can be found */
113  _transcoder = new TranscodeFfmpeg(X_(""));
114  if (!_transcoder->ffexec_ok()) {
115  l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Video Export is not possible until you install those tools. See the Log window for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
116  l->set_line_wrap();
117  vbox->pack_start (*l, false, false, 8);
118  get_vbox()->pack_start (*vbox, false, false);
119  add_button (Stock::OK, RESPONSE_CANCEL);
120  show_all_children ();
121  delete _transcoder; _transcoder = 0;
122  return;
123  }
124  delete _transcoder; _transcoder = 0;
125 
126  l = manage (new Label (_("<b>Output:</b> (file extension defines format)"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
127  l->set_use_markup ();
128  vbox->pack_start (*l, false, false, 4);
129 
130  path_hbox = manage (new HBox);
131  path_hbox->pack_start (outfn_path_label, false, false, 3);
132  path_hbox->pack_start (outfn_path_entry, true, true, 3);
133  path_hbox->pack_start (outfn_browse_button, false, false, 3);
134  vbox->pack_start (*path_hbox, false, false, 2);
135 
136  l = manage (new Label (_("<b>Input Video:</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
137  l->set_use_markup ();
138  vbox->pack_start (*l, false, false, 4);
139 
140  path_hbox = manage (new HBox);
141  path_hbox->pack_start (invid_path_label, false, false, 3);
142  path_hbox->pack_start (invid_path_entry, true, true, 3);
143  path_hbox->pack_start (invid_browse_button, false, false, 3);
144  vbox->pack_start (*path_hbox, false, false, 2);
145 
146  path_hbox = manage (new HBox);
147  l = manage (new Label (_("Audio:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
148  path_hbox->pack_start (*l, false, false, 3);
149  l = manage (new Label (_("Master Bus"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
150  path_hbox->pack_start (*l, false, false, 2);
151  vbox->pack_start (*path_hbox, false, false, 2);
152 
153  insnd_combo.set_name ("PaddedButton");
154  insnd_combo.append_text (string_compose (_("from the %1 session's start to the session's end"), PROGRAM_NAME));
155  outfn_path_entry.set_width_chars(38);
156 
157  l = manage (new Label (_("<b>Settings:</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
158  l->set_use_markup ();
159  options_box->pack_start (*l, false, true, 4);
160 
161  Table* t = manage (new Table (4, 12));
162  t->set_spacings (4);
163  int ty = 0;
164  options_box->pack_start (*t, true, true, 4);
165  l = manage (new Label (_("Range:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
166  t->attach (*l, 0, 1, ty, ty+1);
167  t->attach (insnd_combo, 1, 4, ty, ty+1); ty++;
168  l = manage (new Label (_("Preset:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
169  t->attach (*l, 0, 1, ty, ty+1);
170  t->attach (preset_combo, 1, 4, ty, ty+1); ty++;
171  l = manage (new Label (_("Video Codec:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
172  t->attach (*l, 0, 1, ty, ty+1);
173  t->attach (video_codec_combo, 1, 2, ty, ty+1);
174  l = manage (new Label (_("Video KBit/s:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
175  t->attach (*l, 2, 3, ty, ty+1);
176  t->attach (video_bitrate_combo, 3, 4, ty, ty+1); ty++;
177  l = manage (new Label (_("Audio Codec:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
178  t->attach (*l, 0, 1, ty, ty+1);
179  t->attach (audio_codec_combo, 1, 2, ty, ty+1);
180  l = manage (new Label (_("Audio KBit/s:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
181  t->attach (*l, 2, 3, ty, ty+1);
182  t->attach (audio_bitrate_combo, 3, 4, ty, ty+1); ty++;
183  l = manage (new Label (_("Audio Samplerate:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
184  t->attach (*l, 0, 1, ty, ty+1);
185  t->attach (audio_samplerate_combo, 1, 2, ty, ty+1);
186  t->attach (normalize_checkbox, 2, 4, ty, ty+1); ty++;
187  t->attach (scale_checkbox, 0, 1, ty, ty+1);
188  t->attach (scale_aspect, 1, 2, ty, ty+1);
189  t->attach (width_spinner, 2, 3, ty, ty+1);
190  t->attach (height_spinner, 3, 4, ty, ty+1); ty++;
191  t->attach (fps_checkbox, 0, 3, ty, ty+1);
192  t->attach (fps_combo, 3, 4, ty, ty+1); ty++;
193  t->attach (twopass_checkbox, 0, 2, ty, ty+1);
194  t->attach (aspect_checkbox, 2, 3, ty, ty+1);
195  t->attach (aspect_combo, 3, 4, ty, ty+1); ty++;
196  t->attach (bframes_checkbox, 0, 2, ty, ty+1);
197  t->attach (deinterlace_checkbox, 2, 4, ty, ty+1); ty++;
198  t->attach (meta_checkbox, 2, 4, ty, ty+1); ty++;
199  t->attach (optimizations_checkbox, 0, 1, ty, ty+1);
200  t->attach (optimizations_label, 1, 4, ty, ty+1); ty++;
201 #if 1 /* tentative debug mode */
202  t->attach (debug_checkbox, 0, 4, ty, ty+1); ty++;
203 #endif
204 
205  preset_combo.set_name ("PaddedButton");
206  preset_combo.append_text("none");
207  preset_combo.append_text("dvd-mp2");
208  preset_combo.append_text("dvd-NTSC");
209  preset_combo.append_text("dvd-PAL");
210  preset_combo.append_text("flv");
211  preset_combo.append_text("mpeg4");
212  preset_combo.append_text("mp4/h264/aac");
213  preset_combo.append_text("ogg");
214  preset_combo.append_text("webm");
215  preset_combo.append_text("you-tube");
216 
217  audio_codec_combo.set_name ("PaddedButton");
218  audio_codec_combo.append_text(_("(default for format)"));
219  audio_codec_combo.append_text("ac3");
220  audio_codec_combo.append_text("aac");
221  audio_codec_combo.append_text("libmp3lame");
222  audio_codec_combo.append_text("libvorbis");
223  audio_codec_combo.append_text("mp2");
224  audio_codec_combo.append_text("pcm_s16le");
225 
226  video_codec_combo.set_name ("PaddedButton");
227  video_codec_combo.append_text(_("(default for format)"));
228  video_codec_combo.append_text("flv");
229  video_codec_combo.append_text("libtheora");
230  video_codec_combo.append_text("mjpeg");
231  video_codec_combo.append_text("mpeg2video");
232  video_codec_combo.append_text("mpeg4");
233  video_codec_combo.append_text("h264");
234  video_codec_combo.append_text("vpx (webm)");
235  video_codec_combo.append_text("copy");
236 
237  audio_bitrate_combo.set_name ("PaddedButton");
238  audio_bitrate_combo.append_text(_("(default)"));
239  audio_bitrate_combo.append_text("64k");
240  audio_bitrate_combo.append_text("128k");
241  audio_bitrate_combo.append_text("192k");
242  audio_bitrate_combo.append_text("256k");
243  audio_bitrate_combo.append_text("320k");
244 
245  audio_samplerate_combo.set_name ("PaddedButton");
246  audio_samplerate_combo.append_text("22050");
247  audio_samplerate_combo.append_text("44100");
248  audio_samplerate_combo.append_text("48000");
249 
250  video_bitrate_combo.set_name ("PaddedButton");
251  video_bitrate_combo.append_text(_("(default)"));
252  video_bitrate_combo.append_text(_("(retain)"));
253  video_bitrate_combo.append_text("200k");
254  video_bitrate_combo.append_text("800k");
255  video_bitrate_combo.append_text("2000k");
256  video_bitrate_combo.append_text("5000k");
257  video_bitrate_combo.append_text("8000k");
258 
259  fps_combo.set_name ("PaddedButton");
260  fps_combo.append_text("23.976");
261  fps_combo.append_text("24");
262  fps_combo.append_text("24.976");
263  fps_combo.append_text("25");
264  fps_combo.append_text("29.97");
265  fps_combo.append_text("30");
266  fps_combo.append_text("59.94");
267  fps_combo.append_text("60");
268 
269  aspect_combo.set_name ("PaddedButton");
270  aspect_combo.append_text("4:3");
271  aspect_combo.append_text("16:9");
272 
273  vbox->pack_start (*options_box, false, true, 4);
274  get_vbox()->set_spacing (4);
275  get_vbox()->pack_start (*vbox, false, false);
276 
277  progress_box = manage (new VBox);
278  progress_box->pack_start (pbar, false, false);
279  progress_box->pack_start (abort_button, false, false);
280  get_vbox()->pack_start (*progress_box, false, false);
281 
282  scale_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::scale_checkbox_toggled));
283  aspect_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::aspect_checkbox_toggled));
284  fps_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::fps_checkbox_toggled));
285  preset_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::preset_combo_changed));
286  video_codec_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::video_codec_combo_changed));
287  outfn_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_outfn_dialog));
288  invid_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_invid_dialog));
289  transcode_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::launch_export));
290  abort_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::abort_clicked));
291 
292  invid_path_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::set_original_file_information));
293  width_spinner.signal_value_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::width_value_changed));
294  height_spinner.signal_value_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::height_value_changed));
295 
296  cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
297  get_action_area()->pack_start (transcode_button, false, false);
298  show_all_children ();
299  progress_box->hide();
300 }
301 
303 {
304  if (_transcoder) { delete _transcoder; _transcoder = 0;}
305 }
306 
307 void
309 {
310  assert(_transcoder == 0);
311  std::string infile = invid_path_entry.get_text();
312 
313  if (scale_checkbox.get_active()) {
314  // user may have set custom values already, don't touch.
315  return;
316  }
317  if (infile == "" || !Glib::file_test(infile, Glib::FILE_TEST_EXISTS)) {
318  return;
319  }
320 
321  _transcoder = new TranscodeFfmpeg(infile);
322  if (_transcoder->probe_ok()) {
324  width_spinner.set_value(_transcoder->get_width());
325  height_spinner.set_value(_transcoder->get_height());
327  }
328 
329  delete _transcoder; _transcoder = 0;
330 }
331 void
333 {
334  _suspend_dirty = true; // TODO really just queue 'dirty' and mark session dirty on "Export"
335 
336  export_range = tme;
338 
339  outfn_path_entry.set_text (_session->session_directory().export_path() + G_DIR_SEPARATOR +"export.avi");
340 
341  // TODO remember setting for export-range.. somehow, (let explicit range override)
343  if (av_offset < 0 ) {
344  insnd_combo.append_text (_("from 00:00:00:00 to the video's end"));
345  } else {
346  insnd_combo.append_text (_("from the video's start to the video's end"));
347  }
348  if (!export_range.empty()) {
349  insnd_combo.append_text (_("Selected range")); // TODO show export_range.start() -> export_range.end_frame()
350  }
351  if (range) {
352  insnd_combo.set_active(2);
353  } else {
354  insnd_combo.set_active(0);
355  }
356 
357  preset_combo.set_active(0);
358  audio_codec_combo.set_active(0);
359  video_codec_combo.set_active(0);
360  audio_bitrate_combo.set_active(0);
361  audio_samplerate_combo.set_active(2);
362  video_bitrate_combo.set_active(0);
363  aspect_combo.set_active(1);
364 
365  scale_checkbox.set_active(false);
366  scale_aspect.set_active(true);
367  aspect_checkbox.set_active(false);
368  normalize_checkbox.set_active(false);
369  twopass_checkbox.set_active(false);
370  optimizations_checkbox.set_active(false);
371  deinterlace_checkbox.set_active(false);
372  bframes_checkbox.set_active(false);
373  fps_checkbox.set_active(false);
374  meta_checkbox.set_active(false);
375 
376  float tcfps = _session->timecode_frames_per_second();
377 
378  LocaleGuard lg (X_("C"));
379 
380  XMLNode* node = _session->extra_xml (X_("Videotimeline"));
381  bool filenameset = false;
382  if (node) {
383  if (node->property(X_("OriginalVideoFile"))) {
384  std::string filename = node->property(X_("OriginalVideoFile"))->value();
385  if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) {
386  invid_path_entry.set_text (filename);
387  filenameset = true;
388  }
389  }
390  if (!filenameset
391  && node->property(X_("Filename"))
392  && node->property(X_("LocalFile"))
393  && node->property(X_("LocalFile"))->value() == X_("1")
394  )
395  {
396  std::string filename = node->property(X_("Filename"))->value();
397  if (filename.at(0) != G_DIR_SEPARATOR)
398  {
399  filename = Glib::build_filename (_session->session_directory().video_path(), filename);
400  }
401  if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS))
402  {
403  invid_path_entry.set_text (filename);
404  filenameset = true;
405  }
406  }
407  }
408  if (!filenameset) {
409  invid_path_entry.set_text (X_(""));
410  }
411 
412  node = _session->extra_xml (X_("Videoexport"));
413  if (node) {
414  const XMLProperty* prop;
415  prop = node->property (X_("ChangeGeometry"));
416  if (prop) { scale_checkbox.set_active(atoi(prop->value())?true:false); }
417  prop = node->property (X_("KeepAspect"));
418  if (prop) { scale_aspect.set_active(atoi(prop->value())?true:false); }
419  prop = node->property (X_("ChangeAspect"));
420  if (prop) { aspect_checkbox.set_active(atoi(prop->value())?true:false); }
421  prop = node->property (X_("NormalizeAudio"));
422  if (prop) { normalize_checkbox.set_active(atoi(prop->value())?true:false); }
423  prop = node->property (X_("TwoPassEncode"));
424  if (prop) { twopass_checkbox.set_active(atoi(prop->value())?true:false); }
425  prop = node->property (X_("CodecOptimzations"));
426  if (prop) { optimizations_checkbox.set_active(atoi(prop->value())?true:false); }
427  prop = node->property (X_("Deinterlace"));
428  if (prop) { deinterlace_checkbox.set_active(atoi(prop->value())?true:false); }
429  prop = node->property (X_("BFrames"));
430  if (prop) { bframes_checkbox.set_active(atoi(prop->value())?true:false); }
431  prop = node->property (X_("ChangeFPS"));
432  if (prop) { fps_checkbox.set_active(atoi(prop->value())?true:false); }
433  prop = node->property (X_("Metadata"));
434  if (prop) { meta_checkbox.set_active(atoi(prop->value())?true:false); }
435 
436  prop = node->property (X_("Format"));
437  if (prop && !prop->value().empty()) { change_file_extension( "." + prop->value()); }
438 
439  _suspend_signals = true;
440  prop = node->property (X_("Width"));
441  if (prop) { width_spinner.set_value(atoi(prop->value())); }
442  prop = node->property (X_("Height"));
443  if (prop) { height_spinner.set_value(atoi(prop->value())); }
444  _suspend_signals = false;
445 
446  prop = node->property (X_("FPS"));
447  if (prop && fps_checkbox.get_active()) { tcfps = atof(prop->value()); }
448 
449  prop = node->property (X_("Preset"));
450  if (prop) { preset_combo.set_active_text(prop->value()); }
451  prop = node->property (X_("VCodec"));
452  if (prop) { video_codec_combo.set_active_text(prop->value()); }
453  prop = node->property (X_("ACodec"));
454  if (prop) { audio_codec_combo.set_active_text(prop->value()); }
455  prop = node->property (X_("VBitrate"));
456  if (prop) { video_bitrate_combo.set_active_text(prop->value()); }
457  prop = node->property (X_("ABitrate"));
458  if (prop) { audio_bitrate_combo.set_active_text(prop->value()); }
459  prop = node->property (X_("AspectRatio"));
460  if (prop) { aspect_combo.set_active_text(prop->value()); }
461  prop = node->property (X_("SampleRate"));
462  if (prop) { audio_samplerate_combo.set_active_text(prop->value()); }
463  }
464 
465  if (fabs(tcfps - 23.976) < 0.01) { fps_combo.set_active(0); }
466  else if (fabs(tcfps - 24.0 ) < 0.01) { fps_combo.set_active(1); }
467  else if (fabs(tcfps - 24.976) < 0.01) { fps_combo.set_active(2); }
468  else if (fabs(tcfps - 25.0 ) < 0.01) { fps_combo.set_active(3); }
469  else if (fabs(tcfps - 29.97 ) < 0.01) { fps_combo.set_active(4); }
470  else if (fabs(tcfps - 30.0 ) < 0.01) { fps_combo.set_active(5); }
471  else if (fabs(tcfps - 59.94 ) < 0.01) { fps_combo.set_active(6); }
472  else if (fabs(tcfps - 60.0 ) < 0.01) { fps_combo.set_active(7); }
473  else { fps_combo.set_active(5); }
474 
476 
477  /* update sensitivity */
482 
483  _suspend_dirty = false;
484 
485  show_all_children ();
486  if (progress_box) {
487  progress_box->hide();
488  }
489 }
490 
491 XMLNode&
493 {
494  LocaleGuard lg (X_("C"));
495  XMLNode* node = new XMLNode (X_("Videoexport"));
496  node->add_property (X_("ChangeGeometry"), scale_checkbox.get_active() ? X_("1") : X_("0"));
497  node->add_property (X_("KeepAspect"), scale_aspect.get_active() ? X_("1") : X_("0"));
498  node->add_property (X_("ChangeAspect"), aspect_checkbox.get_active() ? X_("1") : X_("0"));
499  node->add_property (X_("NormalizeAudio"), normalize_checkbox.get_active() ? X_("1") : X_("0"));
500  node->add_property (X_("TwoPassEncode"), twopass_checkbox.get_active() ? X_("1") : X_("0"));
501  node->add_property (X_("CodecOptimzations"), optimizations_checkbox.get_active() ? X_("1") : X_("0"));
502  node->add_property (X_("Deinterlace"), deinterlace_checkbox.get_active() ? X_("1") : X_("0"));
503  node->add_property (X_("BFrames"), bframes_checkbox.get_active() ? X_("1") : X_("0"));
504  node->add_property (X_("ChangeFPS"), fps_checkbox.get_active() ? X_("1") : X_("0"));
505  node->add_property (X_("Metadata"), meta_checkbox.get_active() ? X_("1") : X_("0"));
506 
507  node->add_property (X_("Format"), get_file_extension(outfn_path_entry.get_text()));
508 
509  node->add_property (X_("Width"), width_spinner.get_value());
510  node->add_property (X_("Height"), height_spinner.get_value());
511 
512  node->add_property (X_("Preset"), preset_combo.get_active_text());
513  node->add_property (X_("VCodec"), video_codec_combo.get_active_text());
514  node->add_property (X_("ACodec"), audio_codec_combo.get_active_text());
515  node->add_property (X_("VBitrate"), video_bitrate_combo.get_active_text());
516  node->add_property (X_("ABitrate"), audio_bitrate_combo.get_active_text());
517  node->add_property (X_("AspectRatio"), aspect_combo.get_active_text());
518  node->add_property (X_("SampleRate"), audio_samplerate_combo.get_active_text());
519  node->add_property (X_("FPS"), fps_combo.get_active_text());
520 
521  return *node;
522 }
523 
524 void
526 {
527 }
528 
529 void
531 {
532  Dialog::on_show ();
533 }
534 
535 void
537 {
538  _aborted = true;
539  if (_transcoder) {
540  _transcoder->cancel();
541  }
542 }
543 
544 void
546 {
547  if (a == 0 || c > a) {
548  pbar.set_pulse_step(.1);
549  pbar.pulse();
550  } else {
551  double progress = (double)c / (double) a;
552  progress = progress / ((_twopass ? 2.0 : 1.0) + (_normalize ? 2.0 : 1.0));
553  if (_normalize && _twopass) progress += (_firstpass ? .5 : .75);
554  else if (_normalize) progress += 2.0/3.0;
555  else if (_twopass) progress += (_firstpass ? 1.0/3.0 : 2.0/3.0);
556  else progress += .5;
557 
558  pbar.set_fraction (progress);
559  }
560 }
561 
562 
563 gint
565 {
566  std::string status_text;
567  double progress = 0.0;
568  if (status->normalizing) {
569  pbar.set_text (_("Normalizing audio"));
571  progress = progress / (_twopass ? 4.0 : 3.0) + (_twopass ? .25 : 1.0/3.0);
572  } else {
573  pbar.set_text (_("Exporting audio"));
575  progress = progress / ((_twopass ? 2.0 : 1.0) + (_normalize ? 2.0 : 1.0));
576  }
577  if (progress < _previous_progress) {
578  // Work around gtk bug
579  pbar.hide();
580  pbar.show();
581  }
582  _previous_progress = progress;
583  pbar.set_fraction (progress);
584  return TRUE;
585 }
586 
587 void
589 {
590  if (_aborted) {
591  ::g_unlink(outfn_path_entry.get_text().c_str());
592  ::g_unlink (_insnd.c_str());
593  delete _transcoder; _transcoder = 0;
594  Gtk::Dialog::response(RESPONSE_CANCEL);
595  } else if (_twopass && _firstpass) {
596  _firstpass = false;
597  if (_transcoder) { delete _transcoder; _transcoder = 0;}
598  encode_pass(2);
599  } else {
600  if (twopass_checkbox.get_active()) {
601  std::string outfn = outfn_path_entry.get_text();
602  std::string p2log = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass";
603  ::g_unlink (p2log.c_str());
604  }
605  ::g_unlink (_insnd.c_str());
606  delete _transcoder; _transcoder = 0;
607  Gtk::Dialog::response(RESPONSE_ACCEPT);
608  }
609 }
610 
611 void
613 {
614  /* remember current settings.
615  * needed because apply_state() acts on both:
616  * "Videotimeline" and "Video Export" extra XML
617  * as well as current _session settings
618  */
620 
621  std::string outfn = outfn_path_entry.get_text();
622  if (!confirm_video_outfn(outfn)) { return; }
623 
624  vbox->hide();
625  cancel_button->hide();
626  transcode_button.hide();
627  pbar.set_size_request(300,-1);
628  pbar.set_text(_("Exporting Audio..."));
629  progress_box->show();
630  _aborted = false;
631  _twopass = twopass_checkbox.get_active();
632  _firstpass = true;
633  _normalize = normalize_checkbox.get_active();
634 
635  /* export audio track */
640  XMLTree tree;
641  std::string vtl_samplerate = audio_samplerate_combo.get_active_text();
642  std::string vtl_normalize = _normalize ? "true" : "false";
643  tree.read_buffer(std::string(
644 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
645 "<ExportFormatSpecification name=\"VTL-WAV-16\" id=\"3094591e-ccb9-4385-a93f-c9955ffeb1f0\">"
646 " <Encoding id=\"F_WAV\" type=\"T_Sndfile\" extension=\"wav\" name=\"WAV\" has-sample-format=\"true\" channel-limit=\"256\"/>"
647 " <SampleRate rate=\""+ vtl_samplerate +"\"/>"
648 " <SRCQuality quality=\"SRC_SincBest\"/>"
649 " <EncodingOptions>"
650 " <Option name=\"sample-format\" value=\"SF_16\"/>"
651 " <Option name=\"dithering\" value=\"D_None\"/>"
652 " <Option name=\"tag-metadata\" value=\"true\"/>"
653 " <Option name=\"tag-support\" value=\"false\"/>"
654 " <Option name=\"broadcast-info\" value=\"false\"/>"
655 " </EncodingOptions>"
656 " <Processing>"
657 " <Normalize enabled=\""+ vtl_normalize +"\" target=\"0\"/>"
658 " <Silence>"
659 " <Start>"
660 " <Trim enabled=\"false\"/>"
661 " <Add enabled=\"false\">"
662 " <Duration format=\"Timecode\" hours=\"0\" minutes=\"0\" seconds=\"0\" frames=\"0\"/>"
663 " </Add>"
664 " </Start>"
665 " <End>"
666 " <Trim enabled=\"false\"/>"
667 " <Add enabled=\"false\">"
668 " <Duration format=\"Timecode\" hours=\"0\" minutes=\"0\" seconds=\"0\" frames=\"0\"/>"
669 " </Add>"
670 " </End>"
671 " </Silence>"
672 " </Processing>"
673 "</ExportFormatSpecification>"
674 ));
676 
677  /* set up range */
678  framepos_t start, end;
679  start = end = 0;
680  if (insnd_combo.get_active_row_number() == 1) {
681  _transcoder = new TranscodeFfmpeg(invid_path_entry.get_text());
682  if (_transcoder->probe_ok() && _transcoder->get_fps() > 0) {
684  } else {
685  warning << _("Export Video: Cannot query duration of video-file, using duration from timeline instead.") << endmsg;
687  }
688  if (_transcoder) {delete _transcoder; _transcoder = 0;}
689 
691 #if 0 /* DEBUG */
692  printf("audio-range -- AV offset: %lld\n", av_offset);
693 #endif
694  if (av_offset > 0) {
695  start = av_offset;
696  }
697  end += av_offset;
698  }
699  else if (insnd_combo.get_active_row_number() == 2) {
702  }
703  if (end <= 0) {
704  start = _session->current_start_frame();
705  end = _session->current_end_frame();
706  }
707 #if 0 /* DEBUG */
708  printf("audio export-range %lld -> %lld\n", start, end);
709 #endif
710 
712  const frameoffset_t vend = vstart + ARDOUR_UI::instance()->video_timeline->get_duration();
713 
714  if ( (start >= end) || (end < vstart) || (start > vend)) {
715  warning << _("Export Video: export-range does not include video.") << endmsg;
716  delete _transcoder; _transcoder = 0;
717  Gtk::Dialog::response(RESPONSE_CANCEL);
718  return;
719  }
720 
721  tsp->set_range (start, end);
722  tsp->set_name ("mysession");
723  tsp->set_range_id ("session");
724 
725  /* add master outs as default */
726  IO* master_out = _session->master_out()->output().get();
727  if (!master_out) {
728  warning << _("Export Video: No Master Out Ports to Connect for Audio Export") << endmsg;
729  delete _transcoder; _transcoder = 0;
730  Gtk::Dialog::response(RESPONSE_CANCEL);
731  return;
732  }
733  for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) {
734  PortExportChannel * channel = new PortExportChannel ();
735  channel->add_port (master_out->audio (n));
736  ExportChannelPtr chan_ptr (channel);
737  ccp->register_channel (chan_ptr);
738  }
739 
740  /* outfile */
741  fnp->set_timespan(tsp);
742  fnp->set_label("vtl");
743  fnp->include_label = true;
744  _insnd = fnp->get_path(fmp);
745 
746  /* do sound export */
747  fmp->set_soundcloud_upload(false);
748  _session->get_export_handler()->add_export_config (tsp, ccp, fmp, fnp, b);
751 
752  audio_progress_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ExportVideoDialog::audio_progress_display), 100);
753  _previous_progress = 0.0;
754  while (status->running) {
755  if (_aborted) { status->abort(); }
756  if (gtk_events_pending()) {
757  gtk_main_iteration ();
758  } else {
759  Glib::usleep (10000);
760  }
761  }
762  audio_progress_connection.disconnect();
763  status->finish ();
764  if (status->aborted()) {
765  ::g_unlink (_insnd.c_str());
766  delete _transcoder; _transcoder = 0;
767  Gtk::Dialog::response(RESPONSE_CANCEL);
768  return;
769  }
770  pbar.set_text (_("Encoding Video..."));
771  encode_pass(1);
772 }
773 
774 void
776 {
777  std::string outfn = outfn_path_entry.get_text();
778  std::string invid = invid_path_entry.get_text();
779 
780  _transcoder = new TranscodeFfmpeg(invid);
781  if (!_transcoder->ffexec_ok()) {
782  /* ffmpeg binary was not found. TranscodeFfmpeg prints a warning */
783  ::g_unlink (_insnd.c_str());
784  delete _transcoder; _transcoder = 0;
785  Gtk::Dialog::response(RESPONSE_CANCEL);
786  return;
787  }
788  if (!_transcoder->probe_ok()) {
789  /* video input file can not be read */
790  warning << _("Export Video: Video input file cannot be read.") << endmsg;
791  ::g_unlink (_insnd.c_str());
792  delete _transcoder; _transcoder = 0;
793  Gtk::Dialog::response(RESPONSE_CANCEL);
794  return;
795  }
796 
797  std::string preset = preset_combo.get_active_text();
798  TranscodeFfmpeg::FFSettings ffs ; /* = transcoder->default_encoder_settings(); */
799  ffs.clear();
800 
801  if (fps_checkbox.get_active()) {
802  ffs["-r"] = fps_combo.get_active_text();
803  _transcoder->set_fps(atof(fps_combo.get_active_text()));
804  }
805 
806  if (scale_checkbox.get_active()) {
807  ffs["-s"] = string_compose("%1x%2", width_spinner.get_value(), height_spinner.get_value());
808  }
809 
810  if (video_codec_combo.get_active_text() != _("(default for format)")) {
811  ffs["-vcodec"] = video_codec_combo.get_active_text();
812  }
813  if (audio_codec_combo.get_active_text() != _("(default for format)")) {
814  ffs["-acodec"] = audio_codec_combo.get_active_text();
815  }
816 
817  if (video_bitrate_combo.get_active_text() == _("(default)") ) {
818  ;
819  }
820  else if (video_bitrate_combo.get_active_text() == _("(retain)") ) {
821  ffs["-qscale"] = "0";
822  } else {
823  ffs["-b:v"] = video_bitrate_combo.get_active_text();
824  }
825 
826  if (audio_bitrate_combo.get_active_text() != _("(default)") ) {
827  ffs["-b:a"] = audio_bitrate_combo.get_active_text();
828  }
829 
830  if (audio_codec_combo.get_active_text() == "aac" ) {
831  ffs["-strict"] = "-2";
832  }
833 
834  if (video_codec_combo.get_active_text() == "h264" ) {
835  ffs["-vcodec"] = "libx264";
836  }
837  else if (video_codec_combo.get_active_text() == "vpx (webm)" ) {
838  ffs["-vcodec"] = "libvpx";
839  ffs["-g"] = "120";
840  ffs["-qmin"] = "11";
841  ffs["-qmax"] = "51";
842  }
843 
844  if (optimizations_checkbox.get_active()) {
845  if (video_codec_combo.get_active_text() == "mpeg2video") {
846  ffs["-mbd"] = "rd";
847  ffs["-trellis"] = "2";
848  ffs["-cmp"] = "2";
849  ffs["-subcmp"] = "2";
850  }
851  else if (video_codec_combo.get_active_text() == "mpeg4") {
852  ffs["-mbd"] = "rd";
853  ffs["-flags"] = "+mv4+aic";
854  ffs["-trellis"] = "2";
855  ffs["-cmp"] = "2";
856  ffs["-subcmp"] = "2";
857  ffs["-g"] = "300";
858  }
859  else if (video_codec_combo.get_active_text() == "flv") {
860  ffs["-mbd"] = "2";
861  ffs["-cmp"] = "2";
862  ffs["-subcmp"] = "2";
863  ffs["-trellis"] = "2";
864  ffs["-flags"] = "+aic+mv0+mv4";
865  ffs["-g"] = "160";
866  }
867  }
868 
869  if (bframes_checkbox.get_active() && (
870  video_codec_combo.get_active_text() == "mpeg2video"
871  || video_codec_combo.get_active_text() == "mpeg4"
872  )) {
873  ffs["-bf"] = "2";
874  }
875 
876  if (preset == "dvd-PAL") {
877  ffs.clear(); /* ignore all prev settings */
878  ffs["-target"] = "pal-dvd";
879  ffs["-aspect"] = "4:3"; /* required for DVD - may be overridden below */
880  }
881  else if (preset == "dvd-NTSC") {
882  ffs.clear(); /* ignore all prev settings */
883  ffs["-target"] = "ntsc-dvd";
884  ffs["-aspect"] = "4:3"; /* required for DVD - may be overridden below */
885  }
886 
887  if (aspect_checkbox.get_active()) {
888  ffs["-aspect"] = aspect_combo.get_active_text();
889  }
890  if (deinterlace_checkbox.get_active()) {
891  ffs["-deinterlace"] = "-y"; // we use '-y' as dummy parameter for non key/value options
892  }
893 
894  bool map = true;
895  if (pass == 1 && _twopass) {
896  pbar.set_text (_("Encoding Video.. Pass 1/2"));
897  map = false;
898  ffs["-pass"] = "1";
899  ffs["-an"] = "-y";
900  ffs["-passlogfile"] = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass";
901  ffs["-f"] = get_file_extension(invid).empty()?"mov":get_file_extension(invid);
902 #ifdef PLATFORM_WINDOWS
903  outfn = "NUL";
904 #else
905  outfn = "/dev/null";
906 #endif
907  } else if (pass == 2) {
908  pbar.set_text (_("Encoding Video.. Pass 2/2"));
909  ffs["-pass"] = "2";
910  ffs["-passlogfile"] = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass";
911  }
912 
914  double duration_s = 0;
915 
916  if (insnd_combo.get_active_row_number() == 0) {
917  /* session start to session end */
919  duration_s = (double)duration_f / (double)_session->nominal_frame_rate();
920  } else if (insnd_combo.get_active_row_number() == 2) {
921  /* selected range */
922  duration_s = export_range.length() / (double)_session->nominal_frame_rate();
923  } else {
924  /* video start to end */
926  if (av_offset < 0 ) {
927  duration_f += av_offset;
928  }
929  duration_s = (double)duration_f / (double)_session->nominal_frame_rate();
930  }
931 
932  std::ostringstream osstream; osstream << duration_s;
933  ffs["-t"] = osstream.str();
934  _transcoder->set_duration(duration_s * _transcoder->get_fps());
935 
936  if (insnd_combo.get_active_row_number() == 0 || insnd_combo.get_active_row_number() == 2) {
937  framepos_t start, snend;
939  if (insnd_combo.get_active_row_number() == 0) {
940  start = _session->current_start_frame();
941  snend = _session->current_end_frame();
942  } else {
943  start = export_range.start();
944  snend = export_range.end_frame();
945  }
946 
947 #if 0 /* DEBUG */
948  printf("AV offset: %lld Vid-len: %lld Vid-end: %lld || start:%lld || end:%lld\n",
949  av_offset, vid_duration, av_offset+vid_duration, start, snend); // XXX
950 #endif
951 
952  if (av_offset > start && av_offset + vid_duration < snend) {
953  _transcoder->set_leadinout((av_offset - start) / (double)_session->nominal_frame_rate(),
954  (snend - (av_offset + vid_duration)) / (double)_session->nominal_frame_rate());
955  } else if (av_offset > start) {
956  _transcoder->set_leadinout((av_offset - start) / (double)_session->nominal_frame_rate(), 0);
957  } else if (av_offset + vid_duration < snend) {
958  _transcoder->set_leadinout(0, (snend - (av_offset + vid_duration)) / (double)_session->nominal_frame_rate());
959  _transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_frame_rate());
960  }
961 #if 0
962  else if (start > av_offset) {
963  std::ostringstream osstream; osstream << ((start - av_offset) / (double)_session->nominal_frame_rate());
964  ffs["-ss"] = osstream.str();
965  }
966 #endif
967  else {
968  _transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_frame_rate());
969  }
970 
971  } else if (av_offset < 0) {
972  /* from 00:00:00:00 to video-end */
973  _transcoder->set_avoffset(av_offset / (double)_session->nominal_frame_rate());
974  }
975 
977  if (meta_checkbox.get_active()) {
979  if (session_data->year() > 0 ) {
980  std::ostringstream osstream; osstream << session_data->year();
981  meta["year"] = osstream.str();
982  }
983  if (session_data->track_number() > 0 ) {
984  std::ostringstream osstream; osstream << session_data->track_number();
985  meta["track"] = osstream.str();
986  }
987  if (session_data->disc_number() > 0 ) {
988  std::ostringstream osstream; osstream << session_data->disc_number();
989  meta["disc"] = osstream.str();
990  }
991  if (!session_data->title().empty()) {meta["title"] = session_data->title();}
992  if (!session_data->artist().empty()) {meta["author"] = session_data->artist();}
993  if (!session_data->album_artist().empty()) {meta["album_artist"] = session_data->album_artist();}
994  if (!session_data->album().empty()) {meta["album"] = session_data->album();}
995  if (!session_data->genre().empty()) {meta["genre"] = session_data->genre();}
996  if (!session_data->composer().empty()) {meta["composer"] = session_data->composer();}
997  if (!session_data->comment().empty()) {meta["comment"] = session_data->comment();}
998  if (!session_data->copyright().empty()) {meta["copyright"] = session_data->copyright();}
999  if (!session_data->subtitle().empty()) {meta["description"] = session_data->subtitle();}
1000  }
1001 
1002 #if 1 /* tentative debug mode */
1003  if (debug_checkbox.get_active()) {
1004  _transcoder->set_debug(true);
1005  }
1006 #endif
1007 
1008  _transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&ExportVideoDialog::update_progress , this, _1, _2), gui_context());
1009  _transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&ExportVideoDialog::finished, this), gui_context());
1010  if (!_transcoder->encode(outfn, _insnd, invid, ffs, meta, map)) {
1011  ARDOUR_UI::instance()->popup_error(_("Transcoding failed."));
1012  delete _transcoder; _transcoder = 0;
1013  Gtk::Dialog::response(RESPONSE_CANCEL);
1014  return;
1015  }
1016 }
1017 
1018 void
1020 {
1021  if (ext == "") return;
1022  outfn_path_entry.set_text (
1023  strip_file_extension(outfn_path_entry.get_text()) + ext
1024  );
1025 }
1026 
1027 void
1029 {
1030  if (_suspend_signals) {
1031  return;
1032  }
1034  if (!scale_checkbox.get_active() || !scale_aspect.get_active()) {
1035  return;
1036  }
1037  if (_video_source_aspect_ratio <= 0) {
1038  return;
1039  }
1040  _suspend_signals = true;
1041  height_spinner.set_value(rintf(width_spinner.get_value() / _video_source_aspect_ratio));
1042  _suspend_signals = false;
1043 }
1044 
1045 void
1047 {
1048  if (_suspend_signals) {
1049  return;
1050  }
1052  if (!scale_checkbox.get_active() || !scale_aspect.get_active()) {
1053  return;
1054  }
1055  if (_video_source_aspect_ratio <= 0) {
1056  return;
1057  }
1058  _suspend_signals = true;
1059  width_spinner.set_value(rintf(height_spinner.get_value() * _video_source_aspect_ratio));
1060  _suspend_signals = false;
1061 }
1062 
1063 void
1065 {
1066  scale_aspect.set_sensitive(scale_checkbox.get_active());
1067  width_spinner.set_sensitive(scale_checkbox.get_active());
1068  height_spinner.set_sensitive(scale_checkbox.get_active());
1070 }
1071 
1072 void
1074 {
1075  fps_combo.set_sensitive(fps_checkbox.get_active());
1077 }
1078 
1079 void
1081 {
1082  aspect_combo.set_sensitive(aspect_checkbox.get_active());
1084 }
1085 
1086 void
1088 {
1089  if (( video_codec_combo.get_active_text() == "mpeg4"
1090  ||video_codec_combo.get_active_text() == "mpeg2video"
1091  ) && !(
1092  preset_combo.get_active_text() == "dvd-PAL"
1093  ||preset_combo.get_active_text() == "dvd-NTSC"
1094  )) {
1095  bframes_checkbox.set_sensitive(true);
1096  optimizations_checkbox.set_sensitive(true);
1097  if (video_codec_combo.get_active_text() == "mpeg2video") {
1098  optimizations_label.set_text("-mbd rd -trellis 2 -cmp 2 -subcmp 2"); // mpeg2
1099  } else if (video_codec_combo.get_active_text() == "mpeg4") {
1100  optimizations_label.set_text("-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300"); // mpeg4
1101  } else {
1102  optimizations_label.set_text("-mbd 2 -cmp 2 -subcmp 2 -trellis 2 -flags +aic+mv0+mv4 -g 160"); // flv
1103  }
1104  } else {
1105  bframes_checkbox.set_sensitive(false);
1106  bframes_checkbox.set_active(false);
1107  optimizations_checkbox.set_sensitive(false);
1108  optimizations_checkbox.set_active(false);
1109  optimizations_label.set_text("-");
1110  }
1112 }
1113 
1114 void
1116 {
1117  std::string p = preset_combo.get_active_text();
1118  scale_checkbox.set_sensitive(true);
1119 
1120  if (p == "flv") {
1121  change_file_extension(".flv");
1122  audio_codec_combo.set_active(2);
1123  video_codec_combo.set_active(1);
1124  audio_bitrate_combo.set_active(2);
1125  video_bitrate_combo.set_active(3);
1126  audio_samplerate_combo.set_active(1);
1127  }
1128  else if (p == "you-tube") {
1129  change_file_extension(".avi");
1130  audio_codec_combo.set_active(3);
1131  video_codec_combo.set_active(6);
1132  audio_bitrate_combo.set_active(2);
1133  video_bitrate_combo.set_active(4);
1134  if (_session->nominal_frame_rate() == 48000 || _session->nominal_frame_rate() == 96000) {
1135  audio_samplerate_combo.set_active(2);
1136  } else {
1137  audio_samplerate_combo.set_active(1);
1138  }
1139  }
1140  else if (p == "ogg") {
1141  change_file_extension(".ogv");
1142  audio_codec_combo.set_active(4);
1143  video_codec_combo.set_active(2);
1144  audio_bitrate_combo.set_active(3);
1145  video_bitrate_combo.set_active(4);
1146  if (_session->nominal_frame_rate() == 48000 || _session->nominal_frame_rate() == 96000) {
1147  audio_samplerate_combo.set_active(2);
1148  } else {
1149  audio_samplerate_combo.set_active(1);
1150  }
1151  }
1152  else if (p == "webm") {
1153  change_file_extension(".webm");
1154  audio_codec_combo.set_active(4);
1155  video_codec_combo.set_active(7);
1156  audio_bitrate_combo.set_active(3);
1157  video_bitrate_combo.set_active(4);
1158  if (_session->nominal_frame_rate() == 48000 || _session->nominal_frame_rate() == 96000) {
1159  audio_samplerate_combo.set_active(2);
1160  } else {
1161  audio_samplerate_combo.set_active(1);
1162  }
1163  }
1164  else if (p == "dvd-mp2") {
1165  change_file_extension(".mpg");
1166  audio_codec_combo.set_active(5);
1167  video_codec_combo.set_active(4);
1168  audio_bitrate_combo.set_active(4);
1169  video_bitrate_combo.set_active(5);
1170  audio_samplerate_combo.set_active(2);
1171  }
1172  else if (p == "dvd-NTSC" || p == "dvd-PAL") {
1173  change_file_extension(".mpg");
1174  audio_codec_combo.set_active(6);
1175  video_codec_combo.set_active(4);
1176  audio_bitrate_combo.set_active(4);
1177  video_bitrate_combo.set_active(5);
1178  audio_samplerate_combo.set_active(2);
1179 
1180  scale_checkbox.set_active(false);
1181  scale_checkbox.set_sensitive(false);
1182  }
1183  else if (p == "mpeg4") {
1184  change_file_extension(".mp4");
1185  audio_codec_combo.set_active(1);
1186  video_codec_combo.set_active(5);
1187  audio_bitrate_combo.set_active(4);
1188  video_bitrate_combo.set_active(5);
1189  if (_session->nominal_frame_rate() == 48000 || _session->nominal_frame_rate() == 96000) {
1190  audio_samplerate_combo.set_active(2);
1191  } else {
1192  audio_samplerate_combo.set_active(1);
1193  }
1194  }
1195  else if (p == "mp4/h264/aac") {
1196  change_file_extension(".mp4");
1197  audio_codec_combo.set_active(2);
1198  video_codec_combo.set_active(6);
1199  audio_bitrate_combo.set_active(0);
1200  video_bitrate_combo.set_active(0);
1201  if (_session->nominal_frame_rate() == 48000 || _session->nominal_frame_rate() == 96000) {
1202  audio_samplerate_combo.set_active(2);
1203  } else {
1204  audio_samplerate_combo.set_active(1);
1205  }
1206  }
1207 
1208  if (p == "none") {
1209  audio_codec_combo.set_sensitive(true);
1210  video_codec_combo.set_sensitive(true);
1211  audio_bitrate_combo.set_sensitive(true);
1212  video_bitrate_combo.set_sensitive(true);
1213  audio_samplerate_combo.set_sensitive(true);
1214  } else {
1215  audio_codec_combo.set_sensitive(false);
1216  video_codec_combo.set_sensitive(false);
1217  audio_bitrate_combo.set_sensitive(false);
1218  video_bitrate_combo.set_sensitive(false);
1219  audio_samplerate_combo.set_sensitive(false);
1220  }
1221 
1222  Gtk::Table *t = (Gtk::Table*) preset_combo.get_parent();
1223  Gtk::Table_Helpers::TableList c = t->children();
1224  Gtk::Table_Helpers::TableList::iterator it;
1225  if (p == "dvd-PAL" || p == "dvd-NTSC") {
1226  for (it = c.begin(); it != c.end(); ++it) {
1227  int row = it->get_top_attach();
1228  if (row == 2 || row == 3 || row== 5 || row== 6 || row == 9) {
1229  it->get_widget()->hide();
1230  }
1231  }
1232  } else {
1233  for (it = c.begin(); it != c.end(); ++it) {
1234  int row = it->get_top_attach();
1235  if (row == 2 || row == 3 || row== 5 || row== 6 || row == 9) {
1236  it->get_widget()->show();
1237  }
1238  }
1239  }
1240 
1242 }
1243 
1244 void
1246 {
1247  Gtk::FileChooserDialog dialog(_("Save Exported Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1248  dialog.set_filename (outfn_path_entry.get_text());
1249 
1250  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1251  dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1252 
1253  int result = dialog.run();
1254 
1255  if (result == Gtk::RESPONSE_OK) {
1256  std::string filename = dialog.get_filename();
1257 
1258  if (filename.length()) {
1259  outfn_path_entry.set_text (filename);
1260  }
1261  }
1262 }
1263 
1264 void
1266 {
1267  Gtk::FileChooserDialog dialog(_("Save Exported Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE);
1268  dialog.set_filename (invid_path_entry.get_text());
1269 
1270  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1271  dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1272 
1273  int result = dialog.run();
1274 
1275  if (result == Gtk::RESPONSE_OK) {
1276  std::string filename = dialog.get_filename();
1277 
1278  if (filename.length()) {
1279  invid_path_entry.set_text (filename);
1280  }
1281  }
1282 }
Gtk::ComboBoxText video_bitrate_combo
void update_progress(ARDOUR::framecnt_t, ARDOUR::framecnt_t)
bool add_export_config(ExportTimespanPtr timespan, ExportChannelConfigPtr channel_config, ExportFormatSpecPtr format, ExportFilenamePtr filename, BroadcastInfoPtr broadcast_info)
double timecode_frames_per_second() const
Definition: session_time.cc:55
framecnt_t nominal_frame_rate() const
Definition: session.h:367
void abort(bool error_occurred=false)
int atoi(const string &s)
Definition: convert.cc:140
Gtk::CheckButton aspect_checkbox
ARDOUR::frameoffset_t get_offset()
ExportChannelConfigPtr add_channel_config()
ExportTimespanPtr add_timespan()
TimeSelection export_range
Gtk::CheckButton scale_aspect
const std::string & value() const
Definition: xml++.h:159
Gtk::CheckButton debug_checkbox
int ffs(int x)
Definition: ffs.cc:28
wrapper around ffmpeg and ffprobe command-line utils
Gtk::ProgressBar pbar
volatile framecnt_t processed_frames_current_timespan
Definition: export_status.h:66
Gtk::Button * cancel_button
std::string comment() const
const std::string video_path() const
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
Gtk::Button outfn_browse_button
std::string strip_file_extension(const std::string infile)
Gtk::ComboBoxText fps_combo
Gtk::CheckButton twopass_checkbox
Gtk::ComboBoxText aspect_combo
Gtk::Button transcode_button
volatile framecnt_t total_frames_current_timespan
Definition: export_status.h:65
void set_duration(ARDOUR::framecnt_t d)
ARDOUR::framepos_t end_frame()
uint32_t n_audio() const
Definition: chan_count.h:63
Gtk::SpinButton height_spinner
Basic export channel that reads from AudioPorts.
Definition: Beats.hpp:239
LIBPBD_API Transmitter warning
boost::shared_ptr< ARDOUR::ExportStatus > status
Gtk::CheckButton bframes_checkbox
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
bool encode(std::string outfile, std::string inf_a, std::string inf_v, FFSettings ffs, FFSettings meta, bool map=true)
Gtk::CheckButton fps_checkbox
uint32_t track_number() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
ARDOUR::frameoffset_t quantify_frames_to_apv(ARDOUR::frameoffset_t offset)
std::string genre() const
boost::shared_ptr< ExportStatus > get_export_status()
bool read_buffer(const std::string &)
Definition: xml++.cc:125
#define invalidator(x)
Definition: gui_thread.h:40
Gtk::Button invid_browse_button
Definition: xml++.h:55
uint32_t disc_number() const
boost::shared_ptr< AudioPort > audio(uint32_t n) const
Definition: io.cc:1430
boost::shared_ptr< ExportHandler > get_export_handler()
sigc::connection audio_progress_connection
#define _(Text)
Definition: i18n.h:11
PBD::Signal2< void, ARDOUR::framecnt_t, ARDOUR::framecnt_t > Progress
volatile bool running
Definition: export_status.h:42
std::string get_path(ExportFormatSpecPtr format) const
const ChanCount & n_ports() const
Definition: io.h:135
#define X_(Text)
Definition: i18n.h:13
int64_t framecnt_t
Definition: types.h:76
XMLProperty * property(const char *)
Definition: xml++.cc:413
bool aborted() const
Definition: export_status.h:45
bool confirm_video_outfn(std::string, std::string docroot="")
VideoTimeLine * video_timeline
Definition: ardour_ui.h:236
std::map< std::string, std::string > FFSettings
Gtk::CheckButton meta_checkbox
Gtk::ComboBoxText audio_bitrate_combo
std::string composer() const
std::string title() const
TranscodeFfmpeg * _transcoder
void set_leadinout(double lead_in, double lead_out)
XMLNode * root() const
Definition: xml++.h:62
Definition: amp.h:29
boost::shared_ptr< Route > master_out() const
Definition: session.h:718
void set_fps(double fps)
#define gui_context()
Definition: gui_thread.h:36
void add_port(boost::weak_ptr< AudioPort > port)
void change_file_extension(std::string)
common functions used for video-file im/export
std::string album_artist() const
Gtk::CheckButton optimizations_checkbox
int64_t framepos_t
Definition: types.h:66
Gtk::CheckButton normalize_checkbox
int64_t frameoffset_t
Definition: types.h:71
volatile uint32_t total_normalize_cycles
Definition: export_status.h:68
static SessionMetadata * Metadata()
void set_timespan(ExportTimespanPtr ts)
Gtk::CheckButton deinterlace_checkbox
Gtk::ComboBoxText preset_combo
XMLProperty * add_property(const char *name, const std::string &value)
void register_channel(ExportChannelPtr channel)
const std::string export_path() const
Gtk::ComboBoxText audio_samplerate_combo
Gtk::CheckButton scale_checkbox
ARDOUR::framepos_t start()
ARDOUR::framepos_t length()
Gtk::ComboBoxText audio_codec_combo
framepos_t current_end_frame() const
Definition: session.cc:5048
void set_debug(bool onoff)
framepos_t current_start_frame() const
Definition: session.cc:5042
Definition: xml++.h:95
std::string album() const
Gtk::ComboBoxText video_codec_combo
Gtk::Label optimizations_label
void set_avoffset(double av_offset)
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
Definition: stateful.cc:77
Definition: debug.h:30
void set_state(const XMLNode &)
ARDOUR::framecnt_t get_duration()
ExportFilenamePtr add_filename()
std::string artist() const
PBD::Signal0< void > Finished
boost::shared_ptr< IO > output() const
Definition: route.h:90
std::string copyright() const
const SessionDirectory & session_directory() const
Definition: session.h:182
void add_extra_xml(XMLNode &)
Definition: stateful.cc:66
std::string subtitle() const
Gtk::SpinButton width_spinner
std::string get_file_extension(const std::string infile)
volatile uint32_t current_normalize_cycle
Definition: export_status.h:69
void apply_state(TimeSelection &tme, bool range)
volatile bool normalizing
Definition: export_status.h:56
ARDOUR::Session * _session
FFSettings default_meta_data()
void set_label(std::string value)
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
ExportFormatSpecPtr add_format()
double atof(const string &s)
Definition: convert.cc:158
Definition: io.h:67
ARDOUR::framecnt_t get_duration()
Gtk::ComboBoxText insnd_combo
void popup_error(const std::string &text)
Definition: gtk_ui.cc:665