From 0b5e502546b59f79a3ace3f40d857fb27411ae16 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Mon, 7 Feb 2022 22:46:23 +0100 Subject: [PATCH] Video import/export overhaul and ffmpeg-5.0 compat * Update commandline parameters for ffmpeg 5.0 * Simplify video-export, allow only standard settings * Check ffmpeg exit code and parse errors * Fix SessionhandleRef on audio-import (clear import status) * Cleanup and reformat sourcecode --- gtk2_ardour/editor_videotimeline.cc | 5 +- gtk2_ardour/export_video_dialog.cc | 1232 +++++++------------------ gtk2_ardour/export_video_dialog.h | 99 +- gtk2_ardour/transcode_ffmpeg.cc | 629 +++++++------ gtk2_ardour/transcode_ffmpeg.h | 255 ++--- gtk2_ardour/transcode_video_dialog.cc | 463 +++++----- gtk2_ardour/transcode_video_dialog.h | 73 +- 7 files changed, 1126 insertions(+), 1630 deletions(-) diff --git a/gtk2_ardour/editor_videotimeline.cc b/gtk2_ardour/editor_videotimeline.cc index 2b24c06493..36dd5d338c 100644 --- a/gtk2_ardour/editor_videotimeline.cc +++ b/gtk2_ardour/editor_videotimeline.cc @@ -99,7 +99,8 @@ Editor::embed_audio_from_video (std::string path, samplepos_t n, bool lock_posit std::string const& gid = ARDOUR::Playlist::generate_pgroup_id (); Temporal::timepos_t pos (n); - bool ok = (import_sndfiles (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, pos, 1, 1, track, gid, false) == 0); + bool ok = import_sndfiles (paths, Editing::ImportDistinctFiles, Editing::ImportAsTrack, ARDOUR::SrcBest, pos, 1, 1, track, gid, false) == 0; + import_status.clear(); if (ok && track) { if (lock_position_to_video) { @@ -110,5 +111,5 @@ Editor::embed_audio_from_video (std::string path, samplepos_t n, bool lock_posit } import_status.all_done = true; - ::g_unlink(path.c_str()); + ::g_unlink (path.c_str()); } diff --git a/gtk2_ardour/export_video_dialog.cc b/gtk2_ardour/export_video_dialog.cc index bce5cc8536..1233d8dcdb 100644 --- a/gtk2_ardour/export_video_dialog.cc +++ b/gtk2_ardour/export_video_dialog.cc @@ -20,47 +20,37 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include -#include -#include #include - -#include -#include -#include -#include +#include +#include #include #include +#include #include #include -#include "pbd/gstdio_compat.h" - -#include "pbd/error.h" #include "pbd/convert.h" -#include "gtkmm2ext/keyboard.h" -#include "gtkmm2ext/utils.h" -#include "ardour/session_directory.h" -#include "ardour/profile.h" -#include "ardour/template_utils.h" +#include "pbd/error.h" + #include "ardour/session.h" +#include "ardour/session_directory.h" + #include "ardour_ui.h" #include "gui_thread.h" -#include "ardour/export_handler.h" -#include "ardour/export_status.h" -#include "ardour/export_timespan.h" #include "ardour/export_channel_configuration.h" -#include "ardour/export_format_specification.h" #include "ardour/export_filename.h" -#include "ardour/route.h" +#include "ardour/export_format_specification.h" +#include "ardour/export_handler.h" +#include "ardour/export_timespan.h" #include "ardour/session_metadata.h" -#include "ardour/broadcast_info.h" -#include "opts.h" +#include "ardour_message.h" #include "export_video_dialog.h" #include "utils_videotl.h" + #include "pbd/i18n.h" using namespace Gtk; @@ -71,14 +61,10 @@ using namespace VideoUtils; ExportVideoDialog::ExportVideoDialog () : ArdourDialog (_("Export Video File ")) - , _aborted(false) - , _twopass(false) - , _firstpass(false) - , _normalize(false) - , _previous_progress(0) - , _transcoder(0) - , _video_source_aspect_ratio(-1) - , _suspend_signals(false) + , _aborted (false) + , _normalize (false) + , _previous_progress (0) + , _transcoder (0) , outfn_path_label (_("File:"), Gtk::ALIGN_LEFT) , outfn_browse_button (_("Browse")) , invid_path_label (_("Video:"), Gtk::ALIGN_LEFT) @@ -86,24 +72,9 @@ ExportVideoDialog::ExportVideoDialog () , transcode_button (_("Export")) , abort_button (_("Abort")) , progress_box (0) - , scale_checkbox (_("Scale Video (W x H):")) - , scale_aspect (_("Retain Aspect")) - , width_adjustment (768, 128, 1920, 1, 16, 0) - , width_spinner (width_adjustment) - , height_adjustment (576, 128, 1920, 1, 16, 0) - , height_spinner (height_adjustment) - , aspect_checkbox (_("Set Aspect Ratio:")) , normalize_checkbox (_("Normalize Audio")) - , twopass_checkbox (_("2 Pass Encoding")) - , optimizations_checkbox (_("Codec Optimizations:")) - , optimizations_label ("-") - , deinterlace_checkbox (_("Deinterlace")) - , bframes_checkbox (_("Use [2] B-frames (MPEG 2 or 4 only)")) - , fps_checkbox (_("Override FPS (Default is to retain FPS from the input video file):")) , meta_checkbox (_("Include Session Metadata")) -#if 1 /* tentative debug mode */ , debug_checkbox (_("Debug Mode: Print ffmpeg command and output to stdout.")) -#endif { set_name ("ExportVideoDialog"); set_modal (true); @@ -112,278 +83,161 @@ ExportVideoDialog::ExportVideoDialog () Gtk::Label* l; vbox = manage (new VBox); - VBox* options_box = manage (new VBox); HBox* path_hbox; /* check if ffmpeg can be found */ - _transcoder = new TranscodeFfmpeg(X_("")); - if (!_transcoder->ffexec_ok()) { + _transcoder = new TranscodeFfmpeg (X_("")); + if (!_transcoder->ffexec_ok ()) { l = manage (new Label (_("ffmpeg installation was not found. Video Export is not possible. See the Log window for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - l->set_line_wrap(); + l->set_line_wrap (); vbox->pack_start (*l, false, false, 8); - get_vbox()->pack_start (*vbox, false, false); + get_vbox ()->pack_start (*vbox, false, false); add_button (Stock::OK, RESPONSE_CANCEL); show_all_children (); - delete _transcoder; _transcoder = 0; + delete _transcoder; + _transcoder = 0; return; } - delete _transcoder; _transcoder = 0; + delete _transcoder; + _transcoder = 0; - l = manage (new Label (_("Output: (file extension defines format)"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - l->set_use_markup (); - vbox->pack_start (*l, false, false, 4); + Gtk::Frame* f; + Table* t; + f = manage (new Gtk::Frame (_("Output (file extension defines format)"))); path_hbox = manage (new HBox); path_hbox->pack_start (outfn_path_label, false, false, 3); path_hbox->pack_start (outfn_path_entry, true, true, 3); path_hbox->pack_start (outfn_browse_button, false, false, 3); - vbox->pack_start (*path_hbox, false, false, 2); + f->add (*path_hbox); + path_hbox->set_border_width (2); + vbox->pack_start (*f, false, false, 4); - l = manage (new Label (_("Input Video:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - l->set_use_markup (); - vbox->pack_start (*l, false, false, 4); - - path_hbox = manage (new HBox); + f = manage (new Gtk::Frame (_("Input"))); + VBox* input_box = manage (new VBox); + path_hbox = manage (new HBox); path_hbox->pack_start (invid_path_label, false, false, 3); path_hbox->pack_start (invid_path_entry, true, true, 3); path_hbox->pack_start (invid_browse_button, false, false, 3); - vbox->pack_start (*path_hbox, false, false, 2); + input_box->pack_start (*path_hbox, false, false, 2); path_hbox = manage (new HBox); - l = manage (new Label (_("Audio:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Audio:"), ALIGN_LEFT, ALIGN_CENTER, false)); path_hbox->pack_start (*l, false, false, 3); - l = manage (new Label (_("Master Bus"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (_("Master Bus"), ALIGN_LEFT, ALIGN_CENTER, false)); path_hbox->pack_start (*l, false, false, 2); - vbox->pack_start (*path_hbox, false, false, 2); + input_box->pack_start (*path_hbox, false, false, 2); - outfn_path_entry.set_width_chars(38); + input_box->set_border_width (2); + f->add (*input_box); + vbox->pack_start (*f, false, false, 4); - l = manage (new Label (_("Settings:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - l->set_use_markup (); - options_box->pack_start (*l, false, true, 4); + outfn_path_entry.set_width_chars (38); - Table* t = manage (new Table (4, 12)); + f = manage (new Gtk::Frame (_("Settings"))); + t = manage (new Table (3, 2)); + t->set_border_width (2); t->set_spacings (4); int ty = 0; - options_box->pack_start (*t, true, true, 4); - l = manage (new Label (_("Range:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, ty, ty+1); - t->attach (insnd_combo, 1, 4, ty, ty+1); ty++; - l = manage (new Label (_("Preset:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, ty, ty+1); - t->attach (preset_combo, 1, 4, ty, ty+1); ty++; - l = manage (new Label (_("Video Codec:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, ty, ty+1); - t->attach (video_codec_combo, 1, 2, ty, ty+1); - l = manage (new Label (_("Video KBit/s:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 2, 3, ty, ty+1); - t->attach (video_bitrate_combo, 3, 4, ty, ty+1); ty++; - l = manage (new Label (_("Audio Codec:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, ty, ty+1); - t->attach (audio_codec_combo, 1, 2, ty, ty+1); - l = manage (new Label (_("Audio KBit/s:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 2, 3, ty, ty+1); - t->attach (audio_bitrate_combo, 3, 4, ty, ty+1); ty++; - l = manage (new Label (_("Audio Samplerate:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - t->attach (*l, 0, 1, ty, ty+1); - t->attach (audio_samplerate_combo, 1, 2, ty, ty+1); - t->attach (normalize_checkbox, 2, 4, ty, ty+1); ty++; - t->attach (scale_checkbox, 0, 1, ty, ty+1); - t->attach (scale_aspect, 1, 2, ty, ty+1); - t->attach (width_spinner, 2, 3, ty, ty+1); - t->attach (height_spinner, 3, 4, ty, ty+1); ty++; - t->attach (fps_checkbox, 0, 3, ty, ty+1); - t->attach (fps_combo, 3, 4, ty, ty+1); ty++; - t->attach (twopass_checkbox, 0, 2, ty, ty+1); - t->attach (aspect_checkbox, 2, 3, ty, ty+1); - t->attach (aspect_combo, 3, 4, ty, ty+1); ty++; - t->attach (bframes_checkbox, 0, 2, ty, ty+1); - t->attach (deinterlace_checkbox, 2, 4, ty, ty+1); ty++; - t->attach (meta_checkbox, 2, 4, ty, ty+1); ty++; - t->attach (optimizations_checkbox, 0, 1, ty, ty+1); - t->attach (optimizations_label, 1, 4, ty, ty+1); ty++; -#if 1 /* tentative debug mode */ - t->attach (debug_checkbox, 0, 4, ty, ty+1); ty++; -#endif + l = manage (new Label (_("Range:"), ALIGN_LEFT, ALIGN_CENTER, false)); + t->attach (*l, 0, 1, ty, ty + 1); + t->attach (insnd_combo, 1, 2, ty, ty + 1); + ty++; - preset_combo.append_text("none"); - preset_combo.append_text("dvd-mp2"); - preset_combo.append_text("dvd-NTSC"); - preset_combo.append_text("dvd-PAL"); - preset_combo.append_text("flv"); - preset_combo.append_text("mpeg4"); - preset_combo.append_text("mp4/h264/aac"); - preset_combo.append_text("ogg"); - preset_combo.append_text("webm"); - preset_combo.append_text("you-tube"); + t->attach (normalize_checkbox, 0, 2, ty, ty + 1); + ty++; + t->attach (meta_checkbox, 0, 2, ty, ty + 1); + ty++; + t->attach (debug_checkbox, 0, 2, ty, ty + 1); + ty++; - audio_codec_combo.append_text(_("(default for format)")); - audio_codec_combo.append_text("ac3"); - audio_codec_combo.append_text("aac"); - audio_codec_combo.append_text("libmp3lame"); - audio_codec_combo.append_text("libvorbis"); - audio_codec_combo.append_text("mp2"); - audio_codec_combo.append_text("pcm_s16le"); + f->add (*t); + vbox->pack_start (*f, false, true, 4); - video_codec_combo.append_text(_("(default for format)")); - video_codec_combo.append_text("flv"); - video_codec_combo.append_text("libtheora"); - video_codec_combo.append_text("mjpeg"); - video_codec_combo.append_text("mpeg2video"); - video_codec_combo.append_text("mpeg4"); - video_codec_combo.append_text("h264"); - video_codec_combo.append_text("vpx (webm)"); - video_codec_combo.append_text("copy"); - - audio_bitrate_combo.append_text(_("(default)")); - audio_bitrate_combo.append_text("64k"); - audio_bitrate_combo.append_text("128k"); - audio_bitrate_combo.append_text("192k"); - audio_bitrate_combo.append_text("256k"); - audio_bitrate_combo.append_text("320k"); - - audio_samplerate_combo.append_text("22050"); - audio_samplerate_combo.append_text("44100"); - audio_samplerate_combo.append_text("48000"); - - video_bitrate_combo.append_text(_("(default)")); - video_bitrate_combo.append_text(_("(retain)")); - video_bitrate_combo.append_text("200k"); - video_bitrate_combo.append_text("800k"); - video_bitrate_combo.append_text("2000k"); - video_bitrate_combo.append_text("5000k"); - video_bitrate_combo.append_text("8000k"); - - fps_combo.append_text("23.976"); - fps_combo.append_text("24"); - fps_combo.append_text("24.976"); - fps_combo.append_text("25"); - fps_combo.append_text("29.97"); - fps_combo.append_text("30"); - fps_combo.append_text("59.94"); - fps_combo.append_text("60"); - - aspect_combo.append_text("4:3"); - aspect_combo.append_text("16:9"); - - vbox->pack_start (*options_box, false, true, 4); - get_vbox()->set_spacing (4); - get_vbox()->pack_start (*vbox, false, false); + get_vbox ()->set_spacing (4); + get_vbox ()->pack_start (*vbox, false, false); progress_box = manage (new VBox); progress_box->pack_start (pbar, false, false); progress_box->pack_start (abort_button, false, false); - get_vbox()->pack_start (*progress_box, false, false); + get_vbox ()->pack_start (*progress_box, false, false); - scale_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::scale_checkbox_toggled)); - aspect_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::aspect_checkbox_toggled)); - fps_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &ExportVideoDialog::fps_checkbox_toggled)); - preset_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::preset_combo_changed)); - video_codec_combo.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::video_codec_combo_changed)); - outfn_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_outfn_dialog)); - invid_browse_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_invid_dialog)); - transcode_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::launch_export)); - abort_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportVideoDialog::abort_clicked)); + outfn_browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_outfn_dialog)); + invid_browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &ExportVideoDialog::open_invid_dialog)); + transcode_button.signal_clicked ().connect (sigc::mem_fun (*this, &ExportVideoDialog::launch_export)); + abort_button.signal_clicked ().connect (sigc::mem_fun (*this, &ExportVideoDialog::abort_clicked)); - invid_path_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::set_original_file_information)); - width_spinner.signal_value_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::width_value_changed)); - height_spinner.signal_value_changed().connect (sigc::mem_fun (*this, &ExportVideoDialog::height_value_changed)); + invid_path_entry.signal_changed ().connect (sigc::mem_fun (*this, &ExportVideoDialog::set_original_file_information)); cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL); - get_action_area()->pack_start (transcode_button, false, false); + get_action_area ()->pack_start (transcode_button, false, false); show_all_children (); - progress_box->set_no_show_all(); - progress_box->hide(); + progress_box->set_no_show_all (); + progress_box->hide (); } ExportVideoDialog::~ExportVideoDialog () { - if (_transcoder) { delete _transcoder; _transcoder = 0;} + if (_transcoder) { + delete _transcoder; + _transcoder = 0; + } } void -ExportVideoDialog::set_original_file_information() +ExportVideoDialog::set_original_file_information () { - assert(_transcoder == 0); - std::string infile = invid_path_entry.get_text(); + assert (_transcoder == 0); + string infile = invid_path_entry.get_text (); - if (scale_checkbox.get_active()) { - // user may have set custom values already, don't touch. - return; - } - if (infile == "" || !Glib::file_test(infile, Glib::FILE_TEST_EXISTS)) { + if (infile.empty () || !Glib::file_test (infile, Glib::FILE_TEST_EXISTS)) { + transcode_button.set_sensitive (false); return; } - _transcoder = new TranscodeFfmpeg(infile); - if (_transcoder->probe_ok()) { - _video_source_aspect_ratio = -1; - width_spinner.set_value(_transcoder->get_width()); - height_spinner.set_value(_transcoder->get_height()); - _video_source_aspect_ratio = _transcoder->get_aspect(); - } - - delete _transcoder; _transcoder = 0; + _transcoder = new TranscodeFfmpeg (infile); + transcode_button.set_sensitive (_transcoder->probe_ok ()); + delete _transcoder; + _transcoder = 0; } + void -ExportVideoDialog::apply_state (TimeSelection &tme, bool range) +ExportVideoDialog::apply_state (TimeSelection& tme, bool range) { - _suspend_dirty = true; // TODO really just queue 'dirty' and mark session dirty on "Export" + _export_range = tme; - export_range = tme; - _video_source_aspect_ratio = -1; - - outfn_path_entry.set_text (_session->session_directory().export_path() + G_DIR_SEPARATOR +"export.avi"); + outfn_path_entry.set_text (_session->session_directory ().export_path () + G_DIR_SEPARATOR + "export.mp4"); // TODO remember setting for export-range.. somehow, (let explicit range override) - sampleoffset_t av_offset = ARDOUR_UI::instance()->video_timeline->get_offset(); + sampleoffset_t av_offset = ARDOUR_UI::instance ()->video_timeline->get_offset (); insnd_combo.remove_all (); - insnd_combo.append_text (_("from session start marker to session end marker")); - if (av_offset < 0 ) { + if (av_offset < 0) { insnd_combo.append_text (_("from 00:00:00:00 to the video end")); } else { insnd_combo.append_text (_("from video start to video end")); } - if (!export_range.empty()) { - insnd_combo.append_text (_("Selected range")); // TODO show export_range.start() -> export_range.end_sample() + if (!_export_range.empty ()) { + insnd_combo.append_text (_("Selected range")); // TODO show _export_range.start() -> _export_range.end_sample() } if (range) { - insnd_combo.set_active(2); + insnd_combo.set_active (2); } else { - insnd_combo.set_active(0); + insnd_combo.set_active (0); } - preset_combo.set_active(0); - audio_codec_combo.set_active(0); - video_codec_combo.set_active(0); - audio_bitrate_combo.set_active(0); - audio_samplerate_combo.set_active(2); - video_bitrate_combo.set_active(0); - aspect_combo.set_active(1); + normalize_checkbox.set_active (false); + meta_checkbox.set_active (false); - scale_checkbox.set_active(false); - scale_aspect.set_active(true); - aspect_checkbox.set_active(false); - normalize_checkbox.set_active(false); - twopass_checkbox.set_active(false); - optimizations_checkbox.set_active(false); - deinterlace_checkbox.set_active(false); - bframes_checkbox.set_active(false); - fps_checkbox.set_active(false); - meta_checkbox.set_active(false); - - float tcfps = _session->timecode_frames_per_second(); - - XMLNode* node = _session->extra_xml (X_("Videotimeline")); - bool filenameset = false; + XMLNode* node = _session->extra_xml (X_("Videotimeline")); + bool filenameset = false; if (node) { - std::string filename; - if (node->get_property(X_("OriginalVideoFile"), filename)) { - if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) { + string filename; + if (node->get_property (X_("OriginalVideoFile"), filename)) { + if (Glib::file_test (filename, Glib::FILE_TEST_EXISTS)) { invid_path_entry.set_text (filename); filenameset = true; } @@ -393,120 +247,37 @@ ExportVideoDialog::apply_state (TimeSelection &tme, bool range) if (!filenameset && node->get_property (X_("Filename"), filename) && node->get_property (X_("LocalFile"), local_file) && local_file) { - if (filename.at(0) != G_DIR_SEPARATOR) - { - filename = Glib::build_filename (_session->session_directory().video_path(), filename); + if (filename.at (0) != G_DIR_SEPARATOR) { + filename = Glib::build_filename (_session->session_directory ().video_path (), filename); } - if (Glib::file_test(filename, Glib::FILE_TEST_EXISTS)) - { + if (Glib::file_test (filename, Glib::FILE_TEST_EXISTS)) { invid_path_entry.set_text (filename); filenameset = true; } } } + if (!filenameset) { invid_path_entry.set_text (X_("")); } node = _session->extra_xml (X_("Videoexport")); if (node) { - bool yn; - if (node->get_property (X_("ChangeGeometry"), yn)) { - scale_checkbox.set_active (yn); - } - if (node->get_property (X_("KeepAspect"), yn)) { - scale_aspect.set_active (yn); - } - if (node->get_property (X_("ChangeAspect"), yn)) { - aspect_checkbox.set_active (yn); - } + bool yn; + string str; if (node->get_property (X_("NormalizeAudio"), yn)) { normalize_checkbox.set_active (yn); } - if (node->get_property (X_("TwoPassEncode"), yn)) { - twopass_checkbox.set_active (yn); - } - if (node->get_property (X_("CodecOptimzations"), yn)) { - optimizations_checkbox.set_active (yn); - } - if (node->get_property (X_("Deinterlace"), yn)) { - deinterlace_checkbox.set_active (yn); - } - if (node->get_property (X_("BSamples"), yn)) { - bframes_checkbox.set_active (yn); - } - if (node->get_property (X_("ChangeFPS"), yn)) { - fps_checkbox.set_active (yn); - } if (node->get_property (X_("Metadata"), yn)) { meta_checkbox.set_active (yn); } - - std::string str; - if (node->get_property (X_("Format"), str) && !str.empty()) { - change_file_extension ("." + str); - } - - _suspend_signals = true; - double val; - if (node->get_property (X_("Width"), val)) { - width_spinner.set_value (val); - } - if (node->get_property (X_("Height"), val)) { - height_spinner.set_value (val); - } - _suspend_signals = false; - - if (fps_checkbox.get_active () && node->get_property (X_("FPS"), val)) { - tcfps = val; - } - - if (node->get_property (X_("Preset"), str)) { - preset_combo.set_active_text (str); - } - if (node->get_property (X_("VCodec"), str)) { - video_codec_combo.set_active_text (str); - } - if (node->get_property (X_("ACodec"), str)) { - audio_codec_combo.set_active_text (str); - } - if (node->get_property (X_("VBitrate"), str)) { - video_bitrate_combo.set_active_text (str); - } - if (node->get_property (X_("ABitrate"), str)) { - audio_bitrate_combo.set_active_text (str); - } - if (node->get_property (X_("AspectRatio"), str)) { - aspect_combo.set_active_text (str); - } - if (node->get_property (X_("SampleRate"), str)) { - audio_samplerate_combo.set_active_text (str); - } } - if (fabs(tcfps - 23.976) < 0.01) { fps_combo.set_active(0); } - else if (fabs(tcfps - 24.0 ) < 0.01) { fps_combo.set_active(1); } - else if (fabs(tcfps - 24.976) < 0.01) { fps_combo.set_active(2); } - else if (fabs(tcfps - 25.0 ) < 0.01) { fps_combo.set_active(3); } - else if (fabs(tcfps - 29.97 ) < 0.01) { fps_combo.set_active(4); } - else if (fabs(tcfps - 30.0 ) < 0.01) { fps_combo.set_active(5); } - else if (fabs(tcfps - 59.94 ) < 0.01) { fps_combo.set_active(6); } - else if (fabs(tcfps - 60.0 ) < 0.01) { fps_combo.set_active(7); } - else { fps_combo.set_active(5); } - - set_original_file_information(); - - /* update sensitivity */ - scale_checkbox_toggled(); - aspect_checkbox_toggled(); - fps_checkbox_toggled(); - video_codec_combo_changed(); - - _suspend_dirty = false; + set_original_file_information (); show_all_children (); if (progress_box) { - progress_box->hide(); + progress_box->hide (); } } @@ -514,51 +285,22 @@ XMLNode& ExportVideoDialog::get_state () { XMLNode* node = new XMLNode (X_("Videoexport")); - node->set_property (X_("ChangeGeometry"), scale_checkbox.get_active()); - node->set_property (X_("KeepAspect"), scale_aspect.get_active()); - node->set_property (X_("ChangeAspect"), aspect_checkbox.get_active()); - node->set_property (X_("NormalizeAudio"), normalize_checkbox.get_active()); - node->set_property (X_("TwoPassEncode"), twopass_checkbox.get_active()); - node->set_property (X_("CodecOptimzations"), optimizations_checkbox.get_active()); - node->set_property (X_("Deinterlace"), deinterlace_checkbox.get_active()); - node->set_property (X_("BSamples"), bframes_checkbox.get_active()); - node->set_property (X_("ChangeFPS"), fps_checkbox.get_active()); - node->set_property (X_("Metadata"), meta_checkbox.get_active()); - - node->set_property (X_("Format"), get_file_extension(outfn_path_entry.get_text())); - - node->set_property (X_("Width"), width_spinner.get_value()); - node->set_property (X_("Height"), height_spinner.get_value()); - - node->set_property (X_("Preset"), preset_combo.get_active_text()); - node->set_property (X_("VCodec"), video_codec_combo.get_active_text()); - node->set_property (X_("ACodec"), audio_codec_combo.get_active_text()); - node->set_property (X_("VBitrate"), video_bitrate_combo.get_active_text()); - node->set_property (X_("ABitrate"), audio_bitrate_combo.get_active_text()); - node->set_property (X_("AspectRatio"), aspect_combo.get_active_text()); - node->set_property (X_("SampleRate"), audio_samplerate_combo.get_active_text()); - node->set_property (X_("FPS"), fps_combo.get_active_text()); - + node->set_property (X_("NormalizeAudio"), normalize_checkbox.get_active ()); + node->set_property (X_("Metadata"), meta_checkbox.get_active ()); return *node; } void -ExportVideoDialog::set_state (const XMLNode &) +ExportVideoDialog::set_state (const XMLNode&) { } -void -ExportVideoDialog::on_show () -{ - Dialog::on_show (); -} - void ExportVideoDialog::abort_clicked () { _aborted = true; if (_transcoder) { - _transcoder->cancel(); + _transcoder->cancel (); } } @@ -566,36 +308,35 @@ void ExportVideoDialog::update_progress (samplecnt_t c, samplecnt_t a) { if (a == 0 || c > a) { - pbar.set_pulse_step(.1); - pbar.pulse(); + pbar.set_pulse_step (.1); + pbar.pulse (); } else { - double progress = (double)c / (double) a; - progress = progress / ((_twopass ? 2.0 : 1.0) + (_normalize ? 2.0 : 1.0)); - if (_normalize && _twopass) progress += (_firstpass ? .5 : .75); - else if (_normalize) progress += 2.0/3.0; - else if (_twopass) progress += (_firstpass ? 1.0/3.0 : 2.0/3.0); - else progress += .5; - + double progress = (double)c / (double)a; + progress = progress / (_normalize ? 3.0 : 2.0); + if (_normalize) { + progress += 2.0 / 3.0; + } else { + progress += .5; + } pbar.set_fraction (progress); } } - gint ExportVideoDialog::audio_progress_display () { - std::string status_text; - double progress = -1.0; + string status_text; + double progress = -1.0; switch (status->active_job) { case ExportStatus::Normalizing: pbar.set_text (_("Normalizing audio")); - progress = ((float) status->current_postprocessing_cycle) / status->total_postprocessing_cycles; - progress = progress / (_twopass ? 4.0 : 3.0) + (_twopass ? .25 : 1.0 / 3.0); + progress = ((float)status->current_postprocessing_cycle) / status->total_postprocessing_cycles; + progress = (progress + 1.0) / 3.0; break; case ExportStatus::Exporting: pbar.set_text (_("Exporting audio")); - progress = ((float) status->processed_samples_current_timespan) / status->total_samples_current_timespan; - progress = progress / ((_twopass ? 2.0 : 1.0) + (_normalize ? 2.0 : 1.0)); + progress = ((float)status->processed_samples_current_timespan) / status->total_samples_current_timespan; + progress = progress / (_normalize ? 3.0 : 2.0); break; default: pbar.set_text (_("Exporting audio")); @@ -603,42 +344,39 @@ ExportVideoDialog::audio_progress_display () } if (progress < _previous_progress) { - // Work around gtk bug - pbar.hide(); - pbar.show(); + /* Work around gtk bug */ + pbar.hide (); + pbar.show (); } + _previous_progress = progress; if (progress >= 0) { pbar.set_fraction (progress); } else { - pbar.set_pulse_step(.1); - pbar.pulse(); + pbar.set_pulse_step (.1); + pbar.pulse (); } return TRUE; } void -ExportVideoDialog::finished () +ExportVideoDialog::finished (int status) { - if (_aborted) { - ::g_unlink(outfn_path_entry.get_text().c_str()); - ::g_unlink (_insnd.c_str()); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); - } else if (_twopass && _firstpass) { - _firstpass = false; - if (_transcoder) { delete _transcoder; _transcoder = 0;} - encode_pass(2); - } else { - if (twopass_checkbox.get_active()) { - std::string outfn = outfn_path_entry.get_text(); - std::string p2log = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass"; - ::g_unlink (p2log.c_str()); + delete _transcoder; + _transcoder = 0; + if (_aborted || status != 0) { + if (!_aborted) { + ARDOUR_UI::instance()->popup_error(_("Video transcoding failed.")); } - ::g_unlink (_insnd.c_str()); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_ACCEPT); + ::g_unlink (outfn_path_entry.get_text ().c_str ()); + ::g_unlink (_insnd.c_str ()); + Gtk::Dialog::response (RESPONSE_CANCEL); + } else { + if (!debug_checkbox.get_active ()) { + ::g_unlink (_insnd.c_str ()); + } + Gtk::Dialog::response (RESPONSE_ACCEPT); } } @@ -650,78 +388,84 @@ ExportVideoDialog::launch_export () * "Videotimeline" and "Video Export" extra XML * as well as current _session settings */ - _session->add_extra_xml (get_state()); + _session->add_extra_xml (get_state ()); - std::string outfn = outfn_path_entry.get_text(); - if (!confirm_video_outfn(*this, outfn)) { return; } + string outfn = outfn_path_entry.get_text (); + if (!confirm_video_outfn (*this, outfn)) { + return; + } - vbox->hide(); - cancel_button->hide(); - transcode_button.hide(); - pbar.set_size_request(300,-1); - pbar.set_text(_("Exporting Audio...")); - progress_box->show(); - _aborted = false; - _twopass = twopass_checkbox.get_active(); - _firstpass = true; - _normalize = normalize_checkbox.get_active(); + vbox->hide (); + cancel_button->hide (); + transcode_button.hide (); + pbar.set_size_request (300, -1); + pbar.set_text (_("Exporting Audio...")); + progress_box->show (); + _aborted = false; + _normalize = normalize_checkbox.get_active (); /* export audio track */ - ExportTimespanPtr tsp = _session->get_export_handler()->add_timespan(); - boost::shared_ptr ccp = _session->get_export_handler()->add_channel_config(); - boost::shared_ptr fnp = _session->get_export_handler()->add_filename(); + ExportTimespanPtr tsp = _session->get_export_handler ()->add_timespan (); + boost::shared_ptr ccp = _session->get_export_handler ()->add_channel_config (); + boost::shared_ptr fnp = _session->get_export_handler ()->add_filename (); boost::shared_ptr b; + XMLTree tree; - std::string vtl_samplerate = audio_samplerate_combo.get_active_text(); - std::string vtl_normalize = _normalize ? "true" : "false"; - tree.read_buffer(std::string ( -"" -"" -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -"" - ).c_str()); - boost::shared_ptr fmp = _session->get_export_handler()->add_format(*tree.root()); + string vtl_samplerate = "48000"; + string vtl_normalize = _normalize ? "true" : "false"; + + tree.read_buffer (std::string ( + "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "") + .c_str ()); + + boost::shared_ptr fmp = _session->get_export_handler ()->add_format (*tree.root ()); /* set up range */ samplepos_t start, end; start = end = 0; - if (insnd_combo.get_active_row_number() == 1) { - _transcoder = new TranscodeFfmpeg(invid_path_entry.get_text()); - if (_transcoder->probe_ok() && _transcoder->get_fps() > 0) { - end = _transcoder->get_duration() * _session->nominal_sample_rate() / _transcoder->get_fps(); + if (insnd_combo.get_active_row_number () == 1) { + _transcoder = new TranscodeFfmpeg (invid_path_entry.get_text ()); + if (_transcoder->probe_ok () && _transcoder->get_fps () > 0) { + end = _transcoder->get_duration () * _session->nominal_sample_rate () / _transcoder->get_fps (); } else { warning << _("Export Video: Cannot query duration of video-file, using duration from timeline instead.") << endmsg; - end = ARDOUR_UI::instance()->video_timeline->get_duration(); + end = ARDOUR_UI::instance ()->video_timeline->get_duration (); + } + if (_transcoder) { + delete _transcoder; + _transcoder = 0; } - if (_transcoder) {delete _transcoder; _transcoder = 0;} - sampleoffset_t av_offset = ARDOUR_UI::instance()->video_timeline->get_offset(); + sampleoffset_t av_offset = ARDOUR_UI::instance ()->video_timeline->get_offset (); #if 0 /* DEBUG */ printf("audio-range -- AV offset: %lld\n", av_offset); #endif @@ -729,26 +473,26 @@ ExportVideoDialog::launch_export () start = av_offset; } end += av_offset; - } - else if (insnd_combo.get_active_row_number() == 2) { - start = ARDOUR_UI::instance()->video_timeline->quantify_samples_to_apv(export_range.start_sample()); - end = ARDOUR_UI::instance()->video_timeline->quantify_samples_to_apv(export_range.end_sample()); + } else if (insnd_combo.get_active_row_number () == 2) { + start = ARDOUR_UI::instance ()->video_timeline->quantify_samples_to_apv (_export_range.start_sample ()); + end = ARDOUR_UI::instance ()->video_timeline->quantify_samples_to_apv (_export_range.end_sample ()); } if (end <= 0) { - start = _session->current_start_sample(); - end = _session->current_end_sample(); + start = _session->current_start_sample (); + end = _session->current_end_sample (); } #if 0 /* DEBUG */ printf("audio export-range %lld -> %lld\n", start, end); #endif - const sampleoffset_t vstart = ARDOUR_UI::instance()->video_timeline->get_offset(); - const sampleoffset_t vend = vstart + ARDOUR_UI::instance()->video_timeline->get_duration(); + const sampleoffset_t vstart = ARDOUR_UI::instance ()->video_timeline->get_offset (); + const sampleoffset_t vend = vstart + ARDOUR_UI::instance ()->video_timeline->get_duration (); - if ( (start >= end) || (end < vstart) || (start > vend)) { + if ((start >= end) || (end < vstart) || (start > vend)) { warning << _("Export Video: export-range does not include video.") << endmsg; - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } @@ -757,226 +501,123 @@ ExportVideoDialog::launch_export () tsp->set_range_id ("session"); /* add master outs as default */ - IO* master_out = _session->master_out()->output().get(); + IO* master_out = _session->master_out ()->output ().get (); if (!master_out) { warning << _("Export Video: No Master Out Ports to Connect for Audio Export") << endmsg; - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } - for (uint32_t n = 0; n < master_out->n_ports().n_audio(); ++n) { - PortExportChannel * channel = new PortExportChannel (); + for (uint32_t n = 0; n < master_out->n_ports ().n_audio (); ++n) { + PortExportChannel* channel = new PortExportChannel (); channel->add_port (master_out->audio (n)); ExportChannelPtr chan_ptr (channel); ccp->register_channel (chan_ptr); } /* outfile */ - fnp->set_timespan(tsp); - fnp->set_label("vtl"); + fnp->set_timespan (tsp); + fnp->set_label ("vtl"); fnp->include_label = true; - _insnd = fnp->get_path(fmp); + _insnd = fnp->get_path (fmp); /* do sound export */ - fmp->set_soundcloud_upload(false); - _session->get_export_handler()->reset (); - _session->get_export_handler()->add_export_config (tsp, ccp, fmp, fnp, b); - _session->get_export_handler()->do_export(); + fmp->set_soundcloud_upload (false); + _session->get_export_handler ()->reset (); + _session->get_export_handler ()->add_export_config (tsp, ccp, fmp, fnp, b); + _session->get_export_handler ()->do_export (); status = _session->get_export_status (); - audio_progress_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ExportVideoDialog::audio_progress_display), 100); - _previous_progress = 0.0; + _audio_progress_connection = Glib::signal_timeout ().connect (sigc::mem_fun (*this, &ExportVideoDialog::audio_progress_display), 100); + _previous_progress = 0.0; while (status->running ()) { - if (_aborted) { status->abort(); } - if (gtk_events_pending()) { + if (_aborted) { + status->abort (); + } + if (gtk_events_pending ()) { gtk_main_iteration (); } else { Glib::usleep (10000); } } - audio_progress_connection.disconnect(); + _audio_progress_connection.disconnect (); status->finish (TRS_UI); - if (status->aborted()) { - ::g_unlink (_insnd.c_str()); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + if (status->aborted ()) { + ::g_unlink (_insnd.c_str ()); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } pbar.set_text (_("Encoding Video...")); - encode_pass(1); + encode_video (); } void -ExportVideoDialog::encode_pass (int pass) +ExportVideoDialog::encode_video () { - std::string outfn = outfn_path_entry.get_text(); - std::string invid = invid_path_entry.get_text(); + std::string outfn = outfn_path_entry.get_text (); + std::string invid = invid_path_entry.get_text (); - _transcoder = new TranscodeFfmpeg(invid); - if (!_transcoder->ffexec_ok()) { + _transcoder = new TranscodeFfmpeg (invid); + if (!_transcoder->ffexec_ok ()) { /* ffmpeg binary was not found. TranscodeFfmpeg prints a warning */ - ::g_unlink (_insnd.c_str()); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + ::g_unlink (_insnd.c_str ()); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } - if (!_transcoder->probe_ok()) { + if (!_transcoder->probe_ok ()) { /* video input file can not be read */ warning << _("Export Video: Video input file cannot be read.") << endmsg; - ::g_unlink (_insnd.c_str()); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + ::g_unlink (_insnd.c_str ()); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } - std::string preset = preset_combo.get_active_text(); - TranscodeFfmpeg::FFSettings ffs ; /* = transcoder->default_encoder_settings(); */ - ffs.clear(); - - if (fps_checkbox.get_active()) { - ffs["-r"] = fps_combo.get_active_text(); - _transcoder->set_fps(atof(fps_combo.get_active_text())); - } - - if (scale_checkbox.get_active()) { - ffs["-s"] = string_compose("%1x%2", width_spinner.get_value(), height_spinner.get_value()); - } - - if (video_codec_combo.get_active_text() != _("(default for format)")) { - ffs["-vcodec"] = video_codec_combo.get_active_text(); - } - if (audio_codec_combo.get_active_text() != _("(default for format)")) { - ffs["-acodec"] = audio_codec_combo.get_active_text(); - } - - if (video_bitrate_combo.get_active_text() == _("(default)") ) { - ; - } - else if (video_bitrate_combo.get_active_text() == _("(retain)") ) { - ffs["-qscale"] = "0"; - } else { - ffs["-b:v"] = video_bitrate_combo.get_active_text(); - } - - if (audio_bitrate_combo.get_active_text() != _("(default)") ) { - ffs["-b:a"] = audio_bitrate_combo.get_active_text(); - } - - if (audio_codec_combo.get_active_text() == "aac" ) { - ffs["-strict"] = "-2"; - } - - if (video_codec_combo.get_active_text() == "h264" ) { - ffs["-vcodec"] = "libx264"; - } - else if (video_codec_combo.get_active_text() == "vpx (webm)" ) { - ffs["-vcodec"] = "libvpx"; - ffs["-g"] = "120"; - ffs["-qmin"] = "11"; - ffs["-qmax"] = "51"; - } - - if (optimizations_checkbox.get_active()) { - if (video_codec_combo.get_active_text() == "mpeg2video") { - ffs["-mbd"] = "rd"; - ffs["-trellis"] = "2"; - ffs["-cmp"] = "2"; - ffs["-subcmp"] = "2"; - } - else if (video_codec_combo.get_active_text() == "mpeg4") { - ffs["-mbd"] = "rd"; - ffs["-flags"] = "+mv4+aic"; - ffs["-trellis"] = "2"; - ffs["-cmp"] = "2"; - ffs["-subcmp"] = "2"; - ffs["-g"] = "300"; - } - else if (video_codec_combo.get_active_text() == "flv") { - ffs["-mbd"] = "2"; - ffs["-cmp"] = "2"; - ffs["-subcmp"] = "2"; - ffs["-trellis"] = "2"; - ffs["-flags"] = "+aic+mv0+mv4"; - ffs["-g"] = "160"; - } - } - - if (bframes_checkbox.get_active() && ( - video_codec_combo.get_active_text() == "mpeg2video" - || video_codec_combo.get_active_text() == "mpeg4" - )) { - ffs["-bf"] = "2"; - } - - if (preset == "dvd-PAL") { - ffs.clear(); /* ignore all prev settings */ - ffs["-target"] = "pal-dvd"; - ffs["-aspect"] = "4:3"; /* required for DVD - may be overridden below */ - } - else if (preset == "dvd-NTSC") { - ffs.clear(); /* ignore all prev settings */ - ffs["-target"] = "ntsc-dvd"; - ffs["-aspect"] = "4:3"; /* required for DVD - may be overridden below */ - } - - if (aspect_checkbox.get_active()) { - ffs["-aspect"] = aspect_combo.get_active_text(); - } - if (deinterlace_checkbox.get_active()) { - ffs["-deinterlace"] = "-y"; // we use '-y' as dummy parameter for non key/value options - } + TranscodeFfmpeg::FFSettings ffs; /* = transcoder->default_encoder_settings(); */ + ffs.clear (); bool map = true; - if (pass == 1 && _twopass) { - pbar.set_text (_("Encoding Video.. Pass 1/2")); - map = false; - ffs["-pass"] = "1"; - ffs["-an"] = "-y"; - ffs["-passlogfile"] = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass"; - ffs["-f"] = get_file_extension(invid).empty()?"mov":get_file_extension(invid); -#ifdef PLATFORM_WINDOWS - outfn = "NUL"; -#else - outfn = "/dev/null"; -#endif - } else if (pass == 2) { - pbar.set_text (_("Encoding Video.. Pass 2/2")); - ffs["-pass"] = "2"; - ffs["-passlogfile"] = Glib::path_get_dirname (outfn) + G_DIR_SEPARATOR + "ffmpeg2pass"; - } - sampleoffset_t av_offset = ARDOUR_UI::instance()->video_timeline->get_offset(); - double duration_s = 0; + sampleoffset_t av_offset = ARDOUR_UI::instance ()->video_timeline->get_offset (); + double duration_s = 0; - if (insnd_combo.get_active_row_number() == 0) { + if (insnd_combo.get_active_row_number () == 0) { /* session start to session end */ - samplecnt_t duration_f = _session->current_end_sample() - _session->current_start_sample(); - duration_s = (double)duration_f / (double)_session->nominal_sample_rate(); - } else if (insnd_combo.get_active_row_number() == 2) { + samplecnt_t duration_f = _session->current_end_sample () - _session->current_start_sample (); + duration_s = (double)duration_f / (double)_session->nominal_sample_rate (); + } else if (insnd_combo.get_active_row_number () == 2) { /* selected range */ - duration_s = export_range.length_samples() / (double)_session->nominal_sample_rate(); + duration_s = _export_range.length_samples () / (double)_session->nominal_sample_rate (); } else { /* video start to end */ - samplecnt_t duration_f = ARDOUR_UI::instance()->video_timeline->get_duration(); - if (av_offset < 0 ) { + samplecnt_t duration_f = ARDOUR_UI::instance ()->video_timeline->get_duration (); + if (av_offset < 0) { duration_f += av_offset; } - duration_s = (double)duration_f / (double)_session->nominal_sample_rate(); + duration_s = (double)duration_f / (double)_session->nominal_sample_rate (); } - std::ostringstream osstream; osstream << duration_s; - ffs["-t"] = osstream.str(); - _transcoder->set_duration(duration_s * _transcoder->get_fps()); + std::ostringstream osstream; + osstream << duration_s; + ffs["-t"] = osstream.str (); - if (insnd_combo.get_active_row_number() == 0 || insnd_combo.get_active_row_number() == 2) { - samplepos_t start, snend; - const sampleoffset_t vid_duration = ARDOUR_UI::instance()->video_timeline->get_duration(); - if (insnd_combo.get_active_row_number() == 0) { - start = _session->current_start_sample(); - snend = _session->current_end_sample(); + _transcoder->set_duration (duration_s * _transcoder->get_fps ()); + + if (insnd_combo.get_active_row_number () == 0 || insnd_combo.get_active_row_number () == 2) { + samplepos_t start, snend; + const sampleoffset_t vid_duration = ARDOUR_UI::instance ()->video_timeline->get_duration (); + if (insnd_combo.get_active_row_number () == 0) { + start = _session->current_start_sample (); + snend = _session->current_end_sample (); } else { - start = export_range.start_sample(); - snend = export_range.end_sample(); + start = _export_range.start_sample (); + snend = _export_range.end_sample (); } #if 0 /* DEBUG */ @@ -985,13 +626,13 @@ ExportVideoDialog::encode_pass (int pass) #endif if (av_offset > start && av_offset + vid_duration < snend) { - _transcoder->set_leadinout((av_offset - start) / (double)_session->nominal_sample_rate(), - (snend - (av_offset + vid_duration)) / (double)_session->nominal_sample_rate()); + _transcoder->set_leadinout ((av_offset - start) / (double)_session->nominal_sample_rate (), + (snend - (av_offset + vid_duration)) / (double)_session->nominal_sample_rate ()); } else if (av_offset > start) { - _transcoder->set_leadinout((av_offset - start) / (double)_session->nominal_sample_rate(), 0); + _transcoder->set_leadinout ((av_offset - start) / (double)_session->nominal_sample_rate (), 0); } else if (av_offset + vid_duration < snend) { - _transcoder->set_leadinout(0, (snend - (av_offset + vid_duration)) / (double)_session->nominal_sample_rate()); - _transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_sample_rate()); + _transcoder->set_leadinout (0, (snend - (av_offset + vid_duration)) / (double)_session->nominal_sample_rate ()); + _transcoder->set_avoffset ((av_offset - start) / (double)_session->nominal_sample_rate ()); } #if 0 else if (start > av_offset) { @@ -1000,300 +641,79 @@ ExportVideoDialog::encode_pass (int pass) } #endif else { - _transcoder->set_avoffset((av_offset - start) / (double)_session->nominal_sample_rate()); + _transcoder->set_avoffset ((av_offset - start) / (double)_session->nominal_sample_rate ()); } } else if (av_offset < 0) { /* from 00:00:00:00 to video-end */ - _transcoder->set_avoffset(av_offset / (double)_session->nominal_sample_rate()); + _transcoder->set_avoffset (av_offset / (double)_session->nominal_sample_rate ()); } /* NOTE: type (MetaDataMap) == type (FFSettings) == map */ - ARDOUR::SessionMetadata::MetaDataMap meta = _transcoder->default_meta_data(); - if (meta_checkbox.get_active()) { - ARDOUR::SessionMetadata * session_data = ARDOUR::SessionMetadata::Metadata(); + ARDOUR::SessionMetadata::MetaDataMap meta = _transcoder->default_meta_data (); + if (meta_checkbox.get_active ()) { + ARDOUR::SessionMetadata* session_data = ARDOUR::SessionMetadata::Metadata (); session_data->av_export_tag (meta); } -#if 1 /* tentative debug mode */ - if (debug_checkbox.get_active()) { - _transcoder->set_debug(true); + if (debug_checkbox.get_active ()) { + _transcoder->set_debug (true); } -#endif - _transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&ExportVideoDialog::update_progress , this, _1, _2), gui_context()); - _transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&ExportVideoDialog::finished, this), gui_context()); - if (!_transcoder->encode(outfn, _insnd, invid, ffs, meta, map)) { - ARDOUR_UI::instance()->popup_error(_("Transcoding failed.")); - delete _transcoder; _transcoder = 0; - Gtk::Dialog::response(RESPONSE_CANCEL); + _transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&ExportVideoDialog::update_progress, this, _1, _2), gui_context ()); + _transcoder->Finished.connect (*this, invalidator (*this), boost::bind (&ExportVideoDialog::finished, this, _1), gui_context ()); + + if (!_transcoder->encode (outfn, _insnd, invid, ffs, meta, map)) { + ARDOUR_UI::instance ()->popup_error (_("Transcoding failed.")); + delete _transcoder; + _transcoder = 0; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } } -void -ExportVideoDialog::change_file_extension (std::string ext) -{ - if (ext == "") return; - outfn_path_entry.set_text ( - strip_file_extension(outfn_path_entry.get_text()) + ext - ); -} - -void -ExportVideoDialog::width_value_changed () -{ - if (_suspend_signals) { - return; - } - if (_session && !_suspend_dirty) _session->set_dirty (); - if (!scale_checkbox.get_active() || !scale_aspect.get_active()) { - return; - } - if (_video_source_aspect_ratio <= 0) { - return; - } - _suspend_signals = true; - height_spinner.set_value(rintf(width_spinner.get_value() / _video_source_aspect_ratio)); - _suspend_signals = false; -} - -void -ExportVideoDialog::height_value_changed () -{ - if (_suspend_signals) { - return; - } - if (_session && !_suspend_dirty) _session->set_dirty (); - if (!scale_checkbox.get_active() || !scale_aspect.get_active()) { - return; - } - if (_video_source_aspect_ratio <= 0) { - return; - } - _suspend_signals = true; - width_spinner.set_value(rintf(height_spinner.get_value() * _video_source_aspect_ratio)); - _suspend_signals = false; -} - -void -ExportVideoDialog::scale_checkbox_toggled () -{ - scale_aspect.set_sensitive(scale_checkbox.get_active()); - width_spinner.set_sensitive(scale_checkbox.get_active()); - height_spinner.set_sensitive(scale_checkbox.get_active()); - if (_session && !_suspend_dirty) _session->set_dirty (); -} - -void -ExportVideoDialog::fps_checkbox_toggled () -{ - fps_combo.set_sensitive(fps_checkbox.get_active()); - if (_session && !_suspend_dirty) _session->set_dirty (); -} - -void -ExportVideoDialog::aspect_checkbox_toggled () -{ - aspect_combo.set_sensitive(aspect_checkbox.get_active()); - if (_session && !_suspend_dirty) _session->set_dirty (); -} - -void -ExportVideoDialog::video_codec_combo_changed () -{ - if (( video_codec_combo.get_active_text() == "mpeg4" - ||video_codec_combo.get_active_text() == "mpeg2video" - ) && !( - preset_combo.get_active_text() == "dvd-PAL" - ||preset_combo.get_active_text() == "dvd-NTSC" - )) { - bframes_checkbox.set_sensitive(true); - optimizations_checkbox.set_sensitive(true); - if (video_codec_combo.get_active_text() == "mpeg2video") { - optimizations_label.set_text("-mbd rd -trellis 2 -cmp 2 -subcmp 2"); // mpeg2 - } else if (video_codec_combo.get_active_text() == "mpeg4") { - optimizations_label.set_text("-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300"); // mpeg4 - } else { - optimizations_label.set_text("-mbd 2 -cmp 2 -subcmp 2 -trellis 2 -flags +aic+mv0+mv4 -g 160"); // flv - } - } else { - bframes_checkbox.set_sensitive(false); - bframes_checkbox.set_active(false); - optimizations_checkbox.set_sensitive(false); - optimizations_checkbox.set_active(false); - optimizations_label.set_text("-"); - } - if (_session && !_suspend_dirty) _session->set_dirty (); -} - -void -ExportVideoDialog::preset_combo_changed () -{ - std::string p = preset_combo.get_active_text(); - scale_checkbox.set_sensitive(true); - - if (p == "flv") { - change_file_extension(".flv"); - audio_codec_combo.set_active(2); - video_codec_combo.set_active(1); - audio_bitrate_combo.set_active(2); - video_bitrate_combo.set_active(3); - audio_samplerate_combo.set_active(1); - } - else if (p == "you-tube") { - change_file_extension(".avi"); - audio_codec_combo.set_active(3); - video_codec_combo.set_active(6); - audio_bitrate_combo.set_active(2); - video_bitrate_combo.set_active(4); - if (_session->nominal_sample_rate() == 48000 || _session->nominal_sample_rate() == 96000) { - audio_samplerate_combo.set_active(2); - } else { - audio_samplerate_combo.set_active(1); - } - } - else if (p == "ogg") { - change_file_extension(".ogv"); - audio_codec_combo.set_active(4); - video_codec_combo.set_active(2); - audio_bitrate_combo.set_active(3); - video_bitrate_combo.set_active(4); - if (_session->nominal_sample_rate() == 48000 || _session->nominal_sample_rate() == 96000) { - audio_samplerate_combo.set_active(2); - } else { - audio_samplerate_combo.set_active(1); - } - } - else if (p == "webm") { - change_file_extension(".webm"); - audio_codec_combo.set_active(4); - video_codec_combo.set_active(7); - audio_bitrate_combo.set_active(3); - video_bitrate_combo.set_active(4); - if (_session->nominal_sample_rate() == 48000 || _session->nominal_sample_rate() == 96000) { - audio_samplerate_combo.set_active(2); - } else { - audio_samplerate_combo.set_active(1); - } - } - else if (p == "dvd-mp2") { - change_file_extension(".mpg"); - audio_codec_combo.set_active(5); - video_codec_combo.set_active(4); - audio_bitrate_combo.set_active(4); - video_bitrate_combo.set_active(5); - audio_samplerate_combo.set_active(2); - } - else if (p == "dvd-NTSC" || p == "dvd-PAL") { - change_file_extension(".mpg"); - audio_codec_combo.set_active(6); - video_codec_combo.set_active(4); - audio_bitrate_combo.set_active(4); - video_bitrate_combo.set_active(5); - audio_samplerate_combo.set_active(2); - - scale_checkbox.set_active(false); - scale_checkbox.set_sensitive(false); - } - else if (p == "mpeg4") { - change_file_extension(".mp4"); - audio_codec_combo.set_active(1); - video_codec_combo.set_active(5); - audio_bitrate_combo.set_active(4); - video_bitrate_combo.set_active(5); - if (_session->nominal_sample_rate() == 48000 || _session->nominal_sample_rate() == 96000) { - audio_samplerate_combo.set_active(2); - } else { - audio_samplerate_combo.set_active(1); - } - } - else if (p == "mp4/h264/aac") { - change_file_extension(".mp4"); - audio_codec_combo.set_active(2); - video_codec_combo.set_active(6); - audio_bitrate_combo.set_active(0); - video_bitrate_combo.set_active(0); - if (_session->nominal_sample_rate() == 48000 || _session->nominal_sample_rate() == 96000) { - audio_samplerate_combo.set_active(2); - } else { - audio_samplerate_combo.set_active(1); - } - } - - if (p == "none") { - audio_codec_combo.set_sensitive(true); - video_codec_combo.set_sensitive(true); - audio_bitrate_combo.set_sensitive(true); - video_bitrate_combo.set_sensitive(true); - audio_samplerate_combo.set_sensitive(true); - } else { - audio_codec_combo.set_sensitive(false); - video_codec_combo.set_sensitive(false); - audio_bitrate_combo.set_sensitive(false); - video_bitrate_combo.set_sensitive(false); - audio_samplerate_combo.set_sensitive(false); - } - - Gtk::Table *t = (Gtk::Table*) preset_combo.get_parent(); - Gtk::Table_Helpers::TableList c = t->children(); - Gtk::Table_Helpers::TableList::iterator it; - if (p == "dvd-PAL" || p == "dvd-NTSC") { - for (it = c.begin(); it != c.end(); ++it) { - int row = it->get_top_attach(); - if (row == 2 || row == 3 || row== 5 || row== 6 || row == 9) { - it->get_widget()->hide(); - } - } - } else { - for (it = c.begin(); it != c.end(); ++it) { - int row = it->get_top_attach(); - if (row == 2 || row == 3 || row== 5 || row== 6 || row == 9) { - it->get_widget()->show(); - } - } - } - - video_codec_combo_changed(); -} - void ExportVideoDialog::open_outfn_dialog () { - Gtk::FileChooserDialog dialog(_("Save Exported Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE); + FileChooserDialog dialog (_("Save Exported Video File"), FILE_CHOOSER_ACTION_SAVE); Gtkmm2ext::add_volume_shortcuts (dialog); - dialog.set_filename (outfn_path_entry.get_text()); + dialog.set_filename (outfn_path_entry.get_text ()); - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL); + dialog.add_button (Stock::OK, RESPONSE_OK); - int result = dialog.run(); + int result = dialog.run (); - if (result == Gtk::RESPONSE_OK) { - std::string filename = dialog.get_filename(); + if (result == RESPONSE_OK) { + std::string filename = dialog.get_filename (); - if (filename.length()) { + if (filename.length ()) { outfn_path_entry.set_text (filename); } + std::string ext = get_file_extension (filename); + if (ext != "mp4" || ext != "mov" || ext != "mkv") { + dialog.hide (); + ArdourMessageDialog msg (_("The file extension defines the format and codec.\nPrefer to use .mp4, .mov or .mkv. Otherwise encoding may fail.")); + msg.run (); + } } } void ExportVideoDialog::open_invid_dialog () { - Gtk::FileChooserDialog dialog(_("Save Exported Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE); + FileChooserDialog dialog (_("Input Video File"), FILE_CHOOSER_ACTION_OPEN); Gtkmm2ext::add_volume_shortcuts (dialog); - dialog.set_filename (invid_path_entry.get_text()); + dialog.set_filename (invid_path_entry.get_text ()); - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL); + dialog.add_button (Stock::OK, RESPONSE_OK); - int result = dialog.run(); + int result = dialog.run (); - if (result == Gtk::RESPONSE_OK) { - std::string filename = dialog.get_filename(); - - if (filename.length()) { + if (result == RESPONSE_OK) { + std::string filename = dialog.get_filename (); + if (!filename.empty ()) { invid_path_entry.set_text (filename); } } diff --git a/gtk2_ardour/export_video_dialog.h b/gtk2_ardour/export_video_dialog.h index 1f1c605155..0686fe31d4 100644 --- a/gtk2_ardour/export_video_dialog.h +++ b/gtk2_ardour/export_video_dialog.h @@ -22,16 +22,16 @@ #include #include -#include #include +#include #include #include #include +#include "ardour/export_status.h" #include "ardour/types.h" -#include "ardour/template_utils.h" -#include "ardour_dialog.h" +#include "ardour_dialog.h" #include "time_selection.h" #include "transcode_ffmpeg.h" @@ -42,63 +42,46 @@ * video-encoder presets, progress dialogs and uses * \ref TranscodeFfmpeg to communicate with ffmpeg. */ -class ExportVideoDialog : public ArdourDialog , public PBD::ScopedConnectionList +class ExportVideoDialog : public ArdourDialog, public PBD::ScopedConnectionList { public: ExportVideoDialog (); ~ExportVideoDialog (); - std::string get_exported_filename () { return outfn_path_entry.get_text(); } - - void apply_state(TimeSelection &tme, bool range); - - XMLNode& get_state (); - void set_state (const XMLNode &); - - void on_response (int response_id) { - Gtk::Dialog::on_response (response_id); + std::string get_exported_filename () + { + return outfn_path_entry.get_text (); } -private: - TimeSelection export_range; + void apply_state (TimeSelection& tme, bool range); + + XMLNode& get_state (); + void set_state (const XMLNode&); + +private: - void on_show (); void abort_clicked (); void launch_export (); - void encode_pass (int); - void change_file_extension (std::string); - void width_value_changed (); - void height_value_changed (); + void encode_video (); + void finished (int); void set_original_file_information (); + void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t); + gint audio_progress_display (); void open_outfn_dialog (); void open_invid_dialog (); - void scale_checkbox_toggled (); - void preset_combo_changed (); - void video_codec_combo_changed (); - void aspect_checkbox_toggled (); - void fps_checkbox_toggled (); bool _aborted; - bool _twopass; - bool _firstpass; bool _normalize; - void finished (); - void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t); - boost::shared_ptr status; - sigc::connection audio_progress_connection; - gint audio_progress_display (); - float _previous_progress; - TranscodeFfmpeg *_transcoder; - std::string _insnd; - - float _video_source_aspect_ratio; - bool _suspend_signals; - bool _suspend_dirty; + TimeSelection _export_range; + sigc::connection _audio_progress_connection; + float _previous_progress; + TranscodeFfmpeg* _transcoder; + std::string _insnd; Gtk::Label outfn_path_label; Gtk::Entry outfn_path_entry; @@ -109,40 +92,16 @@ private: Gtk::ComboBoxText insnd_combo; Gtk::Button transcode_button; - Gtk::VBox* vbox; - Gtk::Button *cancel_button; - Gtk::Button abort_button; + Gtk::VBox* vbox; + Gtk::Button* cancel_button; + Gtk::Button abort_button; - Gtk::VBox* progress_box; + Gtk::VBox* progress_box; Gtk::ProgressBar pbar; - Gtk::ComboBoxText audio_codec_combo; - Gtk::ComboBoxText video_codec_combo; - Gtk::ComboBoxText video_bitrate_combo; - Gtk::ComboBoxText audio_bitrate_combo; - Gtk::ComboBoxText audio_samplerate_combo; - Gtk::ComboBoxText preset_combo; - - Gtk::CheckButton scale_checkbox; - Gtk::CheckButton scale_aspect; - Gtk::Adjustment width_adjustment; - Gtk::SpinButton width_spinner; - Gtk::Adjustment height_adjustment; - Gtk::SpinButton height_spinner; - Gtk::CheckButton aspect_checkbox; - Gtk::ComboBoxText aspect_combo; - Gtk::CheckButton normalize_checkbox; - Gtk::CheckButton twopass_checkbox; - Gtk::CheckButton optimizations_checkbox; - Gtk::Label optimizations_label; - Gtk::CheckButton deinterlace_checkbox; - Gtk::CheckButton bframes_checkbox; - Gtk::CheckButton fps_checkbox; - Gtk::ComboBoxText fps_combo; - Gtk::CheckButton meta_checkbox; -#if 1 /* tentative debug mode */ - Gtk::CheckButton debug_checkbox; -#endif + Gtk::CheckButton normalize_checkbox; + Gtk::CheckButton meta_checkbox; + Gtk::CheckButton debug_checkbox; }; #endif /* __gtk_ardour_export_video_dialog_h__ */ diff --git a/gtk2_ardour/transcode_ffmpeg.cc b/gtk2_ardour/transcode_ffmpeg.cc index 5188bff7ac..037a4ed6c7 100644 --- a/gtk2_ardour/transcode_ffmpeg.cc +++ b/gtk2_ardour/transcode_ffmpeg.cc @@ -18,15 +18,15 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #include #include -#include #include -#include "pbd/error.h" -#include "pbd/convert.h" -#include "pbd/file_utils.h" #include "gui_thread.h" +#include "pbd/convert.h" +#include "pbd/error.h" +#include "pbd/file_utils.h" #include "ardour/filesystem_paths.h" @@ -39,178 +39,175 @@ using namespace PBD; using namespace VideoUtils; TranscodeFfmpeg::TranscodeFfmpeg (std::string f) - : infile(f) + : infile (f) { - probeok = false; - ffexecok = false; + probeok = false; + ffexecok = false; m_duration = 0; m_avoffset = m_lead_in = m_lead_out = 0; m_width = m_height = 0; m_aspect = m_fps = 0; - m_sar = ""; -#if 1 /* tentative debug mode */ - debug_enable = false; -#endif + m_sar = ""; + debug_enable = false; - if (!ARDOUR::ArdourVideoToolPaths::transcoder_exe(ffmpeg_exe, ffprobe_exe)) { - warning << string_compose( - _( - "ffmpeg installation was not found on this system.\n" - "%1 requires ffmpeg and ffprobe from ffmpeg.org - version 1.1 or newer.\n" - "Video import and export is not possible until you install tools.\n" - "\n" - "The tools are included with the %1 releases from ardour.org " - "and also available with the video-server at http://x42.github.com/harvid/\n" - "\n" - "Important: the files need to be installed in $PATH and named ffmpeg_harvid and ffprobe_harvid.\n" - "If you already have a suitable ffmpeg installation on your system, we recommend creating " - "symbolic links from ffmpeg to ffmpeg_harvid and from ffprobe to ffprobe_harvid.\n" - "\n" - "see also http://manual.ardour.org/video-timeline/setup/" - ), PROGRAM_NAME) << endmsg; + if (!ARDOUR::ArdourVideoToolPaths::transcoder_exe (ffmpeg_exe, ffprobe_exe)) { + warning << string_compose (_("ffmpeg installation was not found on this system.\n" + "%1 requires ffmpeg and ffprobe from ffmpeg.org - version 1.1 or newer.\n" + "Video import and export is not possible until you install tools.\n" + "\n" + "The tools are included with the %1 releases from ardour.org " + "and also available with the video-server at http://x42.github.com/harvid/\n" + "\n" + "Important: the files need to be installed in $PATH and named ffmpeg_harvid and ffprobe_harvid.\n" + "If you already have a suitable ffmpeg installation on your system, we recommend creating " + "symbolic links from ffmpeg to ffmpeg_harvid and from ffprobe to ffprobe_harvid.\n" + "\n" + "see also http://manual.ardour.org/video-timeline/setup/"), + PROGRAM_NAME) + << endmsg; return; } ffexecok = true; - if (infile.empty() || !probe()) { + if (infile.empty () || !probe ()) { return; } probeok = true; } -TranscodeFfmpeg::~TranscodeFfmpeg () -{ - ; -} - bool TranscodeFfmpeg::probe () { ffoutput = ""; - char **argp; - argp=(char**) calloc(7,sizeof(char*)); - argp[0] = strdup(ffprobe_exe.c_str()); - argp[1] = strdup("-print_format"); - argp[2] = strdup("csv=nk=0"); - argp[3] = strdup("-show_format"); - argp[4] = strdup("-show_streams"); - argp[5] = strdup(infile.c_str()); + char** argp; + argp = (char**)calloc (7, sizeof (char*)); + argp[0] = strdup (ffprobe_exe.c_str ()); + argp[1] = strdup ("-print_format"); + argp[2] = strdup ("csv=nk=0"); + argp[3] = strdup ("-show_format"); + argp[4] = strdup ("-show_streams"); + argp[5] = strdup (infile.c_str ()); argp[6] = 0; - ffcmd = new ARDOUR::SystemExec(ffprobe_exe, argp); - ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffprobeparse, this, _1 ,_2)); - ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context()); + ffcmd = new ARDOUR::SystemExec (ffprobe_exe, argp); + ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffprobeparse, this, _1, _2)); + ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); if (ffcmd->start (SystemExec::IgnoreAndClose)) { - ffexit(); + ffexit (); return false; } /* wait for ffprobe process to exit */ - ffcmd->wait(); + ffcmd->wait (); /* wait for interposer thread to copy all data. * SystemExec::Terminated is emitted and ffcmd set to NULL */ int timeout = 300; // 1.5 sec while (ffcmd && --timeout > 0) { - Glib::usleep(5000); - ARDOUR::GUIIdle(); + Glib::usleep (5000); + ARDOUR::GUIIdle (); } - if (timeout == 0 || ffoutput.empty()) { + if (timeout == 0 || ffoutput.empty ()) { return false; } /* parse */ - std::vector > lines; - ParseCSV(ffoutput, lines); + std::vector> lines; + ParseCSV (ffoutput, lines); double timebase = 0; m_width = m_height = 0; m_fps = m_aspect = 0; - m_duration = 0; - m_sar.clear(); - m_codec.clear(); - m_audio.clear(); + m_duration = 0; + m_sar.clear (); + m_codec.clear (); + m_audio.clear (); -#define PARSE_FRACTIONAL_FPS(VAR) \ - { \ - std::string::size_type pos; \ - VAR = atof(value); \ - pos = value.find_first_of('/'); \ - if (pos != std::string::npos) { \ - VAR = atof(value.substr(0, pos)) / atof(value.substr(pos+1)); \ - } \ - } + /* clang-format off */ +#define PARSE_FRACTIONAL_FPS(VAR) \ +{ \ + std::string::size_type pos; \ + VAR = atof (value); \ + pos = value.find_first_of ('/'); \ + if (pos != std::string::npos) { \ + VAR = atof (value.substr (0, pos)) / atof (value.substr (pos + 1)); \ + } \ +} + /* clang-format on */ std::string duration_from_format; - for (std::vector >::iterator i = lines.begin(); i != lines.end(); ++i) { - if (i->at(0) == X_("format")) { + for (std::vector>::iterator i = lines.begin (); i != lines.end (); ++i) { + if (i->at (0) == X_("format")) { /* format,filename,#streams,format-name,format-long-name,start-time,duration,size,bitrate */ - for (std::vector::iterator kv = i->begin(); kv != i->end(); ++kv) { - const size_t kvsep = kv->find('='); - if(kvsep == std::string::npos) continue; - std::string key = kv->substr(0, kvsep); - std::string value = kv->substr(kvsep + 1); + for (std::vector::iterator kv = i->begin (); kv != i->end (); ++kv) { + const size_t kvsep = kv->find ('='); + if (kvsep == std::string::npos) { + continue; + } + std::string key = kv->substr (0, kvsep); + std::string value = kv->substr (kvsep + 1); if (key == X_("duration")) { duration_from_format = value; } } - } else - if (i->at(0) == X_("stream")) { - if (i->at(5) == X_("codec_type=video") && m_width == 0) { - - for (std::vector::iterator kv = i->begin(); kv != i->end(); ++kv) { - const size_t kvsep = kv->find('='); - if(kvsep == std::string::npos) continue; - std::string key = kv->substr(0, kvsep); - std::string value = kv->substr(kvsep + 1); + } else if (i->at (0) == X_("stream")) { + if (i->at (5) == X_("codec_type=video") && m_width == 0) { + for (std::vector::iterator kv = i->begin (); kv != i->end (); ++kv) { + const size_t kvsep = kv->find ('='); + if (kvsep == std::string::npos) + continue; + std::string key = kv->substr (0, kvsep); + std::string value = kv->substr (kvsep + 1); if (key == X_("index")) { - m_videoidx = atoi(value); + m_videoidx = atoi (value); } else if (key == X_("width")) { - m_width = atoi(value); + m_width = atoi (value); } else if (key == X_("height")) { - m_height = atoi(value); + m_height = atoi (value); } else if (key == X_("codec_name")) { - if (!m_codec.empty()) m_codec += " "; + if (!m_codec.empty ()) { + m_codec += " "; + } m_codec += value; } else if (key == X_("codec_long_name")) { - if (!m_codec.empty()) m_codec += " "; + if (!m_codec.empty ()) { + m_codec += " "; + } m_codec += "[" + value + "]"; } else if (key == X_("codec_tag_string")) { - if (!m_codec.empty()) m_codec += " "; + if (!m_codec.empty ()) { + m_codec += " "; + } m_codec += "(" + value + ")"; } else if (key == X_("r_frame_rate")) { - PARSE_FRACTIONAL_FPS(m_fps) + PARSE_FRACTIONAL_FPS (m_fps) } else if (key == X_("avg_frame_rate") && m_fps == 0) { - PARSE_FRACTIONAL_FPS(m_fps) + PARSE_FRACTIONAL_FPS (m_fps) } else if (key == X_("time_base")) { - PARSE_FRACTIONAL_FPS(timebase) + PARSE_FRACTIONAL_FPS (timebase) } else if (key == X_("timecode") && m_duration == 0 && m_fps > 0) { - int h,m,s; char f[32]; - if (sscanf(i->at(16).c_str(), "%d:%d:%d:%32s",&h,&m,&s,f) == 4) { - m_duration = (ARDOUR::samplecnt_t) floor(m_fps * ( - h * 3600.0 - + m * 60.0 - + s * 1.0 - + atoi(f) / pow((double)10, (int)strlen(f)) - )); + int h, m, s; + char f[32]; + if (sscanf (i->at (16).c_str (), "%d:%d:%d:%32s", &h, &m, &s, f) == 4) { + m_duration = (ARDOUR::samplecnt_t)floor (m_fps * (h * 3600.0 + m * 60.0 + s * 1.0 + atoi (f) / pow ((double)10, (int)strlen (f)))); } - } else if (key == X_("duration_ts") && m_fps == 0 && timebase !=0 ) { - m_duration = atof(value) * m_fps * timebase; + } else if (key == X_("duration_ts") && m_fps == 0 && timebase != 0) { + m_duration = atof (value) * m_fps * timebase; } else if (key == X_("duration") && m_fps != 0 && m_duration == 0) { - m_duration = atof(value) * m_fps; + m_duration = atof (value) * m_fps; } else if (key == X_("sample_aspect_ratio")) { std::string::size_type pos; - pos = value.find_first_of(':'); - if (pos != std::string::npos && atof(value.substr(pos+1)) != 0) { + pos = value.find_first_of (':'); + if (pos != std::string::npos && atof (value.substr (pos + 1)) != 0) { m_sar = value; - m_sar.replace(pos, 1, "/"); + m_sar.replace (pos, 1, "/"); } } else if (key == X_("display_aspect_ratio")) { std::string::size_type pos; - pos = value.find_first_of(':'); - if (pos != std::string::npos && atof(value.substr(pos+1)) != 0) { - m_aspect = atof(value.substr(0, pos)) / atof(value.substr(pos+1)); + pos = value.find_first_of (':'); + if (pos != std::string::npos && atof (value.substr (pos + 1)) != 0) { + m_aspect = atof (value.substr (0, pos)) / atof (value.substr (pos + 1)); } } } @@ -219,56 +216,65 @@ TranscodeFfmpeg::probe () m_aspect = (double)m_width / (double)m_height; } - } else if (i->at(5) == X_("codec_type=audio")) { /* new ffprobe */ + } else if (i->at (5) == X_("codec_type=audio")) { /* new ffprobe */ FFAudioStream as; - for (std::vector::iterator kv = i->begin(); kv != i->end(); ++kv) { - const size_t kvsep = kv->find('='); - if(kvsep == std::string::npos) continue; - std::string key = kv->substr(0, kvsep); - std::string value = kv->substr(kvsep + 1); + for (std::vector::iterator kv = i->begin (); kv != i->end (); ++kv) { + const size_t kvsep = kv->find ('='); + if (kvsep == std::string::npos) { + continue; + } + std::string key = kv->substr (0, kvsep); + std::string value = kv->substr (kvsep + 1); if (key == X_("channels")) { - as.channels = atoi(value); + as.channels = atoi (value); } else if (key == X_("index")) { - as.stream_id = value; + as.stream_id = value; } else if (key == X_("codec_long_name")) { - if (!as.name.empty()) as.name += " "; + if (!as.name.empty ()) { + as.name += " "; + } as.name += value; } else if (key == X_("codec_name")) { - if (!as.name.empty()) as.name += " "; + if (!as.name.empty ()) { + as.name += " "; + } as.name += value; } else if (key == X_("sample_fmt")) { - if (!as.name.empty()) as.name += " "; + if (!as.name.empty ()) { + as.name += " "; + } as.name += "FMT:" + value; } else if (key == X_("sample_rate")) { - if (!as.name.empty()) as.name += " "; + if (!as.name.empty ()) { + as.name += " "; + } as.name += "SR:" + value; } - } - m_audio.push_back(as); + m_audio.push_back (as); } } } /* end parse */ - if (m_duration == 0 && !duration_from_format.empty() && m_fps > 0) { + if (m_duration == 0 && !duration_from_format.empty () && m_fps > 0) { warning << "using video-duration from format (container)." << endmsg; - m_duration = atof(duration_from_format) * m_fps; + m_duration = atof (duration_from_format) * m_fps; } #if 0 /* DEBUG */ - printf("FPS: %f\n", m_fps); - printf("Duration: %lu frames\n",(unsigned long)m_duration); - printf("W/H: %ix%i\n",m_width, m_height); - printf("aspect: %f\n",m_aspect); - printf("codec: %s\n",m_codec.c_str()); + printf ("FPS: %f\n", m_fps); + printf ("Duration: %lu frames\n", (unsigned long)m_duration); + printf ("W/H: %ix%i\n", m_width, m_height); + printf ("aspect: %f\n", m_aspect); + printf ("codec: %s\n", m_codec.c_str()); if (m_audio.size() > 0) { for (AudioStreams::iterator it = m_audio.begin(); it < m_audio.end(); ++it) { - printf("audio: %s - %i channels\n",(*it).stream_id.c_str(), (*it).channels); + printf ("audio: %s - %i channels\n",(*it).stream_id.c_str(), (*it).channels); } } else { - printf("audio: no audio streams in file.\n"); + printf ("audio: no audio streams in file.\n"); } #endif @@ -279,11 +285,11 @@ TranscodeFfmpeg::FFSettings TranscodeFfmpeg::default_encoder_settings () { TranscodeFfmpeg::FFSettings ffs; - ffs.clear(); + ffs.clear (); ffs["-vcodec"] = "mpeg4"; ffs["-acodec"] = "ac3"; - ffs["-b:v"] = "5000k"; - ffs["-b:a"] = "160k"; + ffs["-b:v"] = "5000k"; + ffs["-b:a"] = "160k"; return ffs; } @@ -291,39 +297,43 @@ TranscodeFfmpeg::FFSettings TranscodeFfmpeg::default_meta_data () { TranscodeFfmpeg::FFSettings ffm; - ffm.clear(); + ffm.clear (); ffm["comment"] = "Created with " PROGRAM_NAME; return ffm; } - bool TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf_v, TranscodeFfmpeg::FFSettings ffs, TranscodeFfmpeg::FFSettings meta, bool map) { #define MAX_FFMPEG_ENCODER_ARGS (100) - char **argp; - int a=0; + int a = 0; + + char** argp = (char**)calloc (MAX_FFMPEG_ENCODER_ARGS, sizeof (char*)); + argp[a++] = strdup (ffmpeg_exe.c_str ()); - argp=(char**) calloc(MAX_FFMPEG_ENCODER_ARGS,sizeof(char*)); - argp[a++] = strdup(ffmpeg_exe.c_str()); if (m_avoffset < 0 || m_avoffset > 0) { - std::ostringstream osstream; osstream << m_avoffset; - argp[a++] = strdup("-itsoffset"); - argp[a++] = strdup(osstream.str().c_str()); + argp[a++] = strdup ("-accurate_seek"); + std::ostringstream osstream; + osstream << m_avoffset; + argp[a++] = strdup ("-itsoffset"); + argp[a++] = strdup (osstream.str ().c_str ()); + argp[a++] = strdup ("-ss"); + argp[a++] = strdup ("0"); } - argp[a++] = strdup("-i"); - argp[a++] = strdup(inf_v.c_str()); - argp[a++] = strdup("-i"); - argp[a++] = strdup(inf_a.c_str()); + argp[a++] = strdup ("-i"); + argp[a++] = strdup (inf_v.c_str ()); - for(TranscodeFfmpeg::FFSettings::const_iterator it = ffs.begin(); it != ffs.end(); ++it) { - argp[a++] = strdup(it->first.c_str()); - argp[a++] = strdup(it->second.c_str()); + argp[a++] = strdup ("-i"); + argp[a++] = strdup (inf_a.c_str ()); + + for (TranscodeFfmpeg::FFSettings::const_iterator it = ffs.begin (); it != ffs.end (); ++it) { + argp[a++] = strdup (it->first.c_str ()); + argp[a++] = strdup (it->second.c_str ()); } - for(TranscodeFfmpeg::FFSettings::const_iterator it = meta.begin(); it != meta.end(); ++it) { - argp[a++] = strdup("-metadata"); - argp[a++] = SystemExec::format_key_value_parameter (it->first.c_str(), it->second.c_str()); + for (TranscodeFfmpeg::FFSettings::const_iterator it = meta.begin (); it != meta.end (); ++it) { + argp[a++] = strdup ("-metadata"); + argp[a++] = SystemExec::format_key_value_parameter (it->first.c_str (), it->second.c_str ()); } if (m_fps > 0) { @@ -333,62 +343,70 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf if (m_lead_in != 0 && m_lead_out != 0) { std::ostringstream osstream; - argp[a++] = strdup("-vf"); + argp[a++] = strdup ("-vf"); osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; - if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + if (!m_sar.empty ()) { + osstream << X_(":sar=") << m_sar; + } osstream << X_(" [pre]; "); osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; - if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + if (!m_sar.empty ()) { + osstream << X_(":sar=") << m_sar; + } osstream << X_(" [post]; "); osstream << X_("[pre] [in] [post] concat=n=3"); - argp[a++] = strdup(osstream.str().c_str()); + argp[a++] = strdup (osstream.str ().c_str ()); } else if (m_lead_in != 0) { std::ostringstream osstream; - argp[a++] = strdup("-vf"); + argp[a++] = strdup ("-vf"); osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_in; - if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + if (!m_sar.empty ()) { + osstream << X_(":sar=") << m_sar; + } osstream << X_(" [pre]; "); osstream << X_("[pre] [in] concat=n=2"); - argp[a++] = strdup(osstream.str().c_str()); + argp[a++] = strdup (osstream.str ().c_str ()); } else if (m_lead_out != 0) { std::ostringstream osstream; - argp[a++] = strdup("-vf"); + argp[a++] = strdup ("-vf"); osstream << X_("color=c=black:s=") << m_width << X_("x") << m_height << X_(":d=") << m_lead_out; - if (!m_sar.empty()) osstream << X_(":sar=") << m_sar; + if (!m_sar.empty ()) { + osstream << X_(":sar=") << m_sar; + } osstream << X_(" [post]; "); osstream << X_("[in] [post] concat=n=2"); - argp[a++] = strdup(osstream.str().c_str()); + argp[a++] = strdup (osstream.str ().c_str ()); } if (map) { std::ostringstream osstream; - argp[a++] = strdup("-map"); + argp[a++] = strdup ("-map"); osstream << X_("0:") << m_videoidx; - argp[a++] = strdup(osstream.str().c_str()); - argp[a++] = strdup("-map"); - argp[a++] = strdup("1:0"); + argp[a++] = strdup (osstream.str ().c_str ()); + argp[a++] = strdup ("-map"); + argp[a++] = strdup ("1:0"); } - argp[a++] = strdup("-y"); - argp[a++] = strdup(outfile.c_str()); - argp[a] = (char *)0; - assert(aReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1 ,_2)); - ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context()); + if (debug_enable) { + printf ("EXPORT ENCODE:\n"); + for (int i = 0; i < a; ++i) { + printf ("%s ", argp[i]); + } + printf ("\n"); + } + + ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); + ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2)); + ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); + if (ffcmd->start (SystemExec::MergeWithStdin)) { - ffexit(); + ffexit (); return false; } return true; @@ -397,106 +415,120 @@ TranscodeFfmpeg::encode (std::string outfile, std::string inf_a, std::string inf bool TranscodeFfmpeg::extract_audio (std::string outfile, ARDOUR::samplecnt_t /*samplerate*/, unsigned int stream) { - if (!probeok) return false; - if (stream >= m_audio.size()) return false; + if (!probeok || stream >= m_audio.size ()) { + return false; + } - char **argp; - int i = 0; + char** argp; + int i = 0; - argp=(char**) calloc(15,sizeof(char*)); - argp[i++] = strdup(ffmpeg_exe.c_str()); - argp[i++] = strdup("-i"); - argp[i++] = strdup(infile.c_str()); + argp = (char**)calloc (15, sizeof (char*)); + argp[i++] = strdup (ffmpeg_exe.c_str ()); + argp[i++] = strdup ("-i"); + argp[i++] = strdup (infile.c_str ()); #if 0 /* ffmpeg write original samplerate, use a3/SRC to resample */ argp[i++] = strdup("-ar"); argp[i] = (char*) calloc(7,sizeof(char)); snprintf(argp[i++], 7, "%"PRId64, samplerate); #endif - argp[i++] = strdup("-ac"); - argp[i] = (char*) calloc(3,sizeof(char)); snprintf(argp[i++], 3, "%i", m_audio.at(stream).channels); - argp[i++] = strdup("-map"); - argp[i] = (char*) calloc(8,sizeof(char)); snprintf(argp[i++], 8, "0:%s", m_audio.at(stream).stream_id.c_str()); - argp[i++] = strdup("-vn"); - argp[i++] = strdup("-acodec"); - argp[i++] = strdup("pcm_f32le"); - argp[i++] = strdup("-y"); - argp[i++] = strdup(outfile.c_str()); - argp[i++] = (char *)0; + argp[i++] = strdup ("-ac"); + argp[i] = (char*)calloc (3, sizeof (char)); + snprintf (argp[i++], 3, "%i", m_audio.at (stream).channels); + argp[i++] = strdup ("-map"); + argp[i] = (char*)calloc (8, sizeof (char)); + snprintf (argp[i++], 8, "0:%s", m_audio.at (stream).stream_id.c_str ()); + argp[i++] = strdup ("-vn"); + argp[i++] = strdup ("-acodec"); + argp[i++] = strdup ("pcm_f32le"); + argp[i++] = strdup ("-y"); + argp[i++] = strdup (outfile.c_str ()); + argp[i++] = (char*)0; /* Note: argp is free()d in ~SystemExec */ -#if 1 /* DEBUG */ - if (debug_enable) { /* tentative debug mode */ - printf("EXTRACT AUDIO:\n"); - for (int i=0; i< 14; ++i) { - printf("%s ", argp[i]); - } - printf("\n"); - } -#endif - ffcmd = new ARDOUR::SystemExec(ffmpeg_exe, argp); - ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_a, this, _1 ,_2)); - ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context()); + if (debug_enable) { + printf ("EXTRACT AUDIO:\n"); + for (int i = 0; i < 14; ++i) { + printf ("%s ", argp[i]); + } + printf ("\n"); + } + + ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); + ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_a, this, _1, _2)); + ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); + if (ffcmd->start (SystemExec::MergeWithStdin)) { - ffexit(); + ffexit (); return false; } return true; } - bool TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh, const int kbitps) { - if (!probeok) return false; + if (!probeok) { + return false; + } - char **argp; - int bitrate = kbitps; - int width = outw; - int height = outh; + char** argp; + int bitrate = kbitps; + int width = outw; + int height = outh; - if (width < 1 || width > m_width) { width = m_width; } /* don't allow upscaling */ - if (height < 1 || height > m_height) { height = floor(width / m_aspect); } + if (width < 1 || width > m_width) { + width = m_width; + } + /* don't allow upscaling */ + if (height < 1 || height > m_height) { + height = floor (width / m_aspect); + } if (bitrate == 0) { const double bitperpixel = .7; /* avg quality */ - bitrate = floor(m_fps * width * height * bitperpixel / 10000.0); + bitrate = floor (m_fps * width * height * bitperpixel / 10000.0); } else { bitrate = bitrate / 10; } - if (bitrate < 10) bitrate = 10; - if (bitrate > 1000) bitrate = 1000; + if (bitrate < 10) { + bitrate = 10; + } + if (bitrate > 1000) { + bitrate = 1000; + } - argp=(char**) calloc(16,sizeof(char*)); - argp[0] = strdup(ffmpeg_exe.c_str()); - argp[1] = strdup("-i"); - argp[2] = strdup(infile.c_str()); - argp[3] = strdup("-b:v"); - argp[4] = (char*) calloc(7,sizeof(char)); snprintf(argp[4], 7, "%i0k", bitrate); - argp[5] = strdup("-s"); - argp[6] = (char*) calloc(10,sizeof(char)); snprintf(argp[6], 10, "%ix%i", width, height); - argp[7] = strdup("-y"); - argp[8] = strdup("-vcodec"); - argp[9] = strdup("mjpeg"); - argp[10] = strdup("-an"); - argp[11] = strdup("-intra"); - argp[12] = strdup("-g"); - argp[13] = strdup("1"); - argp[14] = strdup(outfile.c_str()); - argp[15] = (char *)0; + argp = (char**)calloc (15, sizeof (char*)); + argp[0] = strdup (ffmpeg_exe.c_str ()); + argp[1] = strdup ("-i"); + argp[2] = strdup (infile.c_str ()); + argp[3] = strdup ("-b:v"); + argp[4] = (char*)calloc (7, sizeof (char)); + snprintf (argp[4], 7, "%i0k", bitrate); + argp[5] = strdup ("-s"); + argp[6] = (char*)calloc (10, sizeof (char)); + snprintf (argp[6], 10, "%ix%i", width, height); + argp[7] = strdup ("-y"); + argp[8] = strdup ("-vcodec"); + argp[9] = strdup ("mjpeg"); + argp[10] = strdup ("-an"); + argp[11] = strdup ("-g"); + argp[12] = strdup ("0"); + argp[13] = strdup (outfile.c_str ()); + argp[14] = (char*)0; /* Note: these are free()d in ~SystemExec */ -#if 1 /* DEBUG */ - if (debug_enable) { /* tentative debug mode */ - printf("TRANSCODE VIDEO:\n"); - for (int i=0; i< 15; ++i) { - printf("%s ", argp[i]); + + if (debug_enable) { + printf ("TRANSCODE VIDEO:\n"); + for (int i = 0; i < 15; ++i) { + printf ("%s ", argp[i]); + } + printf ("\n"); } - printf("\n"); - } -#endif - ffcmd = new ARDOUR::SystemExec(ffmpeg_exe, argp); - ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1 ,_2)); - ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context()); + + ffcmd = new ARDOUR::SystemExec (ffmpeg_exe, argp); + ffcmd->ReadStdout.connect_same_thread (*this, boost::bind (&TranscodeFfmpeg::ffmpegparse_v, this, _1, _2)); + ffcmd->Terminated.connect (*this, invalidator (*this), boost::bind (&TranscodeFfmpeg::ffexit, this), gui_context ()); if (ffcmd->start (SystemExec::MergeWithStdin)) { - ffexit(); + ffexit (); return false; } return true; @@ -505,75 +537,90 @@ TranscodeFfmpeg::transcode (std::string outfile, const int outw, const int outh, void TranscodeFfmpeg::cancel () { - if (!ffcmd || !ffcmd->is_running()) { return;} - ffcmd->write_to_stdin("q"); -#ifdef PLATFORM_WINDOWS - Sleep(1000); -#else - sleep (1); -#endif + if (!ffcmd || !ffcmd->is_running ()) { + return; + } + ffcmd->write_to_stdin ("q"); + Glib::usleep (1000000); /* 1 sec */ if (ffcmd) { - ffcmd->terminate(); + ffcmd->terminate (); } } void TranscodeFfmpeg::ffexit () { + int rv = ffcmd->wait (); delete ffcmd; - ffcmd=0; - Finished(); /* EMIT SIGNAL */ + ffcmd = 0; + Finished (rv); /* EMIT SIGNAL */ } void TranscodeFfmpeg::ffprobeparse (std::string d, size_t /* s */) { - ffoutput+=d; + ffoutput += d; } void TranscodeFfmpeg::ffmpegparse_a (std::string d, size_t /* s */) { - const char *t; - int h,m,s; char f[7]; - ARDOUR::samplecnt_t p = -1; + const char* t; + int h, m, s; + char f[7]; - if (!(t=strstr(d.c_str(), "time="))) { return; } + if (!(t = strstr (d.c_str (), "time="))) { + Progress (0, 0); /* EMIT SIGNAL */ + return; + } - if (sscanf(t+5, "%d:%d:%d.%s",&h,&m,&s,f) == 4) { - p = (ARDOUR::samplecnt_t) floor( 100.0 * ( - h * 3600.0 - + m * 60.0 - + s * 1.0 - + atoi(f) / pow((double)10, (int)strlen(f)) - )); + if (sscanf (t + 5, "%d:%d:%d.%s", &h, &m, &s, f) == 4) { + ARDOUR::samplecnt_t p; + p = (ARDOUR::samplecnt_t)floor (100.0 * (h * 3600.0 + m * 60.0 + s * 1.0 + atoi (f) / pow (10.0, (int)strlen (f)))); p = p * m_fps / 100.0; - if (p > m_duration ) { p = m_duration; } - Progress(p, m_duration); /* EMIT SIGNAL */ + if (p > m_duration) { + p = m_duration; + } + Progress (p, m_duration); /* EMIT SIGNAL */ } else { - Progress(0, 0); /* EMIT SIGNAL */ + Progress (0, 0); /* EMIT SIGNAL */ } } void TranscodeFfmpeg::ffmpegparse_v (std::string d, size_t /* s */) { - if (strstr(d.c_str(), "ERROR") || strstr(d.c_str(), "Error") || strstr(d.c_str(), "error")) { - warning << "ffmpeg-error: " << d << endmsg; - } - if (strncmp(d.c_str(), "frame=",6)) { -#if 1 /* DEBUG */ - if (debug_enable) { - d.erase(d.find_last_not_of(" \t\r\n") + 1); - printf("ffmpeg: '%s'\n", d.c_str()); - } -#endif + /* see ffmpeg-src/doc/errno.txt + * Not all error messages are forwarded to ardour's log, + * but exit-code other than 0 shows a popup window. + */ + if (strstr (d.c_str (), "No space left on device") || strstr (d.c_str (), "File too large")) { + error << "ffmpeg-error: " << d << endmsg; return; } - ARDOUR::samplecnt_t f = atol(d.substr(6)); + + if (strstr (d.c_str (), "ERROR") || strstr (d.c_str (), "Error") || strstr (d.c_str (), "error")) { + error << "ffmpeg-error: " << d << endmsg; + return; + } + if (strstr (d.c_str (), "Unrecognized option") || strstr (d.c_str (), "Missing argument") || strstr (d.c_str (), "Invalid argument")) { + error << "ffmpeg-error: " << d << endmsg; + return; + } + + if (strncmp (d.c_str (), "frame=", 6)) { + if (debug_enable) { + d.erase (d.find_last_not_of (" \t\r\n") + 1); + printf ("ffmpeg: '%s'\n", d.c_str ()); + } + Progress (0, 0); /* EMIT SIGNAL */ + return; + } + + ARDOUR::samplecnt_t f = atol (d.substr (6)); if (f == 0) { - Progress(0, 0); /* EMIT SIGNAL */ + Progress (0, 0); /* EMIT SIGNAL */ } else { - Progress(f, m_duration); /* EMIT SIGNAL */ + Progress (f, m_duration); /* EMIT SIGNAL */ } } diff --git a/gtk2_ardour/transcode_ffmpeg.h b/gtk2_ardour/transcode_ffmpeg.h index da751a94bc..0a443a186d 100644 --- a/gtk2_ardour/transcode_ffmpeg.h +++ b/gtk2_ardour/transcode_ffmpeg.h @@ -19,10 +19,10 @@ #define __ardour_transcode_ffmpeg_h__ #include + #include "ardour/system_exec.h" #include "ardour/types.h" - /** @class TranscodeFfmpeg * @brief wrapper around ffmpeg and ffprobe command-line utils * @@ -31,138 +31,175 @@ * transcode video-files and extract aufio tracks and query * file information. */ -class TranscodeFfmpeg : public sigc::trackable - , public PBD::ScopedConnectionList +class TranscodeFfmpeg : public sigc::trackable, public PBD::ScopedConnectionList { - public: - +public: struct FFAudioStream { std::string name; std::string stream_id; - uint32_t channels; + uint32_t channels; }; - typedef std::vector FFAudioStreams; - typedef std::map FFSettings; + typedef std::vector FFAudioStreams; + typedef std::map FFSettings; - /** instantiate a new transcoder. If a file-name is given, the file's - * attributes (fps, duration, geometry etc) are read. - * - * @param f path to the video-file to probe or use as input for \ref extract_audio and \ref transcode . - */ - TranscodeFfmpeg (std::string f); - virtual ~TranscodeFfmpeg (); + /** instantiate a new transcoder. If a file-name is given, the file's + * attributes (fps, duration, geometry etc) are read. + * + * @param f path to the video-file to probe or use as input for \ref extract_audio and \ref transcode . + */ + TranscodeFfmpeg (std::string f); - /** transcode to (import a video-file) - * - * @param outfile full-path (incl. file-extension) of the file to create - * @param width video-width, if \c <0 no scaling - * @param height video-height, with \c <0 preserve aspect (\p width \c / \c aspect-ratio) - * @param kbitps video bitrate, with \c 0 calculate to use 0.7 bits per pixel on average - * @return \c true if the transcoder process was successfully started. - */ - bool transcode (std::string outfile, const int width=0, const int height=0, const int kbitps =0); + /** transcode to (import a video-file) + * + * @param outfile full-path (incl. file-extension) of the file to create + * @param width video-width, if \c <0 no scaling + * @param height video-height, with \c <0 preserve aspect (\p width \c / \c aspect-ratio) + * @param kbitps video bitrate, with \c 0 calculate to use 0.7 bits per pixel on average + * @return \c true if the transcoder process was successfully started. + */ + bool transcode (std::string outfile, const int width = 0, const int height = 0, const int kbitps = 0); - /** Extract an audio track from the given input file to a new 32bit float little-endian PCM WAV file. - * @param outfile full-path (incl. file-extension) to .wav file to write - * @param samplerate target samplerate - * @param stream Stream-ID of the audio-track to extract - * specified as element-number in \ref get_audio(). - * @return \c true if the transcoder process was successfully started. - */ - bool extract_audio (std::string outfile, ARDOUR::samplecnt_t samplerate, unsigned int stream=0); + /** Extract an audio track from the given input file to a new 32bit float little-endian PCM WAV file. + * @param outfile full-path (incl. file-extension) to .wav file to write + * @param samplerate target samplerate + * @param stream Stream-ID of the audio-track to extract + * specified as element-number in \ref get_audio(). + * @return \c true if the transcoder process was successfully started. + */ + bool extract_audio (std::string outfile, ARDOUR::samplecnt_t samplerate, unsigned int stream = 0); - /** transcode video and mux audio files into a new video-file. - * @param outfile full-path of output file to create (existing files are overwritten) - * @param inf_a filename of input audio-file - * @param inf_v filename of input video-file - * @param ffs additional command-line parameters for 'ffmpeg'. key/value pairs - * eg ffs["-vcodec"] = "mpeg4" - * @param meta additional meta-data results in -metadata ""="" command-line - * arguments - * @param map if set to \c true stream mapping from input streams to output streams is set to use - * only the first available stream from the audio & video file (-map 0.0 -map 1.0). - * @return \c true if the encoder process was successfully started. - */ - bool encode (std::string outfile, std::string inf_a, std::string inf_v, FFSettings ffs, FFSettings meta, bool map = true); + /** transcode video and mux audio files into a new video-file. + * @param outfile full-path of output file to create (existing files are overwritten) + * @param inf_a filename of input audio-file + * @param inf_v filename of input video-file + * @param ffs additional command-line parameters for 'ffmpeg'. key/value pairs + * eg ffs["-vcodec"] = "mpeg4" + * @param meta additional meta-data results in -metadata ""="" command-line + * arguments + * @param map if set to \c true stream mapping from input streams to output streams is set to use + * only the first available stream from the audio & video file (-map 0.0 -map 1.0). + * @return \c true if the encoder process was successfully started. + */ + bool encode (std::string outfile, std::string inf_a, std::string inf_v, FFSettings ffs, FFSettings meta, bool map = true); - /** @return array with default encoder settings */ - FFSettings default_encoder_settings (); - /** @return array with default meta data */ - FFSettings default_meta_data (); - /** abort any running transcoding process */ - void cancel(); - /** - * @return \c true if the input file was parsed correctly on class creation. */ - bool probe_ok () { return probeok; } - /** @return \c true if the ffmpeg/ffparse executables are avail on this system */ - bool ffexec_ok () { return ffexecok; } + /** abort any running transcoding process */ + void cancel (); - /** signal emitted when ffmpeg reports progress updates - * during \ref encode \ref transcode and \ref extract_audio - * The parameters are current and last video-frame. - */ - PBD::Signal2 Progress; - /** signal emitted when the transcoder process terminates. */ - PBD::Signal0 Finished; + /** @return array with default encoder settings */ + FFSettings default_encoder_settings (); - double get_fps () { return m_fps; } - double get_aspect () { return m_aspect; } - int get_width() { return m_width; } - int get_height() { return m_height; } - ARDOUR::samplecnt_t get_duration() { return m_duration; } - std::string get_codec() { return m_codec; } + /** @return array with default meta data */ + FFSettings default_meta_data (); - FFAudioStreams get_audio() { return m_audio; } + /** @return \c true if the input file was parsed correctly on class creation. */ + bool probe_ok () + { + return probeok; + } - /** override file duration used with the \ref Progress signal. - * @param d duration in video-frames = length_in_seconds * get_fps() - */ - void set_duration(ARDOUR::samplecnt_t d) { m_duration = d; } + /** @return \c true if the ffmpeg/ffparse executables are avail on this system */ + bool ffexec_ok () + { + return ffexecok; + } - /* offset, lead-in/out are in seconds */ - void set_avoffset(double av_offset) { m_avoffset = av_offset; } - void set_leadinout(double lead_in, double lead_out) { m_lead_in = lead_in; m_lead_out = lead_out; } + double get_fps () + { + return m_fps; + } - void set_fps(double fps) { m_fps = fps; } // on export, used for rounding only. + double get_aspect () + { + return m_aspect; + } -#if 1 /* tentative debug mode */ - void set_debug (bool onoff) { debug_enable = onoff; } -#endif - protected: - std::string infile; - ARDOUR::SystemExec *ffcmd; + int get_width () + { + return m_width; + } - bool probe (); + int get_height () + { + return m_height; + } - double m_fps; - double m_aspect; - std::string m_sar; - ARDOUR::samplecnt_t m_duration; - int m_width; - int m_height; - std::string m_codec; + ARDOUR::samplecnt_t get_duration () + { + return m_duration; + } - int m_videoidx; - double m_avoffset; - double m_lead_in; - double m_lead_out; - bool ffexecok; - bool probeok; + std::string get_codec () + { + return m_codec; + } - FFAudioStreams m_audio; + FFAudioStreams get_audio () + { + return m_audio; + } - void ffmpegparse_v (std::string d, size_t s); - void ffmpegparse_a (std::string d, size_t s); - void ffprobeparse (std::string d, size_t s); - void ffexit (); - std::string ffoutput; + /** override file duration used with the \ref Progress signal. + * @param d duration in video-frames = length_in_seconds * get_fps() + */ + void set_duration (ARDOUR::samplecnt_t d) + { + m_duration = d; + } - std::string ffmpeg_exe; - std::string ffprobe_exe; -#if 1 /* tentative debug mode */ - bool debug_enable; -#endif + /* offset, lead-in/out are in seconds */ + void set_avoffset (double av_offset) + { + m_avoffset = av_offset; + } + + void set_leadinout (double lead_in, double lead_out) + { + m_lead_in = lead_in; + m_lead_out = lead_out; + } + + void set_debug (bool onoff) + { + debug_enable = onoff; + } + + /** signal emitted when ffmpeg reports progress updates + * during \ref encode \ref transcode and \ref extract_audio + * The parameters are current and last video-frame. + */ + PBD::Signal2 Progress; + + /** signal emitted when the transcoder process terminates. */ + PBD::Signal1 Finished; + +protected: + bool probe (); + void ffmpegparse_v (std::string d, size_t s); + void ffmpegparse_a (std::string d, size_t s); + void ffprobeparse (std::string d, size_t s); + void ffexit (); + + std::string infile; + ARDOUR::SystemExec* ffcmd; + double m_fps; + double m_aspect; + std::string m_sar; + ARDOUR::samplecnt_t m_duration; + int m_width; + int m_height; + std::string m_codec; + int m_videoidx; + double m_avoffset; + double m_lead_in; + double m_lead_out; + bool ffexecok; + bool probeok; + FFAudioStreams m_audio; + std::string ffoutput; + std::string ffmpeg_exe; + std::string ffprobe_exe; + bool debug_enable; }; #endif /* __ardour_transcode_ffmpeg_h__ */ diff --git a/gtk2_ardour/transcode_video_dialog.cc b/gtk2_ardour/transcode_video_dialog.cc index e4e1978dd9..976bf49534 100644 --- a/gtk2_ardour/transcode_video_dialog.cc +++ b/gtk2_ardour/transcode_video_dialog.cc @@ -18,14 +18,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include -#include -#include #include +#include +#include -#include -#include -#include #include +#include +#include +#include #include @@ -34,19 +34,20 @@ #include "pbd/gstdio_compat.h" -#include "pbd/error.h" -#include "pbd/convert.h" -#include "gtkmm2ext/utils.h" -#include "ardour/session_directory.h" #include "ardour/profile.h" -#include "ardour/template_utils.h" #include "ardour/session.h" +#include "ardour/session_directory.h" +#include "ardour/template_utils.h" #include "ardour_ui.h" +#include "gtkmm2ext/utils.h" #include "gui_thread.h" +#include "pbd/convert.h" +#include "pbd/error.h" #include "opts.h" #include "transcode_video_dialog.h" #include "utils_videotl.h" + #include "pbd/i18n.h" using namespace Gtk; @@ -70,16 +71,14 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) , bitrate_checkbox (_("Manual Override")) , bitrate_adjustment (2000, 500, 10000, 10, 100, 0) , bitrate_spinner (bitrate_adjustment) -#if 1 /* tentative debug mode */ , debug_checkbox (_("Debug Mode: Print ffmpeg command and output to stdout.")) -#endif { set_session (s); - transcoder = new TranscodeFfmpeg(infile); - audiofile = ""; + transcoder = new TranscodeFfmpeg (infile); + audiofile = ""; pending_audio_extract = false; - aborted = false; + aborted = false; set_name ("TranscodeVideoDialog"); set_modal (true); @@ -87,24 +86,26 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) set_resizable (false); Gtk::Label* l; - vbox = manage (new VBox); + vbox = manage (new VBox); VBox* options_box = manage (new VBox); - HBox* path_hbox = manage (new HBox); + HBox* path_hbox = manage (new HBox); int w = 0, h = 0; - m_aspect = 4.0/3.0; - TranscodeFfmpeg::FFAudioStreams as; as.clear(); + m_aspect = 16.0 / 9.0; + + TranscodeFfmpeg::FFAudioStreams as; path_hbox->pack_start (path_label, false, false, 3); path_hbox->pack_start (path_entry, true, true, 3); path_hbox->pack_start (browse_button, false, false, 3); - path_entry.set_width_chars(38); - height_spinner.set_sensitive(false); - bitrate_spinner.set_sensitive(false); + height_spinner.set_sensitive (false); + bitrate_spinner.set_sensitive (false); - std::string dstdir = video_dest_dir(_session->session_directory().video_path(), video_get_docroot(Config)); - std::string dstfn = video_dest_file(dstdir, infile); + std::string dstdir = video_dest_dir (_session->session_directory ().video_path (), video_get_docroot (Config)); + std::string dstfn = video_dest_file (dstdir, infile); + + path_entry.set_width_chars (38); path_entry.set_text (dstfn); l = manage (new Label (_("File Information"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); @@ -112,25 +113,24 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) options_box->pack_start (*l, false, true, 4); bool ffok = false; - if (!transcoder->ffexec_ok()) { + if (!transcoder->ffexec_ok ()) { l = manage (new Label (_("ffmpeg installation was not found. Video Import is not possible. See the Log window for more information."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); - l->set_line_wrap(); + l->set_line_wrap (); options_box->pack_start (*l, false, true, 4); - aspect_checkbox.set_sensitive(false); - bitrate_checkbox.set_sensitive(false); - } - else if (!transcoder->probe_ok()) { - l = manage (new Label (string_compose(_("File-info can not be read. Most likely '%1' is not a valid video-file or an unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + aspect_checkbox.set_sensitive (false); + bitrate_checkbox.set_sensitive (false); + } else if (!transcoder->probe_ok ()) { + l = manage (new Label (string_compose (_("File-info can not be read. Most likely '%1' is not a valid video-file or an unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); options_box->pack_start (*l, false, true, 4); - aspect_checkbox.set_sensitive(false); - bitrate_checkbox.set_sensitive(false); + aspect_checkbox.set_sensitive (false); + bitrate_checkbox.set_sensitive (false); } else { - w = transcoder->get_width(); - h = transcoder->get_height(); - as = transcoder->get_audio(); - m_aspect = transcoder->get_aspect(); + w = transcoder->get_width (); + h = transcoder->get_height (); + as = transcoder->get_audio (); + m_aspect = transcoder->get_aspect (); - if (w > 0 && h > 0 && transcoder->get_fps() > 0 && transcoder->get_duration() > 0) { + if (w > 0 && h > 0 && transcoder->get_fps () > 0 && transcoder->get_duration () > 0) { ffok = true; } @@ -147,35 +147,35 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) t->attach (*l, 2, 3, 1, 2); std::ostringstream osstream; - osstream << transcoder->get_fps(); - l = manage (new Label (osstream.str(), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + osstream << transcoder->get_fps (); + l = manage (new Label (osstream.str (), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); t->attach (*l, 1, 2, 0, 1); - osstream.str(""); + osstream.str (""); osstream << w << "x" << h; - l = manage (new Label (osstream.str(), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (osstream.str (), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); t->attach (*l, 3, 4, 1, 2); - osstream.str(""); - if (transcoder->get_duration() == 0 || transcoder->get_fps() == 0) { + osstream.str (""); + if (transcoder->get_duration () == 0 || transcoder->get_fps () == 0) { osstream << _("??"); } else { - unsigned long sec = transcoder->get_duration() / transcoder->get_fps(); - osstream << setfill('0') << setw(2); + unsigned long sec = transcoder->get_duration () / transcoder->get_fps (); + osstream << setfill ('0') << setw (2); osstream << (sec / 3600) << ":"; - osstream << setfill('0') << setw(2); - osstream << ((sec /60 )%60) << ":"; - osstream << setfill('0') << setw(2); - osstream << (sec%60) << ":"; - osstream << setfill('0') << setw(2); - osstream << (transcoder->get_duration() % (int) floor(transcoder->get_fps())); + osstream << setfill ('0') << setw (2); + osstream << ((sec / 60) % 60) << ":"; + osstream << setfill ('0') << setw (2); + osstream << (sec % 60) << ":"; + osstream << setfill ('0') << setw (2); + osstream << (transcoder->get_duration () % (int)floor (transcoder->get_fps ())); } - l = manage (new Label (osstream.str(), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + l = manage (new Label (osstream.str (), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); t->attach (*l, 3, 4, 0, 1); - osstream.str(""); - osstream << transcoder->get_codec(); - l = manage (new Label (osstream.str(), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); + osstream.str (""); + osstream << transcoder->get_codec (); + l = manage (new Label (osstream.str (), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); t->attach (*l, 1, 2, 1, 2); } @@ -184,36 +184,36 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) options_box->pack_start (*l, false, true, 4); if (ffok) { - video_combo.append_text(_("Reference from Current Location (Previously Transcoded Files Only)")); - video_combo.append_text(_("Import/Transcode Video to Session")); - video_combo.set_active(1); - if (as.size() > 0) { - video_combo.append_text(_("Do Not Import Video (Audio Import Only)")); - audio_combo.set_sensitive(true); + video_combo.append_text (_("Reference from Current Location (Previously Transcoded Files Only)")); + video_combo.append_text (_("Import/Transcode Video to Session")); + video_combo.set_active (1); + if (as.size () > 0) { + video_combo.append_text (_("Do Not Import Video (Audio Import Only)")); + audio_combo.set_sensitive (true); } else { - audio_combo.set_sensitive(false); + audio_combo.set_sensitive (false); } - video_combo.set_sensitive(true); - transcode_button.set_sensitive(true); + video_combo.set_sensitive (true); + transcode_button.set_sensitive (true); path_entry.set_sensitive (true); browse_button.set_sensitive (true); - } else if (as.size() > 0) { - video_combo.append_text(_("Do Not Import Video (Audio Import Only)")); - video_combo.set_active(0); + } else if (as.size () > 0) { + video_combo.append_text (_("Do Not Import Video (Audio Import Only)")); + video_combo.set_active (0); path_entry.set_text (""); - video_combo.set_sensitive(false); - audio_combo.set_sensitive(true); - transcode_button.set_sensitive(true); + video_combo.set_sensitive (false); + audio_combo.set_sensitive (true); + transcode_button.set_sensitive (true); path_entry.set_sensitive (false); browse_button.set_sensitive (false); } else { - video_combo.append_text(_("Do Not Import Video")); - video_combo.set_active(0); + video_combo.append_text (_("Do Not Import Video")); + video_combo.set_active (0); path_entry.set_text (""); - video_combo.set_sensitive(false); - audio_combo.set_sensitive(false); - transcode_button.set_sensitive(false); + video_combo.set_sensitive (false); + audio_combo.set_sensitive (false); + transcode_button.set_sensitive (false); path_entry.set_sensitive (false); browse_button.set_sensitive (false); } @@ -230,20 +230,42 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) t->attach (aspect_checkbox, 2, 3, 0, 1); t->attach (height_spinner, 3, 4, 0, 1); - scale_combo.append_text(_("Original Width")); - if (w > 1920) { scale_combo.append_text("1920 (hd1080)"); } - if (w > 1408) { scale_combo.append_text("1408 (16cif)"); } - if (w > 1280) { scale_combo.append_text("1280 (sxga, hd720)"); } - if (w > 1024) { scale_combo.append_text("1024 (xga)"); } - if (w > 852) { scale_combo.append_text(" 852 (hd480)"); } - if (w > 768) { scale_combo.append_text(" 768 (PAL)"); } - if (w > 720) { scale_combo.append_text(" 720 (PAL)"); } - if (w > 640) { scale_combo.append_text(" 640 (vga, ega)"); } - if (w > 352) { scale_combo.append_text(" 352 (cif)"); } - if (w > 320) { scale_combo.append_text(" 320 (cga, qvga)"); } - if (w > 176) { scale_combo.append_text(" 176 (qcif)"); } - scale_combo.set_active(0); - height_spinner.set_value(h); + scale_combo.append_text (_("Original Width")); + if (w > 1920) { + scale_combo.append_text ("1920 (hd1080)"); + } + if (w > 1408) { + scale_combo.append_text ("1408 (16cif)"); + } + if (w > 1280) { + scale_combo.append_text ("1280 (sxga, hd720)"); + } + if (w > 1024) { + scale_combo.append_text ("1024 (xga)"); + } + if (w > 852) { + scale_combo.append_text (" 852 (hd480)"); + } + if (w > 768) { + scale_combo.append_text (" 768 (PAL)"); + } + if (w > 720) { + scale_combo.append_text (" 720 (PAL)"); + } + if (w > 640) { + scale_combo.append_text (" 640 (vga, ega)"); + } + if (w > 352) { + scale_combo.append_text (" 352 (cif)"); + } + if (w > 320) { + scale_combo.append_text (" 320 (cga, qvga)"); + } + if (w > 176) { + scale_combo.append_text (" 176 (qcif)"); + } + scale_combo.set_active (0); + height_spinner.set_value (h); l = manage (new Label (_("Bitrate (KBit/s):"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false)); t->attach (*l, 0, 1, 1, 2); @@ -254,52 +276,52 @@ TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile) t->attach (*l, 0, 1, 2, 3); t->attach (audio_combo, 1, 4, 2, 3); t->attach (ltc_detect, 1, 4, 3, 4); - if (as.size() == 0) { - audio_combo.append_text(_("No Audio Track Present")); - audio_combo.set_sensitive(false); + + if (as.size () == 0) { + audio_combo.append_text (_("No Audio Track Present")); + audio_combo.set_sensitive (false); } else { - audio_combo.append_text(_("Do Not Extract Audio")); - for (TranscodeFfmpeg::FFAudioStreams::iterator it = as.begin(); it < as.end(); ++it) { - audio_combo.append_text((*it).name); + audio_combo.append_text (_("Do Not Extract Audio")); + for (TranscodeFfmpeg::FFAudioStreams::iterator it = as.begin (); it < as.end (); ++it) { + audio_combo.append_text ((*it).name); } } - audio_combo.set_active(0); + audio_combo.set_active (0); ltc_detect.set_sensitive (false); -#if 1 /* tentative debug mode */ options_box->pack_start (debug_checkbox, false, true, 4); -#endif vbox->pack_start (*path_hbox, false, false); vbox->pack_start (*options_box, false, true); - get_vbox()->set_spacing (4); - get_vbox()->pack_start (*vbox, false, false); + get_vbox ()->set_spacing (4); + get_vbox ()->pack_start (*vbox, false, false); progress_box = manage (new VBox); - progress_box->set_spacing(6); + progress_box->set_spacing (6); progress_box->pack_start (progress_label, false, false); progress_box->pack_start (pbar, false, false); progress_box->pack_start (abort_button, false, false); - get_vbox()->pack_start (*progress_box, false, false); + get_vbox ()->pack_start (*progress_box, false, false); - browse_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::open_browse_dialog)); - transcode_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_transcode)); - abort_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::abort_clicked)); + browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::open_browse_dialog)); + transcode_button.signal_clicked ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_transcode)); + abort_button.signal_clicked ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::abort_clicked)); - video_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::video_combo_changed)); - audio_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::audio_combo_changed)); - scale_combo.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::scale_combo_changed)); - aspect_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::aspect_checkbox_toggled)); - height_spinner.signal_changed().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::update_bitrate)); - bitrate_checkbox.signal_toggled().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::bitrate_checkbox_toggled)); + video_combo.signal_changed ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::video_combo_changed)); + audio_combo.signal_changed ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::audio_combo_changed)); + scale_combo.signal_changed ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::scale_combo_changed)); + aspect_checkbox.signal_toggled ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::aspect_checkbox_toggled)); + height_spinner.signal_changed ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::update_bitrate)); + bitrate_checkbox.signal_toggled ().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::bitrate_checkbox_toggled)); - update_bitrate(); + update_bitrate (); cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL); - get_action_area()->pack_start (transcode_button, false, false); + get_action_area ()->pack_start (transcode_button, false, false); + show_all_children (); - progress_box->hide(); + progress_box->hide (); } TranscodeVideoDialog::~TranscodeVideoDialog () @@ -317,34 +339,37 @@ void TranscodeVideoDialog::abort_clicked () { aborted = true; - transcoder->cancel(); + transcoder->cancel (); } void TranscodeVideoDialog::update_progress (samplecnt_t c, samplecnt_t a) { if (a == 0 || c > a) { - pbar.set_pulse_step(.5); - pbar.pulse(); + pbar.set_pulse_step (.5); + pbar.pulse (); return; } - pbar.set_fraction ((double)c / (double) a); + pbar.set_fraction ((double)c / (double)a); } void -TranscodeVideoDialog::finished () +TranscodeVideoDialog::finished (int status) { - if (aborted) { - ::g_unlink(path_entry.get_text().c_str()); - if (!audiofile.empty()) { - ::g_unlink(audiofile.c_str()); + if (aborted || status != 0) { + if (!aborted) { + ARDOUR_UI::instance ()->popup_error (_("Video transcoding failed.")); } - Gtk::Dialog::response(RESPONSE_CANCEL); + ::g_unlink (path_entry.get_text ().c_str ()); + if (!audiofile.empty ()) { + ::g_unlink (audiofile.c_str ()); + } + Gtk::Dialog::response (RESPONSE_CANCEL); } else { if (pending_audio_extract) { - StartNextStage(); + StartNextStage (); /* EMIT SIGNAL */ } else { - Gtk::Dialog::response(RESPONSE_ACCEPT); + Gtk::Dialog::response (RESPONSE_ACCEPT); } } } @@ -352,35 +377,33 @@ TranscodeVideoDialog::finished () void TranscodeVideoDialog::launch_audioonly () { - if (audio_combo.get_active_row_number() == 0) { - finished(); + if (audio_combo.get_active_row_number () == 0) { + finished (0); return; } - dialog_progress_mode(); -#if 1 /* tentative debug mode */ - if (debug_checkbox.get_active()) { - transcoder->set_debug(true); + dialog_progress_mode (); + if (debug_checkbox.get_active ()) { + transcoder->set_debug (true); } -#endif - transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress , this, _1, _2), gui_context()); - transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context()); - launch_extract(); + transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ()); + transcoder->Finished.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this, _1), gui_context ()); + launch_extract (); } void TranscodeVideoDialog::launch_extract () { - audiofile= path_entry.get_text() + ".wav"; /* TODO: mktemp */ - int audio_stream; + audiofile = path_entry.get_text () + ".wav"; /* TODO: mktemp */ pending_audio_extract = false; - aborted = false; - audio_stream = audio_combo.get_active_row_number() -1; + aborted = false; + int audio_stream = audio_combo.get_active_row_number () - 1; + progress_label.set_text (_("Extracting Audio..")); - if (!transcoder->extract_audio(audiofile, _session->nominal_sample_rate(), audio_stream)) { - ARDOUR_UI::instance()->popup_error(_("Audio Extraction Failed.")); - audiofile=""; - Gtk::Dialog::response(RESPONSE_CANCEL); + if (!transcoder->extract_audio (audiofile, _session->nominal_sample_rate (), audio_stream)) { + ARDOUR_UI::instance ()->popup_error (_("Audio Extraction Failed.")); + audiofile = ""; + Gtk::Dialog::response (RESPONSE_CANCEL); return; } } @@ -388,58 +411,57 @@ TranscodeVideoDialog::launch_extract () void TranscodeVideoDialog::dialog_progress_mode () { - vbox->hide(); - cancel_button->hide(); - transcode_button.hide(); - pbar.set_size_request(300,-1); - progress_box->show(); + vbox->hide (); + cancel_button->hide (); + transcode_button.hide (); + pbar.set_size_request (300, -1); + progress_box->show (); } void TranscodeVideoDialog::launch_transcode () { - if (video_combo.get_active_row_number() != 1) { - launch_audioonly(); + if (video_combo.get_active_row_number () != 1) { + launch_audioonly (); return; } - std::string outfn = path_entry.get_text(); - if (!confirm_video_outfn(*this, outfn, video_get_docroot(Config))) return; + std::string outfn = path_entry.get_text (); + if (!confirm_video_outfn (*this, outfn, video_get_docroot (Config))) + return; progress_label.set_text (_("Transcoding Video..")); - dialog_progress_mode(); -#if 1 /* tentative debug mode */ - if (debug_checkbox.get_active()) { - transcoder->set_debug(true); + dialog_progress_mode (); + if (debug_checkbox.get_active ()) { + transcoder->set_debug (true); } -#endif aborted = false; - if (audio_combo.get_active_row_number() != 0) { + if (audio_combo.get_active_row_number () != 0) { pending_audio_extract = true; - StartNextStage.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::launch_extract , this), gui_context()); + StartNextStage.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::launch_extract, this), gui_context ()); } int scale_width, scale_height, bitrate; - if (scale_combo.get_active_row_number() == 0 ) { - scale_width =0; + if (scale_combo.get_active_row_number () == 0) { + scale_width = 0; } else { - scale_width = atoi(scale_combo.get_active_text()); + scale_width = atoi (scale_combo.get_active_text ()); } - if (!aspect_checkbox.get_active()) { + if (!aspect_checkbox.get_active ()) { scale_height = 0; } else { - scale_height = (int) floor(height_spinner.get_value()); + scale_height = (int)floor (height_spinner.get_value ()); } - if (bitrate_checkbox.get_active() ){ - bitrate = (int) floor(bitrate_spinner.get_value()); + if (bitrate_checkbox.get_active ()) { + bitrate = (int)floor (bitrate_spinner.get_value ()); } else { bitrate = 0; } - transcoder->Progress.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress , this, _1, _2), gui_context()); - transcoder->Finished.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this), gui_context()); - if (!transcoder->transcode(outfn, scale_width, scale_height, bitrate)) { - ARDOUR_UI::instance()->popup_error(_("Transcoding Failed.")); - Gtk::Dialog::response(RESPONSE_CANCEL); + transcoder->Progress.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::update_progress, this, _1, _2), gui_context ()); + transcoder->Finished.connect (*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::finished, this, _1), gui_context ()); + if (!transcoder->transcode (outfn, scale_width, scale_height, bitrate)) { + ARDOUR_UI::instance ()->popup_error (_("Transcoding Failed.")); + Gtk::Dialog::response (RESPONSE_CANCEL); return; } } @@ -447,22 +469,22 @@ TranscodeVideoDialog::launch_transcode () void TranscodeVideoDialog::video_combo_changed () { - const int i = video_combo.get_active_row_number(); + const int i = video_combo.get_active_row_number (); if (i != 1) { - scale_combo.set_sensitive(false); - aspect_checkbox.set_sensitive(false); - height_spinner.set_sensitive(false); - bitrate_checkbox.set_sensitive(false); - bitrate_spinner.set_sensitive(false); + scale_combo.set_sensitive (false); + aspect_checkbox.set_sensitive (false); + height_spinner.set_sensitive (false); + bitrate_checkbox.set_sensitive (false); + bitrate_spinner.set_sensitive (false); } else { - scale_combo.set_sensitive(true); - aspect_checkbox.set_sensitive(true); - height_spinner.set_sensitive(true); - bitrate_checkbox.set_sensitive(true); - bitrate_spinner.set_sensitive(true); + scale_combo.set_sensitive (true); + aspect_checkbox.set_sensitive (true); + height_spinner.set_sensitive (true); + bitrate_checkbox.set_sensitive (true); + bitrate_spinner.set_sensitive (true); } - if (i == 2 && audio_combo.get_active_row_number() == 0) { - audio_combo.set_active(1); + if (i == 2 && audio_combo.get_active_row_number () == 0) { + audio_combo.set_active (1); } else { //update LTC option sensitivity audio_combo_changed (); @@ -472,17 +494,13 @@ TranscodeVideoDialog::video_combo_changed () void TranscodeVideoDialog::audio_combo_changed () { - if (video_combo.get_active_row_number() == 2 - && audio_combo.get_active_row_number() == 0) - { - audio_combo.set_active(1); + if (video_combo.get_active_row_number () == 2 && audio_combo.get_active_row_number () == 0) { + audio_combo.set_active (1); ltc_detect.set_sensitive (false); ltc_detect.set_active (false); } - if (video_combo.get_active_row_number() != 2 - && audio_combo.get_active_row_number() > 0) - { + if (video_combo.get_active_row_number () != 2 && audio_combo.get_active_row_number () > 0) { ltc_detect.set_sensitive (true); } else { ltc_detect.set_sensitive (false); @@ -493,31 +511,31 @@ TranscodeVideoDialog::audio_combo_changed () void TranscodeVideoDialog::scale_combo_changed () { - if (!aspect_checkbox.get_active()) { + if (!aspect_checkbox.get_active ()) { int h; - if (scale_combo.get_active_row_number() == 0 ) { - h = transcoder->get_height(); + if (scale_combo.get_active_row_number () == 0) { + h = transcoder->get_height (); } else { - h = floor(atof(scale_combo.get_active_text()) / m_aspect); + h = floor (atof (scale_combo.get_active_text ()) / m_aspect); } - height_spinner.set_value(h); + height_spinner.set_value (h); } - update_bitrate(); + update_bitrate (); } void TranscodeVideoDialog::aspect_checkbox_toggled () { - height_spinner.set_sensitive(aspect_checkbox.get_active()); - scale_combo_changed(); + height_spinner.set_sensitive (aspect_checkbox.get_active ()); + scale_combo_changed (); } void TranscodeVideoDialog::bitrate_checkbox_toggled () { - bitrate_spinner.set_sensitive(bitrate_checkbox.get_active()); - if (!bitrate_checkbox.get_active()) { - update_bitrate(); + bitrate_spinner.set_sensitive (bitrate_checkbox.get_active ()); + if (!bitrate_checkbox.get_active ()) { + update_bitrate (); } } @@ -525,43 +543,46 @@ void TranscodeVideoDialog::update_bitrate () { double br = .7; /* avg quality - bits per pixel */ - if (bitrate_checkbox.get_active() || !transcoder->probe_ok()) { return; } - br *= transcoder->get_fps(); - br *= height_spinner.get_value(); + if (bitrate_checkbox.get_active () || !transcoder->probe_ok ()) { + return; + } + br *= transcoder->get_fps (); + br *= height_spinner.get_value (); - if (scale_combo.get_active_row_number() == 0 ) { - br *= transcoder->get_width(); + if (scale_combo.get_active_row_number () == 0) { + br *= transcoder->get_width (); } else { - br *= atof(scale_combo.get_active_text()); + br *= atof (scale_combo.get_active_text ()); } if (br != 0) { - bitrate_spinner.set_value(floor(br/10000.0)*10); + bitrate_spinner.set_value (floor (br / 10000.0) * 10); } } void TranscodeVideoDialog::open_browse_dialog () { - Gtk::FileChooserDialog dialog(_("Save Transcoded Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE); - dialog.set_filename (path_entry.get_text()); + Gtk::FileChooserDialog dialog (_("Save Transcoded Video File"), Gtk::FILE_CHOOSER_ACTION_SAVE); + dialog.set_filename (path_entry.get_text ()); Gtkmm2ext::add_volume_shortcuts (dialog); - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); + dialog.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); - int result = dialog.run(); + int result = dialog.run (); if (result == Gtk::RESPONSE_OK) { - std::string filename = dialog.get_filename(); + std::string filename = dialog.get_filename (); - if (filename.length()) { + if (filename.length ()) { path_entry.set_text (filename); } } } enum VtlTranscodeOption -TranscodeVideoDialog::import_option() { - int i = video_combo.get_active_row_number(); - return static_cast(i); +TranscodeVideoDialog::import_option () +{ + int i = video_combo.get_active_row_number (); + return static_cast (i); } diff --git a/gtk2_ardour/transcode_video_dialog.h b/gtk2_ardour/transcode_video_dialog.h index e1ceec9d7e..b4efdb44d9 100644 --- a/gtk2_ardour/transcode_video_dialog.h +++ b/gtk2_ardour/transcode_video_dialog.h @@ -25,38 +25,51 @@ #include #include #include -#include #include +#include #include #include -#include "ardour/types.h" #include "ardour/template_utils.h" +#include "ardour/types.h" #include "ardour_dialog.h" #include "transcode_ffmpeg.h" enum VtlTranscodeOption { - VTL_IMPORT_REFERENCE = 0, - VTL_IMPORT_TRANSCODED = 1, - VTL_IMPORT_NO_VIDEO = 2 + VTL_IMPORT_REFERENCE = 0, + VTL_IMPORT_TRANSCODED = 1, + VTL_IMPORT_NO_VIDEO = 2 }; /** @class TranscodeVideoDialog * @brief dialog-box and controller for importing video-files */ -class TranscodeVideoDialog : public ArdourDialog , public PBD::ScopedConnectionList +class TranscodeVideoDialog : public ArdourDialog, public PBD::ScopedConnectionList { public: TranscodeVideoDialog (ARDOUR::Session*, std::string); ~TranscodeVideoDialog (); - std::string get_filename () { return path_entry.get_text(); } - std::string get_audiofile () { return audiofile; } VtlTranscodeOption import_option (); - bool detect_ltc () { return ltc_detect.get_active (); } - void on_response (int response_id) { + std::string get_filename () + { + return path_entry.get_text (); + } + + std::string get_audiofile () + { + return audiofile; + } + + bool detect_ltc () + { + return ltc_detect.get_active (); + } + + void on_response (int response_id) + { Gtk::Dialog::on_response (response_id); } @@ -74,29 +87,30 @@ private: void launch_transcode (); void launch_extract (); void dialog_progress_mode (); - bool aborted; - bool pending_audio_extract; - std::string audiofile; - std::string infn; - double m_aspect; - - PBD::Signal0 StartNextStage; - void finished (); + void finished (int); void update_progress (ARDOUR::samplecnt_t, ARDOUR::samplecnt_t); - TranscodeFfmpeg *transcoder; + bool aborted; + bool pending_audio_extract; + std::string audiofile; + std::string infn; + double m_aspect; - Gtk::Label path_label; - Gtk::Entry path_entry; - Gtk::Button browse_button; - Gtk::Button transcode_button; + PBD::Signal0 StartNextStage; - Gtk::VBox* vbox; - Gtk::Button *cancel_button; - Gtk::Button abort_button; + TranscodeFfmpeg* transcoder; - Gtk::VBox* progress_box; - Gtk::Label progress_label; + Gtk::Label path_label; + Gtk::Entry path_entry; + Gtk::Button browse_button; + Gtk::Button transcode_button; + + Gtk::VBox* vbox; + Gtk::Button* cancel_button; + Gtk::Button abort_button; + + Gtk::VBox* progress_box; + Gtk::Label progress_label; Gtk::ProgressBar pbar; Gtk::ComboBoxText video_combo; @@ -109,10 +123,7 @@ private: Gtk::CheckButton bitrate_checkbox; Gtk::Adjustment bitrate_adjustment; Gtk::SpinButton bitrate_spinner; -#if 1 /* tentative debug mode */ Gtk::CheckButton debug_checkbox; -#endif - }; #endif /* __gtk_ardour_transcode_video_dialog_h__ */