libvisual  0.5.0
lv_bin.cpp
1 /* Libvisual - The audio visualisation framework.
2  *
3  * Copyright (C) 2012 Libvisual team
4  * 2004-2006 Dennis Smit
5  *
6  * Authors: Dennis Smit <ds@nerds-incorporated.org>
7  * Chong Kai Xiong <kaixiong@codeleft.sg>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as
11  * published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23 
24 #include "config.h"
25 #include "lv_bin.h"
26 #include "lv_common.h"
27 
28 namespace LV {
29 
30  class Bin::Impl
31  {
32  public:
33 
34  ActorPtr actor;
35  VideoPtr actvideo;
36  VideoPtr privvid;
37 
38  VideoPtr actmorphvideo;
39  ActorPtr actmorph;
40 
41  InputPtr input;
42 
43  bool use_morph;
44  MorphPtr morph;
45  bool morphing;
46  Time morphtime;
47 
48  VisBinDepth depthpreferred; /* Prefered depth, highest or lowest */
49  VisVideoDepth depthflag; /* Supported depths */
50  VisVideoDepth depthold; /* Previous depth */
51  VisVideoDepth depth; /* Depth we're running in */
52  bool depthchanged; /* Set true if the depth has changed */
53  bool depthfromGL; /* Set when switching away from openGL */
54  VisVideoDepth depthforced; /* Contains forced depth value, for the actmorph so we've got smooth transformations */
55  VisVideoDepth depthforcedmain; /* Contains forced depth value, for the main actor */
56 
57  Impl ();
58 
59  ~Impl ();
60 
61  VisVideoDepth get_suitable_depth (VisVideoDepth depth);
62 
63  void set_actor (ActorPtr const& actor);
64  void set_input (InputPtr const& input);
65  };
66 
67  VisVideoDepth Bin::Impl::get_suitable_depth (VisVideoDepth depthflag)
68  {
70 
71  switch (depthpreferred) {
72  case VISUAL_BIN_DEPTH_LOWEST:
73  depth = visual_video_depth_get_lowest (depthflag);
74  break;
75 
76  case VISUAL_BIN_DEPTH_HIGHEST:
77  depth = visual_video_depth_get_highest (depthflag);
78  break;
79  }
80 
81  // Is supported within bin natively
82  if (depthflag & depth)
83  return depth;
84 
85  // Not supported by the bin, taking the highest depth from the bin
86  return visual_video_depth_get_highest_nogl (depthflag);
87  }
88 
89 
90  Bin::Impl::Impl ()
91  : use_morph (false)
92  , morphing (false)
93  , morphtime (4, 0)
94  , depthpreferred (VISUAL_BIN_DEPTH_HIGHEST)
95  , depthflag (VISUAL_VIDEO_DEPTH_NONE)
96  , depthold (VISUAL_VIDEO_DEPTH_NONE)
97  , depth (VISUAL_VIDEO_DEPTH_NONE)
98  , depthchanged (false)
99  , depthfromGL (false)
100  , depthforced (VISUAL_VIDEO_DEPTH_NONE)
101  , depthforcedmain (VISUAL_VIDEO_DEPTH_NONE)
102  {
103  // empty
104  }
105 
106  Bin::Impl::~Impl ()
107  {
108  // nothing
109  }
110 
111  void Bin::Impl::set_actor (ActorPtr const& new_actor)
112  {
113  actor = new_actor;
114  }
115 
116  void Bin::Impl::set_input (InputPtr const& new_input)
117  {
118  input = new_input;
119  }
120 
121  Bin::Bin ()
122  : m_impl (new Impl)
123  {
124  // empty
125  }
126 
127  Bin::~Bin ()
128  {
129  // empty
130  }
131 
132  void Bin::realize ()
133  {
134  if (m_impl->actor)
135  m_impl->actor->realize ();
136 
137  if (m_impl->input)
138  m_impl->input->realize ();
139 
140  if (m_impl->morph)
141  m_impl->morph->realize ();
142  }
143 
144  ActorPtr const& Bin::get_actor () const
145  {
146  return m_impl->actor;
147  }
148 
149  InputPtr const& Bin::get_input () const
150  {
151  return m_impl->input;
152  }
153 
154  void Bin::set_morph (std::string const& morph_name)
155  {
156  m_impl->morph = Morph::load (morph_name);
157  visual_return_if_fail (m_impl->morph);
158 
159  VisVideoDepth depthflag = m_impl->morph->get_supported_depths ();
160 
161  if (visual_video_depth_is_supported (depthflag, m_impl->actvideo->get_depth ()) <= 0) {
162  m_impl->morph.reset ();
163  return;
164  }
165  }
166 
167  MorphPtr const& Bin::get_morph () const
168  {
169  return m_impl->morph;
170  }
171 
172  bool Bin::connect (ActorPtr const& actor, InputPtr const& input)
173  {
174  visual_return_val_if_fail (actor, false);
175  visual_return_val_if_fail (input, false);
176 
177  m_impl->set_actor (actor);
178  m_impl->set_input (input);
179 
180  auto depthflag = actor->get_supported_depths ();
181 
182  if (depthflag == VISUAL_VIDEO_DEPTH_GL) {
183  set_depth (VISUAL_VIDEO_DEPTH_GL);
184  } else {
185  set_depth (m_impl->get_suitable_depth (depthflag));
186  }
187 
188  m_impl->depthforcedmain = m_impl->depth;
189 
190  return true;
191  }
192 
193  bool Bin::connect (std::string const& actor_name, std::string const& input_name)
194  {
195  // Create the actor
196  auto actor = Actor::load (actor_name);
197  visual_return_val_if_fail (actor, false);
198 
199  // Create the input
200  auto input = Input::load (input_name);
201  visual_return_val_if_fail (input, false);
202 
203  // Connect
204  if (!connect (actor, input)) {
205  return false;
206  }
207 
208  return true;
209  }
210 
211  void Bin::sync (bool noevent)
212  {
213  visual_log (VISUAL_LOG_DEBUG, "starting sync");
214 
215  VideoPtr video;
216 
217  /* Sync the actor regarding morph */
218  if (m_impl->morphing && m_impl->use_morph &&
219  m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL && !m_impl->depthfromGL) {
220 
221  m_impl->morph->set_video (m_impl->actvideo);
222 
223  video = m_impl->privvid;
224  if (!video) {
225  visual_log (VISUAL_LOG_DEBUG, "Private video data nullptr");
226  return;
227  }
228 
229  video->free_buffer ();
230  video->copy_attrs (m_impl->actvideo);
231 
232  visual_log (VISUAL_LOG_DEBUG, "pitches actvideo %d, new video %d",
233  m_impl->actvideo->get_pitch (), video->get_pitch ());
234 
235  visual_log (VISUAL_LOG_DEBUG, "phase1 m_impl->privvid %p", (void *) m_impl->privvid.get ());
236  if (m_impl->actmorph->get_video ()->get_depth () == VISUAL_VIDEO_DEPTH_GL) {
237  video = m_impl->actvideo;
238  } else
239  video->allocate_buffer ();
240 
241  visual_log (VISUAL_LOG_DEBUG, "phase2");
242  } else {
243  video = m_impl->actvideo;
244  if (!video) {
245  visual_log (VISUAL_LOG_DEBUG, "Actor video is nullptr");
246  return;
247  }
248 
249  visual_log (VISUAL_LOG_DEBUG, "setting new video from actvideo %d %d",
250  video->get_depth (), video->get_bpp ());
251  }
252 
253  // Main actor
254 
255  m_impl->actor->set_video (video);
256 
257  visual_log (VISUAL_LOG_DEBUG, "one last video pitch check %d depth old %d forcedmain %d noevent %d",
258  video->get_pitch (), m_impl->depthold,
259  m_impl->depthforcedmain, noevent);
260 
261  if (m_impl->depthold == VISUAL_VIDEO_DEPTH_GL) {
262  m_impl->actor->video_negotiate (m_impl->depthforcedmain, false, true);
263  }
264  else {
265  m_impl->actor->video_negotiate (m_impl->depthforcedmain, noevent, true);
266  }
267 
268  visual_log (VISUAL_LOG_DEBUG, "pitch after main actor negotiate %d", video->get_pitch ());
269 
270  // Morphing actor
271 
272  if (m_impl->morphing && m_impl->use_morph) {
273 
274  auto actvideo = m_impl->actmorphvideo;
275  if (!actvideo) {
276  visual_log (VISUAL_LOG_DEBUG, "Morph video is nullptr");
277  return;
278  }
279 
280  actvideo->free_buffer ();
281 
282  actvideo->copy_attrs (video);
283 
284  if (m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL)
285  actvideo->allocate_buffer ();
286 
287  m_impl->actmorph->realize ();
288 
289  visual_log (VISUAL_LOG_DEBUG, "phase3 pitch of real framebuffer %d",
290  m_impl->actvideo->get_pitch ());
291 
292  m_impl->actmorph->video_negotiate (m_impl->depthforced, false, true);
293  }
294 
295  visual_log (VISUAL_LOG_DEBUG, "end sync function");
296  }
297 
298  void Bin::set_video (VideoPtr const& video)
299  {
300  m_impl->actvideo = video;
301  }
302 
303  void Bin::set_supported_depth (VisVideoDepth depthflag)
304  {
305  m_impl->depthflag = depthflag;
306  }
307 
308  VisVideoDepth Bin::get_supported_depth () const
309  {
310  return m_impl->depthflag;
311  }
312 
313  void Bin::set_preferred_depth (VisBinDepth depthpreferred)
314  {
315  m_impl->depthpreferred = depthpreferred;
316  }
317 
318  void Bin::set_depth (VisVideoDepth depth)
319  {
320  m_impl->depthold = m_impl->depth;
321 
322  if (!visual_video_depth_is_supported (m_impl->depthflag, depth))
323  return;
324 
325  visual_log (VISUAL_LOG_DEBUG, "old: %d new: %d", m_impl->depth, depth);
326 
327  if (m_impl->depth != depth)
328  m_impl->depthchanged = true;
329 
330  if (m_impl->depth == VISUAL_VIDEO_DEPTH_GL && m_impl->depthchanged)
331  m_impl->depthfromGL = true;
332  else
333  m_impl->depthfromGL = false;
334 
335  m_impl->depth = depth;
336 
337  if (m_impl->actvideo) {
338  m_impl->actvideo->set_depth (depth);
339  }
340  }
341 
342  VisVideoDepth Bin::get_depth () const
343  {
344  return m_impl->depth;
345  }
346 
347  bool Bin::depth_changed ()
348  {
349  if (!m_impl->depthchanged)
350  return false;
351 
352  m_impl->depthchanged = false;
353 
354  return true;
355  }
356 
357  Palette const& Bin::get_palette () const
358  {
359  if (m_impl->morphing)
360  return *m_impl->morph->get_palette ();
361  else
362  return *m_impl->actor->get_palette ();
363  }
364 
365  void Bin::switch_actor (std::string const& actor_name)
366  {
367  visual_log (VISUAL_LOG_DEBUG, "switching to a new actor: %s, old actor: %s",
368  actor_name.c_str (), visual_plugin_get_info (m_impl->actor->get_plugin ())->plugname);
369 
370  if (m_impl->actmorph) {
371  m_impl->actmorph.reset ();
372  m_impl->actmorphvideo.reset ();
373  }
374 
375  /* Create a new managed actor */
376  auto actor = LV::Actor::load (actor_name);
377  visual_return_if_fail (actor);
378 
379  auto video = LV::Video::create ();
380  video->copy_attrs(m_impl->actvideo);
381 
382  auto depthflag = actor->get_supported_depths ();
383  VisVideoDepth depth;
384 
386  visual_log (VISUAL_LOG_INFO, "Switching to GL mode");
387 
388  depth = VISUAL_VIDEO_DEPTH_GL;
389 
390  m_impl->depthforced = depth;
391  m_impl->depthforcedmain = depth;
392 
393  video->set_depth(depth);
394 
395  set_depth (depth);
396 
397  m_impl->depthchanged = true;
398  } else {
399  visual_log (VISUAL_LOG_INFO, "Switching away from Gl mode -- or non Gl switch");
400 
401  /* Switching from GL */
402  depth = m_impl->get_suitable_depth (depthflag);
403  video->set_depth(depth);
404 
405  visual_log (VISUAL_LOG_DEBUG, "after depth fixating");
406 
407  /* After a depth change, the pitch value needs an update from the client
408  * if it's different from width * bpp, after a visual_bin_sync
409  * the issues are fixed again */
410  visual_log (VISUAL_LOG_INFO, "video depth (from fixate): %d", video->get_depth ());
411 
412  /* FIXME check if there are any unneeded depth transform environments and drop these */
413  visual_log (VISUAL_LOG_DEBUG, "checking if we need to drop something: depthforcedmain: %d actvideo->depth %d",
414  m_impl->depthforcedmain, m_impl->actvideo->get_depth ());
415 
416  /* Drop a transformation environment when not needed */
417  if (m_impl->depthforcedmain != m_impl->actvideo->get_depth ()) {
418  m_impl->actor->video_negotiate (m_impl->depthforcedmain, true, true);
419  visual_log (VISUAL_LOG_DEBUG, "[[[[optionally a bogus transform environment, dropping]]]]");
420  }
421 
422  if (m_impl->actvideo->get_depth () > video->get_depth ()
423  && m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL
424  && m_impl->use_morph) {
425 
426  visual_log (VISUAL_LOG_INFO, "old depth is higher, video depth %d, bin depth %d",
427  video->get_depth (), m_impl->depth);
428 
429  m_impl->depthforced = depth;;
430  m_impl->depthforcedmain = m_impl->depth;
431 
432  set_depth (m_impl->actvideo->get_depth ());
433  video->set_depth (m_impl->actvideo->get_depth ());
434 
435  } else if (m_impl->actvideo->get_depth () != VISUAL_VIDEO_DEPTH_GL) {
436 
437  visual_log (VISUAL_LOG_INFO, "new depth is higher, or equal: video depth %d, depth %d bin depth %d",
438  video->get_depth (), depth, m_impl->depth);
439 
440  visual_log (VISUAL_LOG_DEBUG, "depths i can locate: actvideo: %d bin: %d bin-old: %d",
441  m_impl->actvideo->get_depth (), m_impl->depth, m_impl->depthold);
442 
443  m_impl->depthforced = video->get_depth ();
444  m_impl->depthforcedmain = m_impl->depth;
445 
446  visual_log (VISUAL_LOG_DEBUG, "depthforcedmain in switch by name: %d", m_impl->depthforcedmain);
447  visual_log (VISUAL_LOG_DEBUG, "Bin::set_depth %d", video->get_depth ());
448  set_depth (video->get_depth ());
449 
450  } else {
451  /* Don't force ourself into a GL depth, seen we do a direct
452  * switch in the run */
453  m_impl->depthforced = video->get_depth ();
454  m_impl->depthforcedmain = video->get_depth ();
455 
456  visual_log (VISUAL_LOG_INFO, "Switching from GL to framebuffer for real, framebuffer depth: %d",
457  video->get_depth ());
458  }
459 
460  visual_log (VISUAL_LOG_INFO, "Target depth selected: %d", depth);
461 
462  video->set_pitch(video->get_width() * (visual_video_depth_bpp(depth) >> 3));
463 
464  video->allocate_buffer();
465  }
466 
467 
468  visual_log (VISUAL_LOG_INFO, "video pitch of that what connects to the new actor %d",
469  video->get_pitch ());
470 
471  actor->set_video (video);
472 
473  m_impl->actmorphvideo = video;
474 
475  visual_log (VISUAL_LOG_INFO, "switching... ******************************************");
476  switch_actor (actor);
477 
478  visual_log (VISUAL_LOG_INFO, "end switch actor by name function ******************");
479  }
480 
481  void Bin::switch_actor (ActorPtr const& actor)
482  {
483  visual_return_if_fail (actor);
484 
485  /* Set the new actor */
486  m_impl->actmorph = actor;
487 
488  visual_log (VISUAL_LOG_DEBUG, "Starting actor switch...");
489 
490  /* Free the private video */
491  m_impl->privvid.reset ();
492 
493  visual_log (VISUAL_LOG_INFO, "depth of the main actor: %d",
494  m_impl->actor->get_video ()->get_depth ());
495 
496  /* Starting the morph, but first check if we don't have anything todo with openGL */
497  if (m_impl->use_morph &&
498  m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL &&
499  m_impl->actmorph->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL &&
500  !m_impl->depthfromGL) {
501 
502  if (m_impl->morph) {
503  m_impl->morph->set_progress (0.0f);
504  m_impl->morph->set_video (m_impl->actvideo);
505  m_impl->morph->set_time (m_impl->morphtime);
506  }
507 
508  visual_log (VISUAL_LOG_DEBUG, "phase 1");
509  /* Allocate a private video for the main actor, so the morph
510  * can draw to the framebuffer */
511  auto privvid = Video::create ();
512 
513  visual_log (VISUAL_LOG_DEBUG, "actvideo->depth %d actmorph->video->depth %d",
514  m_impl->actvideo->get_depth (),
515  m_impl->actmorph->get_video ()->get_depth ());
516 
517  visual_log (VISUAL_LOG_DEBUG, "phase 2");
518  privvid->copy_attrs (m_impl->actvideo);
519 
520  visual_log (VISUAL_LOG_DEBUG, "phase 3 pitch privvid %d actvideo %d",
521  privvid->get_pitch (), m_impl->actvideo->get_pitch ());
522 
523  privvid->allocate_buffer ();
524 
525  visual_log (VISUAL_LOG_DEBUG, "phase 4");
526  /* Initial privvid initialize */
527 
528  visual_log (VISUAL_LOG_DEBUG, "actmorph->video->depth %d %p",
529  m_impl->actmorph->get_video ()->get_depth (),
530  m_impl->actvideo->get_pixels ());
531 
532  if (m_impl->actvideo->get_pixels () && privvid->get_pixels ())
533  visual_mem_copy (privvid->get_pixels (), m_impl->actvideo->get_pixels (),
534  privvid->get_size ());
535  else if (privvid->get_pixels ())
536  visual_mem_set (privvid->get_pixels (), 0, privvid->get_size ());
537 
538  m_impl->actor->set_video (privvid);
539  m_impl->privvid = privvid;
540  } else {
541  visual_log (VISUAL_LOG_DEBUG, "Pointer actvideo->pixels %p", m_impl->actvideo->get_pixels ());
542  if (m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL &&
543  m_impl->actvideo->get_pixels ()) {
544  visual_mem_set (m_impl->actvideo->get_pixels (), 0, m_impl->actvideo->get_size ());
545  }
546  }
547 
548  visual_log (VISUAL_LOG_DEBUG, "Leaving, actor->video->depth: %d actmorph->video->depth: %d",
549  m_impl->actor->get_video ()->get_depth (),
550  m_impl->actmorph->get_video ()->get_depth ());
551 
552  m_impl->morphing = true;
553  }
554 
555  void Bin::switch_finalize ()
556  {
557  visual_log (VISUAL_LOG_DEBUG, "Completing actor switch...");
558 
559  /* Copy over the depth to be sure, and for GL plugins */
560  /* m_impl->actvideo->set_depth (m_impl->actmorphvideo->get_depth ()); */
561 
562  m_impl->actmorphvideo.reset ();
563  m_impl->privvid.reset ();
564 
565  m_impl->actor = m_impl->actmorph;
566  m_impl->actmorph.reset ();
567 
568  m_impl->actor->set_video (m_impl->actvideo);
569 
570  m_impl->morphing = false;
571  m_impl->morph.reset ();
572 
573  visual_log (VISUAL_LOG_DEBUG, " - in finalize - fscking depth from actvideo: %d %d",
574  m_impl->actvideo->get_depth (),
575  m_impl->actvideo->get_bpp ());
576 
577  VisVideoDepth depthflag = m_impl->actor->get_supported_depths ();
578  m_impl->actvideo->set_depth (m_impl->get_suitable_depth (depthflag));
579  set_depth (m_impl->actvideo->get_depth ());
580 
581  m_impl->depthforcedmain = m_impl->actvideo->get_depth ();
582  visual_log (VISUAL_LOG_DEBUG, "m_impl->depthforcedmain in finalize %d", m_impl->depthforcedmain);
583 
584  /* FIXME replace with a depth fixer */
585  if (m_impl->depthchanged) {
586  visual_log (VISUAL_LOG_INFO, "negotiate without event");
587  m_impl->actor->video_negotiate (m_impl->depthforcedmain, true, true);
588  visual_log (VISUAL_LOG_INFO, "end negotiate without event");
589  //sync(false);
590  }
591 
592  visual_log (VISUAL_LOG_DEBUG, "Leaving...");
593  }
594 
595  void Bin::use_morph (bool use)
596  {
597  m_impl->use_morph = use;
598  }
599 
600  void Bin::switch_set_time (Time const& time)
601  {
602  m_impl->morphtime = time;
603  }
604 
605  void Bin::run ()
606  {
607  visual_return_if_fail (m_impl->actor);
608  visual_return_if_fail (m_impl->input);
609 
610  m_impl->input->run ();
611 
612  /* If we have a direct switch, do this BEFORE we run the actor,
613  * else we can get into trouble especially with GL, also when
614  * switching away from a GL plugin this is needed */
615  if (m_impl->morphing) {
616  if (!visual_plugin_is_realized (m_impl->actmorph->get_plugin ())) {
617  m_impl->actmorph->realize ();
618 
619  m_impl->actmorph->video_negotiate (m_impl->depthforced, false, true);
620  }
621 
622  /* When we've got multiple switch events without a sync we need
623  * to realize the main actor as well */
624  if (!visual_plugin_is_realized (m_impl->actor->get_plugin ())) {
625  m_impl->actor->realize ();
626 
627  m_impl->actor->video_negotiate (m_impl->depthforced, false, true);
628  }
629 
630  /* When the style is DIRECT or the context is GL we shouldn't try
631  * to morph and instead finalize at once */
632  if (!m_impl->use_morph || m_impl->actor->get_video ()->get_depth () == VISUAL_VIDEO_DEPTH_GL) {
633 
634  switch_finalize ();
635 
636  /* We can't start drawing yet, the client needs to catch up with
637  * the depth change */
638  return;
639  }
640  }
641 
642  m_impl->actor->realize ();
643 
644  auto const& audio = m_impl->input->get_audio ();
645 
646  m_impl->actor->run (audio);
647 
648  if (m_impl->morphing) {
649  if (m_impl->use_morph &&
650  m_impl->actmorph->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL &&
651  m_impl->actor->get_video ()->get_depth () != VISUAL_VIDEO_DEPTH_GL) {
652 
653  m_impl->actmorph->run (audio);
654 
655  if (!m_impl->morph) {
656  switch_finalize ();
657  return;
658  }
659 
660  /* Same goes for the morph, we realize it here for depth changes
661  * (especially the OpenGL case */
662  m_impl->morph->realize ();
663  m_impl->morph->run (audio,
664  m_impl->actor->get_video (),
665  m_impl->actmorph->get_video ());
666 
667  if (m_impl->morph->is_done ()) {
668  switch_finalize ();
669  }
670  } else {
671  /* visual_bin_switch_finalize (bin); */
672  }
673  }
674  }
675 
676 } // LV namespace