summaryrefslogtreecommitdiff
path: root/gtk2_ardour/add_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/add_video_dialog.cc
parentd91565093965b3405774acd878b3baf38839f4e4 (diff)
videotimline
squashed 694 commits from http://gareus.org/gitweb/?p=ardour3.git
Diffstat (limited to 'gtk2_ardour/add_video_dialog.cc')
-rw-r--r--gtk2_ardour/add_video_dialog.cc584
1 files changed, 584 insertions, 0 deletions
diff --git a/gtk2_ardour/add_video_dialog.cc b/gtk2_ardour/add_video_dialog.cc
new file mode 100644
index 0000000000..3e9b3d3b08
--- /dev/null
+++ b/gtk2_ardour/add_video_dialog.cc
@@ -0,0 +1,584 @@
+/*
+ Copyright (C) 2010-2013 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 <cmath>
+
+#include <sigc++/bind.h>
+#include <curl/curl.h>
+
+#include "pbd/error.h"
+#include "pbd/convert.h"
+#include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/rgb_macros.h"
+#include "ardour/session_directory.h"
+#include "ardour/profile.h"
+#include "ardour/template_utils.h"
+#include "ardour/session.h"
+#include "ardour_ui.h"
+
+#include "utils.h"
+#include "add_video_dialog.h"
+#include "utils_videotl.h"
+#include "i18n.h"
+
+using namespace Gtk;
+using namespace std;
+using namespace PBD;
+using namespace ARDOUR;
+
+#define PREVIEW_WIDTH (240)
+#define PREVIEW_HEIGHT (180)
+
+#ifndef MIN
+#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
+#endif
+
+AddVideoDialog::AddVideoDialog (Session* s)
+ : ArdourDialog (_("Set Video Track"))
+ , seek_slider (0,1000,1)
+ , preview_path ("")
+ , pi_duration ("-", Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false)
+ , pi_aspect ("-", Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false)
+ , pi_fps ("-", Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false)
+ , chooser (FILE_CHOOSER_ACTION_OPEN)
+ , xjadeo_checkbox (_("Launch External Video Monitor"))
+ , set_session_fps_checkbox (_("Adjust Session Framerate to Match Video Framerate"))
+ , harvid_path ("")
+ , harvid_reset (_("Reload docroot"))
+ , harvid_list (ListStore::create(harvid_list_columns))
+ , harvid_list_view (harvid_list)
+{
+ set_session (s);
+ set_name ("AddVideoDialog");
+ set_position (Gtk::WIN_POS_MOUSE);
+ set_modal (true);
+ set_skip_taskbar_hint (true);
+ set_resizable (true);
+ set_size_request (800, -1);
+
+ harvid_initialized = false;
+ std::string dstdir = video_dest_dir(_session->session_directory().video_path(), Config->get_video_server_docroot());
+
+
+ /* Harvid Browser */
+ harvid_list_view.append_column("", pixBufRenderer);
+ harvid_list_view.append_column(_("Filename"), harvid_list_columns.filename);
+
+ harvid_list_view.get_column(0)->set_alignment(0.5);
+ harvid_list_view.get_column(0)->add_attribute(pixBufRenderer, "stock-id", harvid_list_columns.id);
+ harvid_list_view.get_column(1)->set_expand(true);
+ harvid_list_view.get_column(1)->set_sort_column(harvid_list_columns.filename);
+ harvid_list_view.set_enable_search(true);
+ harvid_list_view.set_search_column(1);
+
+
+ //Glib::RefPtr<Gtk::TreeModelSort> refTreeModelSort = Gtk::TreeModelSort::create(harvid_list_view.get_model());
+ //refTreeModelSort->set_sort_column(harvid_list_columns.filename, Gtk::SORT_ASCENDING);
+ //harvid_list_view.set_model(refTreeModelSort);
+
+ harvid_list_view.get_selection()->set_mode (SELECTION_SINGLE);
+
+ harvid_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &AddVideoDialog::harvid_list_view_selected));
+ harvid_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &AddVideoDialog::harvid_list_view_activated));
+
+ VBox* vbox = manage (new VBox);
+ Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
+ scroll->add(harvid_list_view);
+ scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+
+ HBox* hbox = manage (new HBox);
+ harvid_path.set_alignment (0, 0.5);
+ hbox->pack_start (harvid_path, true, true);
+ hbox->pack_start (harvid_reset, false, false);
+
+ vbox->pack_start (*hbox, false, false);
+ vbox->pack_start (*scroll, true, true);
+
+ notebook.append_page (*vbox, _("VideoServerIndex"));
+
+
+
+ /* file chooser */
+ chooser.set_border_width (4);
+#ifdef GTKOSX
+ /* some broken redraw behaviour - this is a bandaid */
+ chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
+#endif
+ chooser.set_current_folder (dstdir);
+
+ Gtk::FileFilter video_filter;
+ Gtk::FileFilter matchall_filter;
+ video_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &AddVideoDialog::on_video_filter));
+ video_filter.set_name (_("Video files"));
+
+ matchall_filter.add_pattern ("*.*");
+ matchall_filter.set_name (_("All files"));
+
+ chooser.add_filter (video_filter);
+ chooser.add_filter (matchall_filter);
+ chooser.set_select_multiple (false);
+
+ /* file import options */
+ import_combo.set_name ("PaddedButton");
+ import_combo.append_text(_("Reference From Current Location"));
+ import_combo.append_text(_("Hardlink or Copy to Session"));
+ import_combo.append_text(_("Transcode to Session"));
+ import_combo.set_active(2);
+
+ vbox = manage (new VBox);
+ vbox->pack_start (chooser, true, true, 0);
+ vbox->pack_start (import_combo, false, true, 4);
+
+ if (Config->get_video_server_docroot().size() > 0) {
+ notebook.append_page (*vbox, _("Browse Files"));
+ }
+
+ /* Global Options*/
+ Gtk::Label* l;
+ VBox* options_box = manage (new VBox);
+
+ 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);
+ options_box->pack_start (xjadeo_checkbox, false, true, 2);
+ options_box->pack_start (set_session_fps_checkbox, false, true, 2);
+
+ /* preview pane */
+ VBox* previewpane = manage (new VBox);
+ Gtk::Table *table = manage(new Table(4,2));
+
+ table->set_row_spacings(2);
+ table->set_col_spacings(4);
+
+ l = manage (new Label (_("<b>Video Information</b>"), Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, false));
+ l->set_use_markup ();
+ table->attach (*l, 0, 2, 0, 1, FILL, FILL);
+ l = manage (new Label (_("Duration:"), Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false));
+ table->attach (*l, 0, 1, 1, 2, FILL, FILL);
+ table->attach (pi_duration, 1, 2, 1, 2, FILL, FILL);
+ l = manage (new Label (_("Frame rate:"), Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false));
+ table->attach (*l, 0, 1, 2, 3, FILL, FILL);
+ table->attach (pi_fps, 1, 2, 2, 3, FILL, FILL);
+ l = manage (new Label (_("Aspect Ratio:"), Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER, false));
+ table->attach (*l, 0, 1, 3, 4, FILL, FILL);
+ table->attach (pi_aspect, 1, 2, 3, 4, FILL, FILL);
+
+ preview_image = manage(new Gtk::Image);
+
+ imgbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, true, 8, PREVIEW_WIDTH, PREVIEW_HEIGHT);
+ imgbuf->fill(RGBA_TO_UINT(127,0,0,255));
+ preview_image->set(imgbuf);
+ seek_slider.set_draw_value(false);
+
+ hbox = manage (new HBox);
+ hbox->pack_start (*table, true, false);
+
+ Gtk::Alignment *al = manage(new Gtk::Alignment());
+ al->set_size_request(-1, 20);
+
+ previewpane->pack_start (*al, false, false);
+ previewpane->pack_start (*hbox, true, true, 6);
+ previewpane->pack_start (*preview_image, false, false);
+ previewpane->pack_start (seek_slider, false, false);
+
+ /* Overall layout */
+ hbox = manage (new HBox);
+ hbox->pack_start (notebook, true, true);
+ hbox->pack_start (*previewpane, false, false);
+
+ get_vbox()->set_spacing (4);
+ get_vbox()->pack_start (*hbox, true, true);
+ get_vbox()->pack_start (*options_box, false, false);
+
+
+ /* xjadeo checkbox */
+ if (ARDOUR_UI::instance()->video_timeline->found_xjadeo()
+ /* TODO xjadeo setup w/ xjremote */
+ && Config->get_video_server_docroot().size() > 0) {
+ xjadeo_checkbox.set_active(true); /* set in ardour_ui.cpp ?! */
+ } else {
+ xjadeo_checkbox.set_active(false);
+ xjadeo_checkbox.set_sensitive(false);
+ }
+
+ /* FPS checkbox */
+ set_session_fps_checkbox.set_active(true);
+
+ /* Buttons */
+ add_button (Stock::CANCEL, RESPONSE_CANCEL);
+ ok_button = add_button (Stock::OK, RESPONSE_ACCEPT);
+ //ok_button->set_sensitive(false);
+ set_action_ok(false);
+
+ /* connect signals after eveything has been initialized */
+ chooser.signal_selection_changed().connect (mem_fun (*this, &AddVideoDialog::file_selection_changed));
+ chooser.signal_file_activated().connect (mem_fun (*this, &AddVideoDialog::file_activated));
+ //chooser.signal_update_preview().connect(sigc::mem_fun(*this, &AddVideoDialog::update_preview));
+ notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &AddVideoDialog::page_switch)))));
+ seek_slider.signal_value_changed().connect(sigc::mem_fun(*this, &AddVideoDialog::seek_preview));
+ harvid_reset.signal_clicked().connect (sigc::mem_fun (*this, &AddVideoDialog::harvid_load_docroot));
+
+ show_all_children ();
+}
+
+AddVideoDialog::~AddVideoDialog ()
+{
+}
+
+void
+AddVideoDialog::on_show ()
+{
+ Dialog::on_show ();
+}
+
+static bool check_video_file_extension(std::string file)
+{
+ const char* suffixes[] = {
+ ".avi" , ".AVI" ,
+ ".mov" , ".MOV" ,
+ ".ogg" , ".OGG" ,
+ ".ogv" , ".OGV" ,
+ ".mpg" , ".MPG" ,
+ ".mov" , ".MOV" ,
+ ".mp4" , ".MP4" ,
+ ".mkv" , ".MKV" ,
+ ".vob" , ".VOB" ,
+ ".asf" , ".ASF" ,
+ ".avs" , ".AVS" ,
+ ".dts" , ".DTS" ,
+ ".flv" , ".FLV" ,
+ ".m4v" , ".M4V" ,
+ ".matroska", ".MATROSKA",
+ ".h264" , ".H264" ,
+ ".dv" , ".DV" ,
+ ".dirac" , ".DIRAC" ,
+ ".webm" , ".WEBM" ,
+ };
+
+ for (size_t n = 0; n < sizeof(suffixes)/sizeof(suffixes[0]); ++n) {
+ if (file.rfind (suffixes[n]) == file.length() - strlen (suffixes[n])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+AddVideoDialog::on_video_filter (const FileFilter::Info& filter_info)
+{
+ return check_video_file_extension(filter_info.filename);
+}
+
+std::string
+AddVideoDialog::file_name (bool &local_file)
+{
+ int n = notebook.get_current_page ();
+ if (n == 1) {
+ local_file = true;
+ return chooser.get_filename();
+ } else {
+ local_file = false;
+ Gtk::TreeModel::iterator iter = harvid_list_view.get_selection()->get_selected();
+ if(!iter) return "";
+ return (*iter)[harvid_list_columns.uri];
+ }
+}
+
+enum VtlImportOption
+AddVideoDialog::import_option ()
+{
+ int n = notebook.get_current_page ();
+ if (n == 0) { return VTL_IMPORT_NONE; }
+ int i = import_combo.get_active_row_number();
+ return static_cast<VtlImportOption>(i);
+}
+
+bool
+AddVideoDialog::launch_xjadeo ()
+{
+ return xjadeo_checkbox.get_active();
+}
+
+bool
+AddVideoDialog::auto_set_session_fps ()
+{
+ return set_session_fps_checkbox.get_active();
+}
+
+void
+AddVideoDialog::set_action_ok (bool yn)
+{
+ if (yn) {
+ ok_button->set_sensitive(true);
+ } else {
+ preview_path = "";
+ pi_duration.set_text("-");
+ pi_aspect.set_text("-");
+ pi_fps.set_text("-");
+ ok_button->set_sensitive(false);
+ imgbuf->fill(RGBA_TO_UINT(0,0,0,255));
+ video_draw_cross(imgbuf);
+ preview_image->set(imgbuf);
+ preview_image->show();
+ }
+}
+
+void
+AddVideoDialog::file_selection_changed ()
+{
+ if (chooser.get_filename().size() > 0) {
+ std::string path = chooser.get_filename();
+ bool ok =
+ check_video_file_extension(path)
+ && Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_REGULAR | Glib::FILE_TEST_IS_SYMLINK)
+ && !Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR);
+ set_action_ok(ok);
+ if (ok) {
+ request_preview(video_map_path(Config->get_video_server_docroot(), path));
+ }
+ } else {
+ set_action_ok(false);
+ }
+}
+
+void
+AddVideoDialog::file_activated ()
+{
+ if (chooser.get_filename().size() > 0) {
+ std::string path = chooser.get_filename();
+ // TODO check docroot -> set import options
+ bool ok =
+ check_video_file_extension(path)
+ && Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_REGULAR | Glib::FILE_TEST_IS_SYMLINK)
+ && !Glib::file_test(path.c_str(), Glib::FILE_TEST_IS_DIR);
+ if (ok) {
+ Gtk::Dialog::response(RESPONSE_ACCEPT);
+ }
+ }
+}
+
+/**** Tree List Interaction ***/
+
+void
+AddVideoDialog::harvid_list_view_selected () {
+ Gtk::TreeModel::iterator iter = harvid_list_view.get_selection()->get_selected();
+ // TODO check docroot -> set import options, xjadeo
+ if(!iter) {
+ set_action_ok(false);
+ return;
+ }
+ if ((std::string)((*iter)[harvid_list_columns.id]) == Stock::DIRECTORY.id) {
+ set_action_ok(false);
+ } else {
+ set_action_ok(true);
+ request_preview((*iter)[harvid_list_columns.uri]);
+ }
+}
+
+void
+AddVideoDialog::harvid_list_view_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn*) {
+ Gtk::TreeModel::iterator iter = harvid_list->get_iter(path);
+ if (!iter) return;
+ std::string type = (*iter)[harvid_list_columns.id];
+ std::string url = (*iter)[harvid_list_columns.uri];
+
+#if 0
+ printf ("A: %s %s %s\n",
+ ((std::string)((*iter)[harvid_list_columns.id])).c_str(),
+ ((std::string)((*iter)[harvid_list_columns.uri])).c_str(),
+ ((std::string)((*iter)[harvid_list_columns.filename])).c_str());
+#endif
+
+ if (type == Gtk::Stock::DIRECTORY.id) {
+ harvid_request(url.c_str());
+ } else {
+ Gtk::Dialog::response(RESPONSE_ACCEPT);
+ }
+}
+
+void
+AddVideoDialog::harvid_load_docroot() {
+ set_action_ok(false);
+
+ std::string video_server_url = Config->get_video_server_url();
+ char url[2048];
+ snprintf(url, sizeof(url), "%s%sindex/"
+ , video_server_url.c_str()
+ , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/");
+ harvid_request(url);
+ harvid_initialized = true;
+}
+
+bool
+AddVideoDialog::page_switch() {
+ if (notebook.get_current_page () == 1) {
+ file_selection_changed();
+ return true;
+ }
+
+ if (harvid_initialized) {
+ harvid_list_view_selected();
+ } else {
+ harvid_load_docroot();
+ }
+ return true;
+}
+
+/**** Harvid HTTP interface ***/
+void
+AddVideoDialog::harvid_request(std::string u)
+{
+ char url[2048];
+ int status;
+ snprintf(url, sizeof(url), "%s?format=csv", u.c_str());
+
+ harvid_list->clear();
+
+ char *res = curl_http_get(url, &status);
+ if (status != 200) {
+ printf("request failed\n"); // XXX
+ harvid_path.set_text(" - request failed -");
+ free(res);
+ return;
+ }
+
+ /* add up-to-parent */
+ size_t se = u.find_last_of("/", u.size()-2);
+ size_t ss = u.find("/index/");
+ if (se != string::npos && ss != string::npos && se > ss) {
+ TreeModel::iterator new_row = harvid_list->append();
+ TreeModel::Row row = *new_row;
+ row[harvid_list_columns.id ] = Gtk::Stock::DIRECTORY.id;
+ row[harvid_list_columns.uri ] = u.substr(0, se + 1);
+ row[harvid_list_columns.filename] = X_("..");
+ }
+ if (se != string::npos) {
+ int plen;
+ std::string path = u.substr(ss + 6);
+ CURL *curl;
+ curl = curl_easy_init();
+ char *ue = curl_easy_unescape(curl, path.c_str(), path.length(), &plen);
+ harvid_path.set_text(std::string(ue));
+ curl_easy_cleanup(curl);
+ curl_free(ue);
+ } else {
+ harvid_path.set_text(" ??? ");
+ }
+
+ if (!res) return;
+
+ std::vector<std::vector<std::string> > lines;
+ ParseCSV(std::string(res), lines);
+ for (std::vector<std::vector<std::string> >::iterator i = lines.begin(); i != lines.end(); ++i) {
+ TreeModel::iterator new_row = harvid_list->append();
+ TreeModel::Row row = *new_row;
+
+ if (i->at(0) == X_("D")) {
+ row[harvid_list_columns.id ] = Gtk::Stock::DIRECTORY.id;
+ row[harvid_list_columns.uri ] = i->at(1).c_str();
+ row[harvid_list_columns.filename] = i->at(2).c_str();
+ } else {
+ row[harvid_list_columns.id ] = Gtk::Stock::MEDIA_PLAY.id;
+ row[harvid_list_columns.uri ] = i->at(2).c_str();
+ row[harvid_list_columns.filename] = i->at(3).c_str();
+ }
+ }
+
+ free(res);
+}
+
+void
+AddVideoDialog::seek_preview()
+{
+ if (preview_path.size() > 0)
+ request_preview(preview_path);
+}
+
+void
+AddVideoDialog::request_preview(std::string u)
+{
+ std::string video_server_url = Config->get_video_server_url();
+
+ double video_file_fps;
+ long long int video_duration;
+ double video_start_offset;
+ double video_aspect_ratio;
+
+ int clip_width = PREVIEW_WIDTH;
+ int clip_height = PREVIEW_HEIGHT;
+ int clip_xoff, clip_yoff;
+
+ if (!video_query_info(video_server_url, u,
+ video_file_fps, video_duration, video_start_offset, video_aspect_ratio))
+ {
+ printf("image preview info request failed\n");
+ // set_action_ok(false); // XXX only if docroot mismatch
+ preview_path = "";
+ pi_duration.set_text("-");
+ pi_aspect.set_text("-");
+ pi_fps.set_text("-");
+ return;
+ }
+
+ if ((PREVIEW_WIDTH / (double)PREVIEW_HEIGHT) > video_aspect_ratio ) {
+ clip_width = MIN(PREVIEW_WIDTH, rint(clip_height * video_aspect_ratio));
+ } else {
+ clip_height = MIN(PREVIEW_HEIGHT, rint(clip_width / video_aspect_ratio));
+ }
+
+ pi_duration.set_text(string_compose("%1 sec", video_duration / video_file_fps));
+ pi_aspect.set_text(string_compose("%1", video_aspect_ratio));
+ pi_fps.set_text(string_compose("%1 fps", video_file_fps));
+
+ clip_xoff = (PREVIEW_WIDTH - clip_width)/2;
+ clip_yoff = (PREVIEW_HEIGHT - clip_height)/2;
+
+ char url[2048];
+ snprintf(url, sizeof(url), "%s%s?frame=%lli&w=%d&h=%di&file=%s&format=rgb"
+ , video_server_url.c_str()
+ , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/"
+ , (long long) (video_duration * seek_slider.get_value() / 1000.0)
+ , clip_width, clip_height, u.c_str());
+
+ char *data = curl_http_get(url, NULL);
+ if (!data) {
+ printf("image preview request failed %s\n", url);
+ imgbuf->fill(RGBA_TO_UINT(0,0,0,255));
+ video_draw_cross(imgbuf);
+ preview_path = "";
+ } else {
+ Glib::RefPtr<Gdk::Pixbuf> tmp;
+ tmp = Gdk::Pixbuf::create_from_data ((guint8*) data, Gdk::COLORSPACE_RGB, false, 8, clip_width, clip_height, clip_width*3);
+ if (clip_width != PREVIEW_WIDTH || clip_height != PREVIEW_HEIGHT) {
+ imgbuf->fill(RGBA_TO_UINT(0,0,0,255));
+ }
+ tmp->copy_area (0, 0, clip_width, clip_height, imgbuf, clip_xoff, clip_yoff);
+ preview_path = u;
+ free(data);
+ }
+ preview_image->set(imgbuf);
+ preview_image->show();
+}
+
+#endif /* WITH_VIDEOTIMELINE */