summaryrefslogtreecommitdiff
path: root/gtk2_ardour/transcode_video_dialog.cc
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2013-03-12 22:00:09 +0100
committerRobin Gareus <robin@gareus.org>2013-03-13 20:28:15 +0100
commit0c3e840700a915fc1476cef73c591048f688f81e (patch)
tree3241845f899cfed86217db2f6f589740b2b9c04a /gtk2_ardour/transcode_video_dialog.cc
parentd91565093965b3405774acd878b3baf38839f4e4 (diff)
videotimline
squashed 694 commits from http://gareus.org/gitweb/?p=ardour3.git
Diffstat (limited to 'gtk2_ardour/transcode_video_dialog.cc')
-rw-r--r--gtk2_ardour/transcode_video_dialog.cc524
1 files changed, 524 insertions, 0 deletions
diff --git a/gtk2_ardour/transcode_video_dialog.cc b/gtk2_ardour/transcode_video_dialog.cc
new file mode 100644
index 0000000000..8d927b915e
--- /dev/null
+++ b/gtk2_ardour/transcode_video_dialog.cc
@@ -0,0 +1,524 @@
+/*
+ Copyright (C) 2010 Paul Davis
+ Author: Robin Gareus <robin@gareus.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+#ifdef WITH_VIDEOTIMELINE
+
+#include <cstdio>
+#include <string>
+#include <sstream>
+#include <iomanip>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <sigc++/bind.h>
+#include <libgen.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_ui.h"
+#include "gui_thread.h"
+
+#include "utils.h"
+#include "opts.h"
+#include "transcode_video_dialog.h"
+#include "video_copy_dialog.h"
+#include "utils_videotl.h"
+#include "i18n.h"
+
+using namespace Gtk;
+using namespace std;
+using namespace PBD;
+using namespace ARDOUR;
+
+TranscodeVideoDialog::TranscodeVideoDialog (Session* s, std::string infile)
+ : ArdourDialog (_("Transcode/Import Video File "))
+ , infn (infile)
+ , path_label (_("Output File:"), Gtk::ALIGN_LEFT)
+ , browse_button (_("Browse"))
+ , transcode_button (_("Transcode Video\n And Import"))
+ , copy_button (_("Copy Video\nFile Only"))
+ , audio_button (_("Extract and\nImport Audio Only"))
+ , abort_button (_("Abort"))
+ , progress_label ()
+ , aspect_checkbox (_("Height = "))
+ , height_adjustment (128, 0, 1920, 1, 16, 0)
+ , height_spinner (height_adjustment)
+ , bitrate_checkbox (_("Manual Override"))
+ , bitrate_adjustment (2000, 100, 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 = "";
+ pending_audio_extract = false;
+ pending_copy_file = false;
+
+ set_name ("TranscodeVideoDialog");
+ set_position (Gtk::WIN_POS_MOUSE);
+ set_modal (true);
+ set_skip_taskbar_hint (true);
+ set_resizable (false);
+
+ Gtk::Label* l;
+ vbox = manage (new VBox);
+ VBox* options_box = manage (new VBox);
+ HBox* path_hbox = manage (new HBox);
+
+ int w = 0, h = 0;
+ m_aspect = 4.0/3.0;
+ AudioStreams as; as.clear();
+
+ 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);
+ browse_button.set_name ("PaddedButton");
+
+ path_entry.set_width_chars(38);
+ height_spinner.set_sensitive(false);
+ bitrate_spinner.set_sensitive(false);
+
+ std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
+ std::string dstfn = video_dest_file(dstdir, infile);
+ path_entry.set_text (dstfn);
+
+ l = manage (new Label (_("<b>Info</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ l->set_use_markup ();
+ options_box->pack_start (*l, false, true, 4);
+
+
+ if (!transcoder->ffexec_ok()) {
+ l = manage (new Label (_("No ffprobe or ffmpeg executables could be found on this system. Transcoding is not possible until you install those tools."), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ l->set_line_wrap();
+ options_box->pack_start (*l, false, true, 4);
+ transcode_button.set_sensitive(false);
+ aspect_checkbox.set_sensitive(false);
+ bitrate_checkbox.set_sensitive(false);
+ }
+ else if (!transcoder->probe_ok()) {
+ l = manage (new Label (string_compose(_("Video file-info could not be read. Most likely '%1' is not a valid video-file. It could also be a rare unsupported video codec or format."), infn), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ options_box->pack_start (*l, false, true, 4);
+ transcode_button.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();
+
+ Table* t = manage (new Table (4, 2));
+ t->set_spacings (4);
+ options_box->pack_start (*t, true, true, 4);
+ l = manage (new Label (_("FPS:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 0, 1, 0, 1);
+ l = manage (new Label (_("Duration:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 2, 3, 0, 1);
+ l = manage (new Label (_("Codec:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 0, 1, 1, 2);
+ l = manage (new Label (_("Geometry:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ 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));
+ t->attach (*l, 1, 2, 0, 1);
+
+ osstream.str("");
+ osstream << w << "x" << h;
+ l = manage (new Label (osstream.str(), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 3, 4, 1, 2);
+
+ osstream.str("");
+ unsigned long sec = transcoder->get_duration() / transcoder->get_fps();
+ if (sec == 0) {
+ osstream << _("??");
+ } else {
+ 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()));
+ }
+ 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));
+ t->attach (*l, 1, 2, 1, 2);
+ }
+
+ l = manage (new Label (_("<b>Options</b>"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ l->set_use_markup ();
+ options_box->pack_start (*l, false, true, 4);
+
+ Table* t = manage (new Table (4, 3));
+ t->set_spacings (4);
+ options_box->pack_start (*t, true, true, 4);
+
+ l = manage (new Label (_("Scale Video: Width = "), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 0, 1, 0, 1);
+ scale_combo.set_name ("PaddedButton");
+ t->attach (scale_combo, 1, 2, 0, 1);
+ 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);
+
+ l = manage (new Label (_("Bitrate (KBit/s):"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 0, 1, 1, 2);
+ t->attach (bitrate_checkbox, 2, 3, 1, 2);
+ t->attach (bitrate_spinner, 3, 4, 1, 2);
+
+ l = manage (new Label (_("Extract Audio:"), Gtk::ALIGN_LEFT, Gtk::ALIGN_CENTER, false));
+ t->attach (*l, 0, 1, 2, 3);
+ audio_combo.set_name ("PaddedButton");
+ t->attach (audio_combo, 1, 4, 2, 3);
+ audio_combo.append_text("No audio");
+ if (as.size() > 0) {
+ for (AudioStreams::iterator it = as.begin(); it < as.end(); ++it) {
+ audio_combo.append_text((*it).name);
+ }
+ }
+ audio_combo.set_active(0);
+
+#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);
+
+ progress_box = manage (new VBox);
+ 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);
+
+ browse_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::open_browse_dialog));
+ copy_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::prepare_copy));
+ audio_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_audioonly));
+ transcode_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::launch_transcode));
+ abort_button.signal_clicked().connect (sigc::mem_fun (*this, &TranscodeVideoDialog::abort_clicked));
+
+ 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();
+
+ audio_button.set_sensitive(false);
+
+ cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
+ get_action_area()->pack_start (audio_button, false, false);
+ get_action_area()->pack_start (copy_button, false, false);
+ get_action_area()->pack_start (transcode_button, false, false);
+ show_all_children ();
+ progress_box->hide();
+}
+
+TranscodeVideoDialog::~TranscodeVideoDialog ()
+{
+ delete transcoder;
+}
+
+void
+TranscodeVideoDialog::on_show ()
+{
+ Dialog::on_show ();
+}
+
+void
+TranscodeVideoDialog::abort_clicked ()
+{
+ aborted = true;
+ transcoder->cancel();
+}
+
+void
+TranscodeVideoDialog::update_progress (framecnt_t c, framecnt_t a)
+{
+ if (a == 0 || c > a) {
+ pbar.set_pulse_step(.5);
+ pbar.pulse();
+ return;
+ }
+ pbar.set_fraction ((double)c / (double) a);
+}
+
+void
+TranscodeVideoDialog::finished ()
+{
+ if (aborted) {
+ unlink(path_entry.get_text().c_str());
+ if (!audiofile.empty()) {
+ unlink(audiofile.c_str());
+ }
+ Gtk::Dialog::response(RESPONSE_CANCEL);
+ } else {
+ if (pending_audio_extract || pending_copy_file) {
+ StartNextStage();
+ } else {
+ Gtk::Dialog::response(RESPONSE_ACCEPT);
+ }
+ }
+}
+
+void
+TranscodeVideoDialog::prepare_copy ()
+{
+ dialog_progress_mode();
+#if 1 /* tentative debug mode */
+ if (debug_checkbox.get_active()) {
+ transcoder->set_debug(true);
+ }
+#endif
+
+ if (audio_combo.get_active_row_number() == 0) {
+ launch_copy();
+ } else {
+ aborted = false;
+ pending_copy_file = true;
+ StartNextStage.connect(*this, invalidator (*this), boost::bind (&TranscodeVideoDialog::launch_copy , this), gui_context());
+ 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();
+ }
+}
+
+void
+TranscodeVideoDialog::launch_audioonly ()
+{
+ dialog_progress_mode();
+ path_entry.set_text("");
+#if 1 /* tentative debug mode */
+ if (debug_checkbox.get_active()) {
+ transcoder->set_debug(true);
+ }
+#endif
+ if (audio_combo.get_active_row_number() == 0) {
+ return;
+ }
+ 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();
+}
+
+void
+TranscodeVideoDialog::launch_copy ()
+{
+ hide();
+ VideoCopyDialog *video_copy_dialog;
+ video_copy_dialog = new VideoCopyDialog(_session, infn);
+ video_copy_dialog->setup_non_interactive_copy(path_entry.get_text());
+ ResponseType r = (ResponseType) video_copy_dialog->run ();
+ video_copy_dialog->hide();
+ delete video_copy_dialog;
+ Gtk::Dialog::response(r);
+}
+
+void
+TranscodeVideoDialog::launch_extract ()
+{
+ audiofile= path_entry.get_text() + ".wav"; /* TODO: mktemp & check if file exists in audiofiles */
+ /* think: do_embed() vs do_import() - editor_videotimeline.cc
+ * directly use _session->session_directory().sound_path() ?!
+ */
+ int audio_stream;
+ pending_audio_extract = false;
+ aborted = false;
+ audio_stream = audio_combo.get_active_row_number() -1;
+ progress_label.set_text (_("Extracting Audio.."));
+
+ if (!transcoder->extract_audio(audiofile, _session->nominal_frame_rate(), audio_stream)) {
+ ARDOUR_UI::instance()->popup_error(_("Audio Extraction Failed."));
+ audiofile="";
+ Gtk::Dialog::response(RESPONSE_CANCEL);
+ return;
+ }
+}
+
+void
+TranscodeVideoDialog::dialog_progress_mode ()
+{
+ vbox->hide();
+ cancel_button->hide();
+ copy_button.hide();
+ transcode_button.hide();
+ pbar.set_size_request(300,-1);
+ progress_box->show();
+}
+
+void
+TranscodeVideoDialog::launch_transcode ()
+{
+ std::string outfn = path_entry.get_text();
+ if (!confirm_video_outfn(outfn, Config->get_video_server_docroot())) return;
+ progress_label.set_text (_("Transcoding Video.."));
+ dialog_progress_mode();
+#if 1 /* tentative debug mode */
+ if (debug_checkbox.get_active()) {
+ transcoder->set_debug(true);
+ }
+#endif
+
+ aborted = false;
+ 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());
+ }
+
+ int scale_width, scale_height, bitrate;
+ if (scale_combo.get_active_row_number() == 0 ) {
+ scale_width =0;
+ } else {
+ scale_width = atoi(scale_combo.get_active_text().c_str());
+ }
+ if (!aspect_checkbox.get_active()) {
+ scale_height = 0;
+ } else {
+ scale_height = (int) floor(height_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);
+ return;
+ }
+}
+
+void
+TranscodeVideoDialog::audio_combo_changed ()
+{
+ bool use_audio = audio_combo.get_active_row_number() != 0;
+ audio_button.set_sensitive(use_audio);
+ if (use_audio) {
+ copy_button.set_label(_("Copy File And\nExtract Audio"));
+ } else {
+ copy_button.set_label(_("Copy Video\nFile Only"));
+ }
+}
+
+void
+TranscodeVideoDialog::scale_combo_changed ()
+{
+ update_bitrate();
+ if (!aspect_checkbox.get_active()) {
+ int h;
+ if (scale_combo.get_active_row_number() == 0 ) {
+ h = transcoder->get_height();
+ } else {
+ h = floor(atof(scale_combo.get_active_text().c_str()) / m_aspect);
+ }
+ height_spinner.set_value(h);
+ }
+}
+
+void
+TranscodeVideoDialog::aspect_checkbox_toggled ()
+{
+ 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();
+ }
+}
+
+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 (scale_combo.get_active_row_number() == 0 ) {
+ br *= transcoder->get_height();
+ } else {
+ br *= atof(scale_combo.get_active_text().c_str());
+ }
+ 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());
+
+ dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+ int result = dialog.run();
+
+ if (result == Gtk::RESPONSE_OK) {
+ std::string filename = dialog.get_filename();
+
+ if (filename.length()) {
+ path_entry.set_text (filename);
+ }
+ }
+}
+
+#endif /* WITH_VIDEOTIMELINE */