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 "utils.h"
#include <stdio.h>
#include "public_editor.h"
+#include "editor.h"
#include "video_monitor.h"
#include "i18n.h"
using namespace std;
+using namespace PBD;
VideoMonitor::VideoMonitor (PublicEditor *ed, std::string xjadeo_bin_path)
: editor (ed)
sync_by_manual_seek = false;
_restore_settings_mask = 0;
clock_connection = sigc::connection();
+ state_connection = sigc::connection();
debug_enable = false;
+ state_clk_divide = 0;
+ starting = 0;
+ osdmode = 10; // 1: frameno, 2: timecode, 8: box
- process = new SystemExec(xjadeo_bin_path);
- process->ReadStdout.connect (*this, invalidator (*this), boost::bind (&VideoMonitor::parse_output, this, _1 ,_2), gui_context());
+ process = new SystemExec(xjadeo_bin_path, X_("-R"));
+ 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 ()
if (clock_connection.connected()) {
clock_connection.disconnect();
}
+ if (state_connection.connected()) {
+ state_connection.disconnect();
+ }
delete process;
}
}
void
-VideoMonitor::quit ()
+VideoMonitor::query_full_state (bool wait)
{
- if (!is_started()) return;
+ knownstate = 0;
process->write_to_stdin("get windowsize\n");
process->write_to_stdin("get windowpos\n");
process->write_to_stdin("get letterbox\n");
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");
+ if (timeout <= 0) {
+ process->terminate();
}
-#endif
- process->terminate();
- if (clock_connection.connected()) { clock_connection.disconnect(); }
}
void
{
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
+ * 0x01 : ignore 'q', ESC / quite
+ * 0x02 : ignore "window closed by WM" / quit
+ * 0x04 : (osx only) menu-exit / quit
+ * 0x08 : ignore mouse-button 1 -- resize
+ * 0x10 : no A/V offset
+ * 0x20 : don't use jack-session
+ * 0x40 : no jack-transport control play/pause/rewind
+ */
+ process->write_to_stdin("set override 120\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) {
if (skip_setting(it->first)) { continue; }
process->write_to_stdin(it->first + " " + it->second + "\n");
}
+ if (!state_connection.connected()) {
+ starting = 15;
+ 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));
+ }
xjadeo_sync_setup();
}
+void
+VideoMonitor::querystate ()
+{
+ /* clock-divider hack -- RapidScreenUpdate == every_point_one_seconds */
+ 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");
+ process->write_to_stdin("get letterbox\n");
+}
+
bool
VideoMonitor::skip_setting (std::string which)
{
return false;
}
+void
+VideoMonitor::send_cmd (int what, int param)
+{
+ bool osd_update = false;
+ int prev_osdmode = osdmode;
+ if (!is_started()) return;
+ switch (what) {
+ case 1:
+ if (param) process->write_to_stdin("window ontop on\n");
+ else process->write_to_stdin("window ontop off\n");
+ break;
+ case 2:
+ if (param) osdmode |= 2;
+ else osdmode &= ~2;
+ osd_update = (prev_osdmode != osdmode);
+ break;
+ case 3:
+ if (param) osdmode |= 1;
+ else osdmode &= ~1;
+ osd_update = (prev_osdmode != osdmode);
+ break;
+ case 4:
+ if (param) osdmode |= 8;
+ else osdmode &= ~8;
+ osd_update = (prev_osdmode != osdmode);
+ break;
+ case 5:
+ if (param) process->write_to_stdin("window zoom on\n");
+ else process->write_to_stdin("window zoom off\n");
+ break;
+ case 6:
+ if (param) process->write_to_stdin("window letterbox on\n");
+ else process->write_to_stdin("window letterbox off\n");
+ break;
+ case 7:
+ process->write_to_stdin("window resize 100%");
+ break;
+ default:
+ break;
+ }
+ if (osd_update) {
+ std::ostringstream osstream; osstream << "osd mode " << osdmode << "\n";
+ process->write_to_stdin(osstream.str());
+ }
+}
+
bool
VideoMonitor::is_started ()
{
}
void
-VideoMonitor::parse_output (std::string d, size_t s)
+VideoMonitor::forward_keyevent (unsigned int keyval)
+{
+ Editor* ed = dynamic_cast<Editor*>(&PublicEditor::instance());
+ if (!ed) return;
+ emulate_key_event(ed, keyval);
+}
+
+void
+VideoMonitor::parse_output (std::string d, size_t /*s*/)
{
std::string line = d;
std::string::size_type start = 0;
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) {
*/
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:
#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) {
+ 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) {
+ 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) {
+ 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") {
+ 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"); }
+ if ((osdmode & 2) == 0) { UiState("xjadeo-window-osd-timecode-off"); }
+ 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
}
}
}
void
VideoMonitor::terminated ()
{
- save_session();
+ process->terminate(); // from gui-context clean up
Terminated();
}
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 ();
}
}
}
}
-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)
{
{
return (xjadeo_settings[k]);
}
+
#define NO_OFFSET (1<<31) //< skip setting or modifying offset -- TODO check ARDOUR::frameoffset_t max value.
void
VideoMonitor::srsupdate ()
video_frame_offset = floor(offset * _session->timecode_frames_per_second() / audio_frame_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 (framepos_t when, bool /*force*/, ARDOUR::frameoffset_t offset)
{
if (!is_started()) { return; }
if (!_session) { return; }
bool my_manual_seek = true;
if (_session->config.get_external_sync()) {
- if (ARDOUR::Config->get_sync_source() == ARDOUR::JACK)
+ if (ARDOUR::Config->get_sync_source() == ARDOUR::Engine)
my_manual_seek = false;
}
sync_by_manual_seek = my_manual_seek;
}
}
-#endif /* WITH_VIDEOTIMELINE */