X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fvideo_monitor.cc;h=d6831e45b744e6f232a17fda759f156cac53dec8;hb=d6b5c23579dc02d2f98fc1f48bf038c1070057fb;hp=5bc6bb67771439c59c7f42dd03bdd50b9540953e;hpb=55a10480945f2a41fe6cfda2173bed12d3d5bc89;p=ardour.git diff --git a/gtk2_ardour/video_monitor.cc b/gtk2_ardour/video_monitor.cc index 5bc6bb6777..d6831e45b7 100644 --- a/gtk2_ardour/video_monitor.cc +++ b/gtk2_ardour/video_monitor.cc @@ -17,26 +17,29 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifdef WITH_VIDEOTIMELINE - #include "pbd/file_utils.h" +#include "pbd/convert.h" #include "gui_thread.h" -#include "ardour_ui.h" +#include "timers.h" +#include "utils.h" #include #include "public_editor.h" +#include "editor.h" #include "video_monitor.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; +using namespace PBD; +using namespace ARDOUR_UI_UTILS; VideoMonitor::VideoMonitor (PublicEditor *ed, std::string xjadeo_bin_path) : editor (ed) { manually_seeked_frame = 0; fps =0.0; // = _session->timecode_frames_per_second(); - sync_by_manual_seek = false; + sync_by_manual_seek = true; _restore_settings_mask = 0; clock_connection = sigc::connection(); state_connection = sigc::connection(); @@ -45,9 +48,10 @@ VideoMonitor::VideoMonitor (PublicEditor *ed, std::string xjadeo_bin_path) starting = 0; osdmode = 10; // 1: frameno, 2: timecode, 8: box - process = new SystemExec(xjadeo_bin_path, X_("-R")); + process = new ARDOUR::SystemExec(xjadeo_bin_path, X_("-R -J")); process->ReadStdout.connect_same_thread (*this, boost::bind (&VideoMonitor::parse_output, this, _1 ,_2)); process->Terminated.connect (*this, invalidator (*this), boost::bind (&VideoMonitor::terminated, this), gui_context()); + XJKeyEvent.connect (*this, invalidator (*this), boost::bind (&VideoMonitor::forward_keyevent, this, _1), gui_context()); } VideoMonitor::~VideoMonitor () @@ -79,11 +83,9 @@ VideoMonitor::start () } void -VideoMonitor::quit () +VideoMonitor::query_full_state (bool wait) { - if (!is_started()) return; - if (state_connection.connected()) { state_connection.disconnect(); } - if (clock_connection.connected()) { clock_connection.disconnect(); } + knownstate = 0; process->write_to_stdin("get windowsize\n"); process->write_to_stdin("get windowpos\n"); process->write_to_stdin("get letterbox\n"); @@ -91,24 +93,33 @@ VideoMonitor::quit () process->write_to_stdin("get ontop\n"); process->write_to_stdin("get offset\n"); process->write_to_stdin("get osdcfg\n"); + int timeout = 40; + if (wait && knownstate !=127 && --timeout) { + Glib::usleep(50000); + sched_yield(); + } +} + +void +VideoMonitor::quit () +{ + if (!is_started()) return; + if (state_connection.connected()) { state_connection.disconnect(); } + if (clock_connection.connected()) { clock_connection.disconnect(); } + query_full_state(true); process->write_to_stdin("quit\n"); -#if 1 - /* wait for replies to the config requests above. - * the 'quit' command should result in process termination + /* the 'quit' command should result in process termination * but in case it fails (communication failure, SIGSTOP, ??) * here's a timeout.. */ int timeout = 40; while (is_started() && --timeout) { - usleep(50000); + Glib::usleep(50000); sched_yield(); } if (timeout <= 0) { - printf("xjadeo connection: time-out. session may not be saved.\n"); process->terminate(); } -#endif - save_session(); } void @@ -117,14 +128,26 @@ VideoMonitor::open (std::string filename) if (!is_started()) return; manually_seeked_frame = 0; osdmode = 10; // 1: frameno, 2: timecode, 8: box - sync_by_manual_seek = false; starting = 15; process->write_to_stdin("load " + filename + "\n"); process->write_to_stdin("set fps -1\n"); process->write_to_stdin("window resize 100%\n"); process->write_to_stdin("window ontop on\n"); process->write_to_stdin("set seekmode 1\n"); - process->write_to_stdin("set override 47\n"); + /* override bitwise flags -- see xjadeo.h + * 0x0001 : ignore 'q', ESC / quit + * 0x0002 : ignore "window closed by WM" / quit + * 0x0004 : (osx only) menu-exit / quit + * 0x0008 : ignore mouse-button 1 -- resize + * 0x0010 : no A/V offset control with keyboard + * 0x0020 : don't use jack-session + * 0x0040 : disable jack transport control + * 0x0080 : disallow sync source change (OSX menu) + * 0x0100 : disallow file open (OSX menu, X11 DnD) + */ + process->write_to_stdin("set override 504\n"); + process->write_to_stdin("notify keyboard\n"); + process->write_to_stdin("notify settings\n"); process->write_to_stdin("window letterbox on\n"); process->write_to_stdin("osd mode 10\n"); for(XJSettings::const_iterator it = xjadeo_settings.begin(); it != xjadeo_settings.end(); ++it) { @@ -136,8 +159,10 @@ VideoMonitor::open (std::string filename) querystate(); state_clk_divide = 0; /* TODO once every two second or so -- state_clk_divide hack below */ - state_connection = ARDOUR_UI::RapidScreenUpdate.connect (sigc::mem_fun (*this, &VideoMonitor::querystate)); + state_connection = Timers::rapid_connect (sigc::mem_fun (*this, &VideoMonitor::querystate)); } + sync_by_manual_seek = true; + clock_connection = Timers::fps_connect (sigc::mem_fun (*this, &VideoMonitor::srsupdate)); xjadeo_sync_setup(); } @@ -145,9 +170,16 @@ void VideoMonitor::querystate () { /* clock-divider hack -- RapidScreenUpdate == every_point_one_seconds */ - state_clk_divide = (state_clk_divide + 1) % 15; // every 1.5 seconds - if (state_clk_divide != 0) return; - + state_clk_divide = (state_clk_divide + 1) % 300; // 30 secs + if (state_clk_divide == 0) { + // every 30 seconds + query_full_state(false); + return; + } + if (state_clk_divide%25 != 0) { + return; + } + // every 2.5 seconds: process->write_to_stdin("get fullscreen\n"); process->write_to_stdin("get ontop\n"); process->write_to_stdin("get osdcfg\n"); @@ -172,6 +204,7 @@ void VideoMonitor::send_cmd (int what, int param) { bool osd_update = false; + int prev_osdmode = osdmode; if (!is_started()) return; switch (what) { case 1: @@ -181,17 +214,17 @@ VideoMonitor::send_cmd (int what, int param) case 2: if (param) osdmode |= 2; else osdmode &= ~2; - osd_update = true; + osd_update = (prev_osdmode != osdmode); break; case 3: if (param) osdmode |= 1; else osdmode &= ~1; - osd_update = true; + osd_update = (prev_osdmode != osdmode); break; case 4: if (param) osdmode |= 8; else osdmode &= ~8; - osd_update = true; + osd_update = (prev_osdmode != osdmode); break; case 5: if (param) process->write_to_stdin("window zoom on\n"); @@ -207,7 +240,7 @@ VideoMonitor::send_cmd (int what, int param) default: break; } - if (osd_update >= 0) { + if (osd_update) { std::ostringstream osstream; osstream << "osd mode " << osdmode << "\n"; process->write_to_stdin(osstream.str()); } @@ -220,7 +253,13 @@ VideoMonitor::is_started () } void -VideoMonitor::parse_output (std::string d, size_t s) +VideoMonitor::forward_keyevent (unsigned int keyval) +{ + emulate_key_event (keyval); +} + +void +VideoMonitor::parse_output (std::string d, size_t /*s*/) { std::string line = d; std::string::size_type start = 0; @@ -237,7 +276,7 @@ VideoMonitor::parse_output (std::string d, size_t s) printf("xjadeo: '%s'\n", line.c_str()); } #endif - int status = atoi(line.substr(1,3).c_str()); + int status = atoi(line.substr(1,3)); switch(status / 100) { case 4: /* errors */ if (status == 403) { @@ -247,8 +286,41 @@ VideoMonitor::parse_output (std::string d, size_t s) */ process->write_to_stdin("quit\n"); } - case 1: /* requested async notifications */ - case 3: /* warnings ; command succeeded, but status is negative. */ +#ifdef DEBUG_XJCOM + else + printf("xjadeo: error '%s'\n", line.c_str()); +#endif + break; + case 3: /* async notifications */ + { + std::string::size_type equalsign = line.find('='); + std::string::size_type comment = line.find('#'); + if (comment != std::string::npos) { line = line.substr(0,comment); } + if (equalsign != std::string::npos) { + std::string key = line.substr(5, equalsign - 5); + std::string value = line.substr(equalsign + 1); + + if (status == 310 && key=="keypress") { + /* keyboard event */ + XJKeyEvent((unsigned int)atoi(value)); + } +#ifdef DEBUG_XJCOM + else { + std::string msg = line.substr(5); + printf("xjadeo: async '%s' -> '%s'\n", key, value); + } +#endif + } +#ifdef DEBUG_XJCOM + else { + std::string msg = line.substr(5); + printf("xjadeo: async '%s'\n", msg.c_str()); + } +#endif + } break; + case 1: /* text messages - command reply */ + break; + case 8: /* comments / info for humans */ break; case 2: /* replies: @@ -268,35 +340,50 @@ VideoMonitor::parse_output (std::string d, size_t s) #if 0 /* DEBUG */ std::cout << "parsed: " << key << " => " << value << std::endl; #endif - if(key == "windowpos") { + if (key == "windowpos") { + knownstate |= 16; + if (xjadeo_settings["window xy"] != value) { + if (!starting && _session) _session->set_dirty (); + } xjadeo_settings["window xy"] = value; } else if(key == "windowsize") { + knownstate |= 32; + if (xjadeo_settings["window size"] != value) { + if (!starting && _session) _session->set_dirty (); + } xjadeo_settings["window size"] = value; } else if(key == "windowontop") { + knownstate |= 2; if (starting || xjadeo_settings["window ontop"] != value) { - starting &= ~2; - if (atoi(value.c_str())) { UiState("xjadeo-window-ontop-on"); } + if (!starting && _session) _session->set_dirty (); + if (atoi(value)) { UiState("xjadeo-window-ontop-on"); } else { UiState("xjadeo-window-ontop-off"); } + starting &= ~2; } xjadeo_settings["window ontop"] = value; } else if(key == "fullscreen") { + knownstate |= 4; if (starting || xjadeo_settings["window zoom"] != value) { - starting &= ~4; - if (atoi(value.c_str())) { UiState("xjadeo-window-fullscreen-on"); } + if (!starting && _session) _session->set_dirty (); + if (atoi(value)) { UiState("xjadeo-window-fullscreen-on"); } else { UiState("xjadeo-window-fullscreen-off"); } + starting &= ~4; } xjadeo_settings["window zoom"] = value; } else if(key == "letterbox") { + knownstate |= 8; if (starting || xjadeo_settings["window letterbox"] != value) { - starting &= ~8; - if (atoi(value.c_str())) { UiState("xjadeo-window-letterbox-on"); } + if (!starting && _session) _session->set_dirty (); + if (atoi(value)) { UiState("xjadeo-window-letterbox-on"); } else { UiState("xjadeo-window-letterbox-off"); } + starting &= ~8; } xjadeo_settings["window letterbox"] = value; } else if(key == "osdmode") { - if (starting || xjadeo_settings["osd mode"] != value) { - starting &= ~1; - osdmode = atoi(value.c_str()); + knownstate |= 1; + osdmode = atoi(value); + if (starting || atoi(xjadeo_settings["osd mode"]) != osdmode) { + if (!starting && _session) _session->set_dirty (); if ((osdmode & 1) == 1) { UiState("xjadeo-window-osd-frame-on"); } if ((osdmode & 1) == 0) { UiState("xjadeo-window-osd-frame-off"); } if ((osdmode & 2) == 2) { UiState("xjadeo-window-osd-timecode-on"); } @@ -304,9 +391,18 @@ VideoMonitor::parse_output (std::string d, size_t s) if ((osdmode & 8) == 8) { UiState("xjadeo-window-osd-box-on"); } if ((osdmode & 8) == 0) { UiState("xjadeo-window-osd-box-off"); } } + starting &= ~1; xjadeo_settings["osd mode"] = value; } else if(key == "offset") { + knownstate |= 64; + if (xjadeo_settings["set offset"] != value) { + if (!starting && _session) _session->set_dirty (); + } xjadeo_settings["set offset"] = value; +#ifdef DEBUG_XJCOM + } else { + printf("xjadeo: '%s' -> '%s'\n", key.c_str(), value.c_str()); +#endif } } } @@ -321,7 +417,6 @@ void VideoMonitor::terminated () { process->terminate(); // from gui-context clean up - save_session(); Terminated(); } @@ -329,35 +424,14 @@ void VideoMonitor::save_session () { if (!_session) { return; } - bool is_dirty = false; - - XMLNode* prev = _session->extra_xml (X_("XJSettings")); - XMLNode* node = new XMLNode(X_("XJSettings")); - XMLNodeList nlist; - if (!prev) { is_dirty = true; } - else { nlist = prev->children(); } + XMLNode* node = _session->extra_xml (X_("XJSettings"), true); + if (!node) return; + node->remove_nodes_and_delete("XJSetting"); for(XJSettings::const_iterator it = xjadeo_settings.begin(); it != xjadeo_settings.end(); ++it) { XMLNode* child = node->add_child (X_("XJSetting")); - child->add_property (X_("k"), it->first); - child->add_property (X_("v"), it->second); - if (!is_dirty) { - bool found = false; - XMLNodeConstIterator i; - for (i = nlist.begin(); i != nlist.end(); ++i) { - if ((*i)->property(X_("k"))->value() == it->first && - (*i)->property(X_("v"))->value() == it->second ) { - found=true; - break; - } - } - if (!found) {is_dirty = true;} - } - } - - if (is_dirty) { - _session->add_extra_xml (*node); - _session->set_dirty (); + child->set_property (X_("k"), it->first); + child->set_property (X_("v"), it->second); } } @@ -367,6 +441,7 @@ VideoMonitor::set_session (ARDOUR::Session *s) { SessionHandlePtr::set_session (s); if (!_session) { return; } + ARDOUR::Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&VideoMonitor::parameter_changed, this, _1), gui_context()); _session->config.ParameterChanged.connect (*this, invalidator (*this), ui_bind (&VideoMonitor::parameter_changed, this, _1), gui_context()); XMLNode* node = _session->extra_xml (X_("XJSettings")); if (!node) { return;} @@ -379,16 +454,6 @@ VideoMonitor::set_session (ARDOUR::Session *s) } } -void -VideoMonitor::clear_session_state () -{ - xjadeo_settings.clear(); - if (!_session) { return; } - XMLNode* node = new XMLNode(X_("XJSettings")); - _session->add_extra_xml (*node); - _session->set_dirty (); -} - bool VideoMonitor::set_custom_setting (const std::string k, const std::string v) { @@ -402,60 +467,62 @@ VideoMonitor::get_custom_setting (const std::string k) return (xjadeo_settings[k]); } -#define NO_OFFSET (1<<31) //< skip setting or modifying offset -- TODO check ARDOUR::frameoffset_t max value. +#define NO_OFFSET (Temporal::max_samplepos) //< skip setting or modifying offset void VideoMonitor::srsupdate () { if (!_session) { return; } if (editor->dragging_playhead()) { return ;} - manual_seek(_session->audible_frame(), false, NO_OFFSET); + manual_seek(_session->audible_sample(), false, NO_OFFSET); } void -VideoMonitor::set_offset (ARDOUR::frameoffset_t offset) +VideoMonitor::set_offset (ARDOUR::sampleoffset_t offset) { if (!is_started()) { return; } if (!_session) { return; } if (offset == NO_OFFSET ) { return; } - framecnt_t video_frame_offset; - framecnt_t audio_frame_rate; + samplecnt_t video_frame_offset; + samplecnt_t audio_sample_rate; if (_session->config.get_videotimeline_pullup()) { - audio_frame_rate = _session->frame_rate(); + audio_sample_rate = _session->sample_rate(); } else { - audio_frame_rate = _session->nominal_frame_rate(); + audio_sample_rate = _session->nominal_sample_rate(); } - /* Note: pull-up/down are applied here: frame_rate() vs. nominal_frame_rate() */ + /* Note: pull-up/down are applied here: sample_rate() vs. nominal_sample_rate() */ if (_session->config.get_use_video_file_fps()) { - video_frame_offset = floor(offset * fps / audio_frame_rate); + video_frame_offset = floor(offset * fps / audio_sample_rate); } else { - video_frame_offset = floor(offset * _session->timecode_frames_per_second() / audio_frame_rate); + video_frame_offset = floor(offset * _session->timecode_frames_per_second() / audio_sample_rate); } - // TODO remember if changed.. + if (video_offset == video_frame_offset) { return; } + video_offset = video_frame_offset; + std::ostringstream osstream1; osstream1 << -1 * video_frame_offset; process->write_to_stdin("set offset " + osstream1.str() + "\n"); } void -VideoMonitor::manual_seek (framepos_t when, bool force, ARDOUR::frameoffset_t offset) +VideoMonitor::manual_seek (samplepos_t when, bool /*force*/, ARDOUR::sampleoffset_t offset) { if (!is_started()) { return; } if (!_session) { return; } - framecnt_t video_frame; - framecnt_t audio_frame_rate; + samplecnt_t video_frame; + samplecnt_t audio_sample_rate; if (_session->config.get_videotimeline_pullup()) { - audio_frame_rate = _session->frame_rate(); + audio_sample_rate = _session->sample_rate(); } else { - audio_frame_rate = _session->nominal_frame_rate(); + audio_sample_rate = _session->nominal_sample_rate(); } - /* Note: pull-up/down are applied here: frame_rate() vs. nominal_frame_rate() */ + /* Note: pull-up/down are applied here: sample_rate() vs. nominal_sample_rate() */ if (_session->config.get_use_video_file_fps()) { - video_frame = floor(when * fps / audio_frame_rate); + video_frame = floor(when * fps / audio_sample_rate); } else { - video_frame = floor(when * _session->timecode_frames_per_second() / audio_frame_rate); + video_frame = floor(when * _session->timecode_frames_per_second() / audio_sample_rate); } if (video_frame < 0 ) video_frame = 0; @@ -489,9 +556,8 @@ VideoMonitor::xjadeo_sync_setup () if (!_session) { return; } bool my_manual_seek = true; - if (_session->config.get_external_sync()) { - if (ARDOUR::Config->get_sync_source() == ARDOUR::JACK) - my_manual_seek = false; + if (_session->synced_to_engine ()) { + my_manual_seek = false; } if (my_manual_seek != sync_by_manual_seek) { @@ -502,9 +568,8 @@ VideoMonitor::xjadeo_sync_setup () process->write_to_stdin("jack connect\n"); } else { process->write_to_stdin("jack disconnect\n"); - clock_connection = ARDOUR_UI::SuperRapidScreenUpdate.connect (sigc::mem_fun (*this, &VideoMonitor::srsupdate)); + clock_connection = Timers::fps_connect (sigc::mem_fun (*this, &VideoMonitor::srsupdate)); } sync_by_manual_seek = my_manual_seek; } } -#endif /* WITH_VIDEOTIMELINE */