ardour
video_timeline.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 Paul Davis
3  Author: Robin Gareus <robin@gareus.org>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 #include <algorithm>
21 #include <sigc++/bind.h>
22 #include "ardour/tempo.h"
23 
24 #include "pbd/file_utils.h"
25 #include "pbd/convert.h"
27 
28 #include "ardour_ui.h"
29 #include "public_editor.h"
30 #include "gui_thread.h"
31 #include "utils_videotl.h"
32 #include "rgb_macros.h"
33 #include "video_timeline.h"
34 #include "video_tool_paths.h"
35 
36 #include <gtkmm2ext/utils.h>
37 #include <pthread.h>
38 #include <curl/curl.h>
39 
40 #include "i18n.h"
41 
42 using namespace std;
43 using namespace ARDOUR;
44 using namespace PBD;
45 using namespace Timecode;
46 using namespace VideoUtils;
47 
48 VideoTimeLine::VideoTimeLine (PublicEditor *ed, ArdourCanvas::Container *vbg, int initial_height)
49  : editor (ed)
50  , videotl_group(vbg)
51  , bar_height(initial_height)
52 {
53  video_start_offset = 0L;
54  video_offset = 0L;
55  video_offset_p = 0L;
56  video_duration = 0L;
57  auto_set_session_fps = false;
58  video_offset_lock = false;
59  video_aspect_ratio = 4.0/3.0;
63  video_filename = "";
64  local_file = true;
65  video_file_fps = 25.0;
66  flush_frames = false;
67  vmonitor=0;
68  reopen_vmonitor=false;
69  find_xjadeo();
70 
71  VtlUpdate.connect (*this, invalidator (*this), boost::bind (&PublicEditor::queue_visual_videotimeline_update, editor), gui_context());
72  GuiUpdate.connect (*this, invalidator (*this), boost::bind (&VideoTimeLine::gui_update, this, _1), gui_context());
73 }
74 
76 {
77  close_session();
78 }
79 
80 /* close and save settings */
81 void
83 {
84  if (!_session) {
85  return;
86  }
87 
88  LocaleGuard lg (X_("C"));
89 
90  XMLNode* node = new XMLNode(X_("Videomonitor"));
91  if (!node) return;
92  node->add_property (X_("active"), (vmonitor && vmonitor->is_started())?"yes":"no");
93  _session->add_extra_xml (*node);
94 
95  if (vmonitor) {
96  if (vmonitor->is_started()) {
98  }
100  }
101 
102  /* VTL settings */
103  node = _session->extra_xml (X_("Videotimeline"));
104  if (!node) return;
105  node->add_property (X_("id"), id().to_s());
106  node->add_property (X_("Height"), editor->get_videotl_bar_height());
107  node->add_property (X_("VideoOffsetLock"), video_offset_lock?X_("1"):X_("0"));
108  node->add_property (X_("VideoOffset"), video_offset);
109  node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
110 }
111 
112 /* close and save settings */
113 void
115 {
116  if (video_duration == 0) {
117  return;
118  }
121 
122  remove_frames();
123  video_filename = "";
124  video_duration = 0;
125  GuiUpdate("set-xjadeo-sensitive-off");
126  GuiUpdate("video-unavailable");
127 }
128 
129 void
131 {
132  if (!_session || !vmonitor || !vmonitor->is_started()) {
133  return;
134  }
135  save_session();
136 }
137 
139 void
141 {
142  SessionHandlePtr::set_session (s);
143  if (!_session) { return ; }
144 
145  _session->SessionSaveUnderway.connect_same_thread (sessionsave, boost::bind (&VideoTimeLine::save_session, this));
146  LocaleGuard lg (X_("C"));
147 
148  XMLNode* node = _session->extra_xml (X_("Videotimeline"));
149 
150  if (!node || !node->property (X_("Filename"))) {
151  return;
152  }
153 
154  ARDOUR_UI::instance()->start_video_server((Gtk::Window*)0, false);
155 
156  set_id(*node);
157 
158  const XMLProperty* proph = node->property (X_("Height"));
159  if (proph) {
161  }
162 #if 0 /* TODO THINK: set FPS first time only ?! */
163  const XMLProperty* propasfps = node->property (X_("AutoFPS"));
164  if (propasfps) {
165  auto_set_session_fps = atoi(propasfps->value())?true:false;
166  }
167 #endif
168 
169  const XMLProperty* propoffset = node->property (X_("VideoOffset"));
170  if (propoffset) {
171  video_offset = atoll(propoffset->value());
173  }
174 
175  const XMLProperty* proplock = node->property (X_("VideoOffsetLock"));
176  if (proplock) {
177  video_offset_lock = atoi(proplock->value())?true:false;
178  }
179 
180  const XMLProperty* localfile = node->property (X_("LocalFile"));
181  if (localfile) {
182  local_file = atoi(localfile->value())?true:false;
183  }
184 
185  const XMLProperty* propf = node->property (X_("Filename"));
186  video_file_info(propf->value(), local_file);
187 
188  if ((node = _session->extra_xml (X_("Videomonitor")))) {
189  const XMLProperty* prop = node->property (X_("active"));
190  if (prop && prop->value() == "yes" && found_xjadeo() && !video_filename.empty() && local_file) {
192  }
193  }
194 
197 }
198 
199 void
201  if (_session && v != video_offset_lock) {
202  _session->set_dirty ();
203  }
204  video_offset_lock = v;
205 }
206 
207 void
210  if (_session) {
211  _session->set_dirty ();
212  }
213 }
214 
215 void
217 {
219  _session->set_dirty ();
220  }
222 }
223 
224 int
225 VideoTimeLine::set_state (const XMLNode& node, int /*version*/)
226 {
227  LocaleGuard lg (X_("C"));
228  const XMLProperty* propoffset = node.property (X_("VideoOffset"));
229  if (propoffset) {
230  video_offset = atoll(propoffset->value());
231  }
233  return 0;
234 }
235 
236 XMLNode&
238 {
239  XMLNode* node = new XMLNode (X_("Videotimeline"));
240  LocaleGuard lg (X_("C"));
241  node->add_property (X_("VideoOffset"), video_offset_p);
242  return *node;
243 }
244 
245 void
247 {
248  for (VideoFrames::iterator i = video_frames.begin(); i != video_frames.end(); ++i ) {
249  VideoImageFrame *frame = (*i);
250  delete frame;
251  (*i) = 0;
252  }
253  video_frames.clear();
254 }
255 
257 VideoTimeLine::get_video_frame (framepos_t vfn, int cut, int rightend)
258 {
259  if (vfn==0) cut=0;
260  for (VideoFrames::iterator i = video_frames.begin(); i != video_frames.end(); ++i) {
261  VideoImageFrame *frame = (*i);
262  if (abs(frame->get_video_frame_number()-vfn)<=cut
263  && frame->get_rightend() == rightend) { return frame; }
264  }
265  return 0;
266 }
267 
268 float
270 {
271  // XXX: dup code - TODO use this fn in update_video_timeline()
272  float apv = -1; /* audio samples per video frame; */
273  if (!_session) return apv;
274 
275  if (_session->config.get_use_video_file_fps()) {
276  if (video_file_fps == 0 ) return apv;
277  } else {
278  if (_session->timecode_frames_per_second() == 0 ) return apv;
279  }
280 
281  if (_session->config.get_videotimeline_pullup()) {
282  apv = _session->frame_rate();
283  } else {
284  apv = _session->nominal_frame_rate();
285  }
286  if (_session->config.get_use_video_file_fps()) {
287  apv /= video_file_fps;
288  } else {
290  }
291  return apv;
292 }
293 
294 void
296 {
297  if (!_session) return;
298 
299  if (_session->config.get_use_video_file_fps()) {
300  if (video_file_fps == 0 ) return;
301  } else {
302  if (_session->timecode_frames_per_second() == 0 ) return;
303  }
304 
305  const double samples_per_pixel = editor->get_current_zoom();
306  const framepos_t leftmost_sample = editor->leftmost_sample();
307 
308  /* Outline:
309  * 1) calculate how many frames there should be in current zoom (plus 1 page on each side)
310  * 2) calculate first frame and distance between video-frames (according to zoom)
311  * 3) destroy/add frames
312  * 4) reposition existing frames
313  * 5) assign framenumber to frames -> request/decode video.
314  */
315 
316  /* video-file and session properties */
317  double display_vframe_width; /* unit: pixels ; width of one thumbnail in the timeline */
318  float apv; /* audio samples per video frame; */
319  framepos_t leftmost_video_frame; /* unit: video-frame number ; temporary var -> vtl_start */
320 
321  /* variables needed to render videotimeline -- what needs to computed first */
322  framepos_t vtl_start; /* unit: audio-samples ; first displayed video-frame */
323  framepos_t vtl_dist; /* unit: audio-samples ; distance between displayed video-frames */
324  unsigned int visible_video_frames; /* number of frames that fit on current canvas */
325 
326  if (_session->config.get_videotimeline_pullup()) {
327  apv = _session->frame_rate();
328  } else {
329  apv = _session->nominal_frame_rate();
330  }
331  if (_session->config.get_use_video_file_fps()) {
332  apv /= video_file_fps;
333  } else {
335  }
336 
337  display_vframe_width = bar_height * video_aspect_ratio;
338 
339  if (apv > samples_per_pixel * display_vframe_width) {
340  /* high-zoom: need space between successive video-frames */
341  vtl_dist = rint(apv);
342  } else {
343  /* continous timeline: skip video-frames */
344  vtl_dist = ceil(display_vframe_width * samples_per_pixel / apv) * apv;
345  }
346 
347  assert (vtl_dist > 0);
348  assert (apv > 0);
349 
350  leftmost_video_frame = floor (floor((long double)(leftmost_sample - video_start_offset - video_offset ) / vtl_dist) * vtl_dist / apv);
351 
352  vtl_start = rint (video_offset + video_start_offset + leftmost_video_frame * apv);
353  visible_video_frames = 2 + ceil((double)editor->current_page_samples() / vtl_dist); /* +2 left+right partial frames */
354 
355  /* expand timeline (cache next/prev page images) */
356  vtl_start -= visible_video_frames * vtl_dist;
357  visible_video_frames *=3;
358 
359  if (vtl_start < video_offset ) {
360  visible_video_frames += ceil((double)vtl_start/vtl_dist);
361  vtl_start = video_offset;
362  }
363 
364  /* apply video-file constraints */
365  if (vtl_start > video_start_offset + video_duration + video_offset ) {
366  visible_video_frames = 0;
367  }
368  /* TODO optimize: compute rather than iterate */
369  while (visible_video_frames > 0 && vtl_start + (visible_video_frames-1) * vtl_dist >= video_start_offset + video_duration + video_offset) {
370  --visible_video_frames;
371  }
372 
373  if (flush_frames) {
374  remove_frames();
375  flush_frames=false;
376  }
377 
378  while (video_frames.size() < visible_video_frames) {
379  VideoImageFrame *frame;
380  frame = new VideoImageFrame(*editor, *videotl_group, display_vframe_width, bar_height, video_server_url, translated_filename());
381  frame->ImgChanged.connect (*this, invalidator (*this), boost::bind (&PublicEditor::queue_visual_videotimeline_update, editor), gui_context());
382  video_frames.push_back(frame);
383  }
384 
385  VideoFrames outdated_video_frames;
386  std::list<int> remaining;
387 
388  outdated_video_frames = video_frames;
389 
390 #if 1
391  /* when zoomed out, ignore shifts by +-1 frame
392  * which can occur due to rounding errors when
393  * scrolling to a new leftmost-audio frame.
394  */
395  int cut =1;
396  if (vtl_dist/apv < 3.0) cut =0;
397 #else
398  int cut =0;
399 #endif
400 
401  for (unsigned int vfcount=0; vfcount < visible_video_frames; ++vfcount){
402  framepos_t vfpos = vtl_start + vfcount * vtl_dist; /* unit: audio-frames */
403  framepos_t vframeno = rint ( (vfpos - video_offset) / apv); /* unit: video-frames */
404  vfpos = (vframeno * apv ) + video_offset; /* audio-frame corresponding to /rounded/ video-frame */
405 
406  int rightend = -1; /* unit: pixels */
407  if (vfpos + vtl_dist > video_start_offset + video_duration + video_offset) {
408  rightend = display_vframe_width * (video_start_offset + video_duration + video_offset - vfpos) / vtl_dist;
409  //printf("lf(e): %lu\n", vframeno); // XXX
410  }
411  VideoImageFrame * frame = get_video_frame(vframeno, cut, rightend);
412  if (frame) {
413  frame->set_position(vfpos);
414  outdated_video_frames.remove(frame);
415  } else {
416  remaining.push_back(vfcount);
417  }
418  }
419 
420  for (VideoFrames::iterator i = outdated_video_frames.begin(); i != outdated_video_frames.end(); ++i ) {
421  VideoImageFrame *frame = (*i);
422  if (remaining.empty()) {
423  frame->set_position(-2 * vtl_dist + leftmost_sample); /* move off screen */
424  } else {
425  int vfcount=remaining.front();
426  remaining.pop_front();
427  framepos_t vfpos = vtl_start + vfcount * vtl_dist; /* unit: audio-frames */
428  framepos_t vframeno = rint ((vfpos - video_offset) / apv); /* unit: video-frames */
429  int rightend = -1; /* unit: pixels */
430  if (vfpos + vtl_dist > video_start_offset + video_duration + video_offset) {
431  rightend = display_vframe_width * (video_start_offset + video_duration + video_offset - vfpos) / vtl_dist;
432  //printf("lf(n): %lu\n", vframeno); // XXX
433  }
434  frame->set_position(vfpos);
435  frame->set_videoframe(vframeno, rightend);
436  }
437  }
438 }
439 
440 std::string
442 {
443  if (!local_file){
444  return video_filename;
445  } else {
447  }
448 }
449 
450 bool
451 VideoTimeLine::video_file_info (std::string filename, bool local)
452 {
453 
454  local_file = local;
455  if (Glib::path_is_absolute(filename) || !local_file)
456  {
457  video_filename = filename;
458  } else {
459  video_filename = Glib::build_filename (_session->session_directory().video_path(), filename);
460  }
461 
462  long long int _duration;
463  double _start_offset;
464 
465  if (!video_query_info(
467  video_file_fps, _duration, _start_offset, video_aspect_ratio)) {
468  warning << _("Parsing video file info failed. Is the Video Server running? Is the file readable by the Video Server? Does the docroot match? Is it a video file?") << endmsg;
469  video_duration = 0;
470  GuiUpdate("set-xjadeo-sensitive-off");
471  GuiUpdate("video-unavailable");
472  return false;
473  }
475  video_start_offset = _start_offset * _session->nominal_frame_rate();
476 
478  switch ((int)floorf(video_file_fps*1000.0)) {
479  case 23976:
480  _session->config.set_timecode_format(timecode_23976);
481  break;
482  case 24000:
483  _session->config.set_timecode_format(timecode_24);
484  break;
485  case 24975:
486  case 24976:
487  _session->config.set_timecode_format(timecode_24976);
488  break;
489  case 25000:
490  _session->config.set_timecode_format(timecode_25);
491  break;
492  case 29970:
493  _session->config.set_timecode_format(timecode_2997drop);
494  break;
495  case 30000:
496  _session->config.set_timecode_format(timecode_30);
497  break;
498  case 59940:
499  _session->config.set_timecode_format(timecode_5994);
500  break;
501  case 60000:
502  _session->config.set_timecode_format(timecode_60);
503  break;
504  default:
506  _("Failed to set session-framerate: '%1' does not have a corresponding option setting in %2."),
507  video_file_fps, PROGRAM_NAME ) << endmsg;
508  break;
509  }
510  _session->config.set_video_pullup(0); /* TODO only set if set_timecode_format() was successful ?!*/
511  }
512  if (floor(video_file_fps*100) != floor(_session->timecode_frames_per_second()*100)) {
514  _("Video file's framerate is not equal to %1 session timecode's framerate: '%2' vs '%3'"),
516  << endmsg;
517  }
519 
520  if (found_xjadeo() && local_file) {
521  GuiUpdate("set-xjadeo-sensitive-on");
522  if (vmonitor && vmonitor->is_started()) {
523 #if 1
524  /* xjadeo <= 0.6.4 has a bug where changing the video-file may segfauls
525  * if the geometry changes to a different line-size alignment
526  */
527  reopen_vmonitor = true;
528  vmonitor->quit();
529 #else
532 #endif
533  }
534  } else if (!local_file) {
535 #if 1 /* temp debug/devel message */
536  // TODO - call xjremote remotely.
537  printf("the given video file can not be accessed on localhost, video monitoring is not currently supported for this case\n");
538  GuiUpdate("set-xjadeo-sensitive-off");
539 #endif
540  }
541  VtlUpdate();
542  GuiUpdate("video-available");
543  return true;
544 }
545 
546 bool
548 {
549  bool ok = false;
550  char url[1024];
551  snprintf(url, sizeof(url), "%s%sstatus"
552  , video_server_url.c_str()
553  , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/"
554  );
555  char *res=a3_curl_http_get(url, NULL);
556  if (res) {
557  if (strstr(res, "status: ok, online.")) { ok = true; }
558  free(res);
559  }
560  return ok;
561 }
562 
563 bool
565 {
566  bool ok = true;
567  char url[1024];
568  std::vector<std::vector<std::string> > lines;
569 
570  if (video_server_url.find("/localhost:") == string::npos) {
571  return true;
572  }
573  snprintf(url, sizeof(url), "%s%src?format=csv"
574  , video_server_url.c_str()
575  , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/"
576  );
577  char *res=a3_curl_http_get(url, NULL);
578  if (!res) {
579  return false;
580  }
581 
582  ParseCSV(std::string(res), lines);
583  if ( lines.empty()
584  || lines.at(0).empty()
585  || lines.at(0).at(0) != video_get_docroot(Config)) {
587  _("Video-server docroot mismatch. %1: '%2', video-server: '%3'. This usually means that the video server was not started by %1 and uses a different document-root."),
588  PROGRAM_NAME, video_get_docroot(Config), lines.at(0).at(0))
589  << endmsg;
590  ok = false; // TODO allow to override
591  }
592  free(res);
593  return ok;
594 }
595 
596 void
597 VideoTimeLine::gui_update(std::string const & t) {
598  /* this is to be called via GuiUpdate() only. */
599  ENSURE_GUI_THREAD (*this, &VideoTimeLine::queue_visual_videotimeline_update)
600  if (t == "videotimeline-update") {
602  } else if (t == "set-xjadeo-active-off") {
604  } else if (t == "set-xjadeo-active-on") {
606  } else if (t == "set-xjadeo-sensitive-on") {
608  } else if (t == "set-xjadeo-sensitive-off") {
610  //close_video_monitor();
612  } else if (t == "xjadeo-window-ontop-on") {
614  } else if (t == "xjadeo-window-ontop-off") {
616  } else if (t == "xjadeo-window-osd-timecode-on") {
618  } else if (t == "xjadeo-window-osd-timecode-off") {
620  } else if (t == "xjadeo-window-osd-frame-on") {
622  } else if (t == "xjadeo-window-osd-frame-off") {
624  } else if (t == "xjadeo-window-osd-box-on") {
626  } else if (t == "xjadeo-window-osd-box-off") {
628  } else if (t == "xjadeo-window-fullscreen-on") {
630  } else if (t == "xjadeo-window-fullscreen-off") {
632  } else if (t == "xjadeo-window-letterbox-on") {
634  } else if (t == "xjadeo-window-letterbox-off") {
636  } else if (t == "video-available") {
638  } else if (t == "video-unavailable") {
640  }
641 }
642 
643 void
645  if (_session && bar_height != height) {
646  _session->set_dirty ();
647  }
648  bar_height = height;
650 }
651 
652 void
654  if (vmonitor && vmonitor->is_started()) {
655  vmonitor->set_offset(video_offset); // TODO proper re-init xjadeo w/o restart not just offset.
656  }
657 }
658 
659 void
661  flush_frames = true;
662  vmon_update();
663 }
664 
665 void
668  char url[1024];
669  snprintf(url, sizeof(url), "%s%sadmin/flush_cache"
670  , video_server_url.c_str()
671  , (video_server_url.length()>0 && video_server_url.at(video_server_url.length()-1) == '/')?"":"/"
672  );
673  char *res=a3_curl_http_get(url, NULL);
674  if (res) {
675  free (res);
676  }
677  if (vmonitor && vmonitor->is_started()) {
678  reopen_vmonitor=true;
679  vmonitor->quit();
680  }
682 }
683 
684 /* config */
685 void
686 VideoTimeLine::parameter_changed (std::string const & p)
687 {
688  if (p == "video-server-url") {
690  } else if (p == "video-server-docroot") {
692  } else if (p == "video-advanced-setup") {
695  }
696  if (p == "use-video-file-fps" || p == "videotimeline-pullup" ) { /* session->config parameter */
697  VtlUpdate();
698  }
699 }
700 
701 void
704  video_server_url = vsu;
705  VtlUpdate();
706 }
707 
708 void
711  server_docroot = vsr;
712  VtlUpdate();
713 }
714 
715 /* video-monitor for this timeline */
716 void
717 VideoTimeLine::xjadeo_readversion (std::string d, size_t /* s */) {
718  xjadeo_version += d;
719 }
720 
721 void
724  warning << _("Video-monitor 'xjadeo' was not found. Please install http://xjadeo.sf.net/ "
725  "(a custom path to xjadeo can be specified by setting the XJREMOTE environment variable. "
726  "It should point to an application compatible with xjadeo's remote-control interface 'xjremote').\n"
727  "\n"
728  "see also http://manual.ardour.org/video-timeline/setup/")
729  << endmsg;
730  }
731 
732  if (found_xjadeo ()) {
733  ARDOUR::SystemExec version_check(_xjadeo_bin, X_("--version"));
734  xjadeo_version = "";
735  version_check.ReadStdout.connect_same_thread (*this, boost::bind (&VideoTimeLine::xjadeo_readversion, this, _1 ,_2));
736  version_check.Terminated.connect_same_thread (*this, boost::bind (&VideoTimeLine::xjadeo_readversion, this, "\n" ,1));
737  if (version_check.start(2)) {
738  warning << _(
739  "Video-monitor 'xjadeo' cannot be launched."
740  ) << endmsg;
741  _xjadeo_bin = X_("");
742  return;
743  }
744 
745  version_check.wait ();
746  int timeout = 300;
747  while (xjadeo_version.empty() && --timeout) {
748  Glib::usleep(10000);
749  }
750 
751  bool v_ok = false;
752  size_t vo = xjadeo_version.find(" version ");
753  if (vo != string::npos) {
754  int v_major, v_minor, v_micro;
755  if(sscanf(xjadeo_version.substr(vo + 9, string::npos).c_str(),"%d.%d.%d",
756  &v_major, &v_minor, &v_micro) == 3)
757  {
758  if (v_major >= 1) v_ok = true;
759  else if (v_major == 0 && v_minor >= 8) v_ok = true;
760  else if (v_major == 0 && v_minor >= 7 && v_micro >= 7) v_ok = true;
761  }
762  }
763  if (!v_ok) {
764  _xjadeo_bin = X_("");
765  warning << _(
766  "Video-monitor 'xjadeo' is too old. "
767  "Please install xjadeo version 0.7.7 or later. http://xjadeo.sf.net/"
768  ) << endmsg;
769  }
770  }
771 }
772 
773 void
775  if (!found_xjadeo()) return;
776  if (!vmonitor) {
780  vmonitor->Terminated.connect (sigc::mem_fun (*this, &VideoTimeLine::terminated_video_monitor));
781  vmonitor->UiState.connect (*this, invalidator (*this), boost::bind (&VideoTimeLine::gui_update, this, _1), gui_context());
782  } else if (vmonitor->is_started()) {
783  return;
784  }
785 
786 #if 0
787  /* unused for now.
788  * the idea is to selective ignore certain monitor window
789  * states if xjadeo is not running on the same host as ardour.
790  * However with the removal of the video-monitor-startup-dialogue
791  * (git rev 5a4d0fff0) these settings are currently not accessible.
792  */
793  int xj_settings_mask = vmonitor->restore_settings_mask();
794  if (_session) {
795  /* load mask from Session */
796  XMLNode* node = _session->extra_xml (X_("XJRestoreSettings"));
797  if (node) {
798  const XMLProperty* prop = node->property (X_("mask"));
799  if (prop) {
800  xj_settings_mask = atoi(prop->value());
801  }
802  }
803  }
804 
805  vmonitor->restore_settings_mask(xj_settings_mask);
806 #endif
807 
808  if (!vmonitor->start()) {
809  warning << "launching xjadeo failed.." << endmsg;
811  } else {
812  GuiUpdate("set-xjadeo-active-on");
815 
816  if (_session) {
817  XMLNode* node = _session->extra_xml (X_("Videomonitor"));
818  if (node) {
819  const XMLProperty* prop = node->property (X_("active"));
820  if (prop && prop->value() != "yes") _session->set_dirty ();
821  } else {
822  _session->set_dirty ();
823  }
824  }
825 
826  }
827 }
828 
829 void
831  if (vmonitor && vmonitor->is_started()) {
832  vmonitor->quit();
833  }
834 }
835 
836 void
838  if (!vmonitor || !vmonitor->is_started()) {
839  return;
840  }
841  vmonitor->send_cmd(what, param);
842 }
843 
844 
845 void
847  if (vmonitor) {
849  delete vmonitor;
850  }
851  vmonitor=0;
852  GuiUpdate("set-xjadeo-active-off");
853  if (reopen_vmonitor) {
854  reopen_vmonitor=false;
856  } else {
857  if (_session) {
858  _session->set_dirty ();
859  }
860  }
861 }
862 
863 void
865 {
866  if (!vmonitor) { return; }
867  if (!vmonitor->is_started()) { return; }
868  if (!vmonitor->synced_by_manual_seeks()) { return; }
869  vmonitor->manual_seek(pos, false, video_offset); // XXX -> set offset in xjadeo
870 }
bool xjadeo_exe(std::string &xjadeo_exe)
void manual_seek(ARDOUR::framepos_t, bool, ARDOUR::frameoffset_t)
std::string video_get_docroot(ARDOUR::RCConfiguration *config)
double timecode_frames_per_second() const
Definition: session_time.cc:55
framecnt_t nominal_frame_rate() const
Definition: session.h:367
std::string video_server_url
int atoi(const string &s)
Definition: convert.cc:140
bool video_query_info(std::string video_server_url, std::string filepath, double &video_file_fps, long long int &video_duration, double &video_start_offset, double &video_aspect_ratio)
void gui_update(const std::string &)
#define ui_bind(f,...)
Definition: gui_thread.h:37
const std::string & value() const
Definition: xml++.h:159
void set_height(int)
void close_video_monitor()
int64_t atoll(const string &s)
Definition: convert.cc:152
char * a3_curl_http_get(const char *u, int *status)
void control_video_monitor(int, int)
PBD::Signal0< void > Terminated
Definition: system_exec.h:183
void open_video_monitor()
void set_videoframe(framepos_t, int rightend=-1)
void parameter_changed(std::string const &p)
const std::string video_path() const
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
void send_cmd(int what, int param)
bool start_video_server(Gtk::Window *float_window, bool popup_msg)
Definition: ardour_ui.cc:3765
void save_undo(void)
Representation of the interface of the Editor class.
void ParseCSV(const std::string &csv, std::vector< std::vector< std::string > > &lines)
ARDOUR::frameoffset_t video_start_offset
void xjadeo_readversion(std::string d, size_t s)
Definition: Beats.hpp:239
LIBPBD_API Transmitter warning
void set_offset(ARDOUR::frameoffset_t)
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
SessionConfiguration config
Definition: session.h:866
void restore_settings_mask(int i)
Definition: video_monitor.h:67
virtual void set_close_video_sensitive(bool)=0
a single video-frame to be displayed in the video timeline
std::string server_docroot
framecnt_t frame_rate() const
Definition: session.h:365
void flush_videotimeline_cache(bool localcacheonly=false)
Definition: ardour_ui.cc:4017
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
void save_session()
#define invalidator(x)
Definition: gui_thread.h:40
PBD::Signal1< void, std::string > UiState
Definition: video_monitor.h:77
void query_full_state(bool)
std::string video_map_path(std::string server_docroot, std::string filepath)
virtual void set_xjadeo_sensitive(bool onoff)=0
virtual void queue_visual_videotimeline_update()=0
PBD::Signal0< void > VtlUpdate
communication with xjadeo's remote-control interface
Definition: video_monitor.h:49
#define _(Text)
Definition: i18n.h:11
bool video_file_info(std::string, bool)
std::string translated_filename()
std::list< VideoImageFrame * > VideoFrames
std::string xjadeo_version
void terminated_video_monitor()
std::string video_filename
#define X_(Text)
Definition: i18n.h:13
virtual void set_video_timeline_height(const int h)=0
void sync_session_state()
bool synced_by_manual_seeks()
Definition: video_monitor.h:74
VideoMonitor * vmonitor
XMLProperty * property(const char *)
Definition: xml++.cc:413
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
void set_video_server_url(std::string)
PBD::Signal1< void, std::string > GuiUpdate
virtual framecnt_t get_current_zoom() const =0
framepos_t get_video_frame_number()
void set_session(ARDOUR::Session *s)
Definition: amp.h:29
VideoTimeLine(PublicEditor *, ArdourCanvas::Container *, int)
bool set_id(const XMLNode &)
Definition: stateful.cc:381
PBD::Signal0< void > ImgChanged
#define gui_context()
Definition: gui_thread.h:36
void set_session(ARDOUR::Session *s)
std::string _xjadeo_bin
void open(std::string)
common functions used for video-file im/export
void update_video_timeline()
void flush_local_cache()
int64_t framepos_t
Definition: types.h:66
VideoImageFrame * get_video_frame(framepos_t vfn, int cut=0, int rightend=-1)
virtual framecnt_t current_page_samples() const =0
std::string video_get_server_url(ARDOUR::RCConfiguration *config)
int wait(int options=0)
Definition: system_exec.cc:679
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
virtual ~VideoTimeLine()
virtual void toggle_xjadeo_proc(int)=0
XMLProperty * add_property(const char *name, const std::string &value)
ArdourCanvas::Container * videotl_group
int start(int stderr_mode=1)
Definition: system_exec.h:38
PBD::Signal0< void > SessionSaveUnderway
Definition: session.h:457
XMLNode & get_state()
void toggle_offset_locked()
bool auto_set_session_fps
PBD::ScopedConnection sessionsave
Definition: xml++.h:95
virtual void toggle_xjadeo_viewoption(int, int)=0
void set_fps(float f)
Definition: video_monitor.h:56
int set_state(const XMLNode &, int version)
XMLNode * extra_xml(const std::string &str, bool add_if_missing=false)
Definition: stateful.cc:77
Definition: debug.h:30
ARDOUR::frameoffset_t video_offset_p
PublicEditor * editor
PBD::Signal2< void, std::string, size_t > ReadStdout
Definition: system_exec.h:176
virtual int get_videotl_bar_height() const =0
double video_file_fps
void set_video_server_docroot(std::string)
virtual framepos_t leftmost_sample() const =0
void set_position(framepos_t)
const SessionDirectory & session_directory() const
Definition: session.h:182
framepos_t video_duration
sigc::signal< void > Terminated
Definition: video_monitor.h:76
void add_extra_xml(XMLNode &)
Definition: stateful.cc:66
bool found_xjadeo()
void register_with_memento_command_factory(PBD::ID, PBD::StatefulDestructible *)
ARDOUR::frameoffset_t video_offset
void set_offset_locked(bool v)
double video_aspect_ratio
void manual_seek_video_monitor(framepos_t pos)
ARDOUR::Session * _session
VideoFrames video_frames
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
bool check_server_docroot()