libvisual  0.5.0
lv_actor.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  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as
10  * published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22 
23 #include "config.h"
24 #include "lv_actor.h"
25 #include "lv_common.h"
26 #include "lv_plugin_registry.h"
27 #include <stdexcept>
28 
29 namespace LV {
30 
31  class Actor::Impl
32  {
33  public:
34 
35  VisPluginData* plugin;
36  VideoPtr video;
37  VideoPtr to_scale;
38  VideoPtr to_convert;
39  SongInfo songcompare;
40  VisVideoDepth run_depth;
41 
42  Impl ();
43  ~Impl ();
44 
45  VisActorPlugin* get_actor_plugin () const;
46 
48  };
49 
50  Actor::Impl::Impl ()
51  : plugin (nullptr)
52  , songcompare {SONG_INFO_TYPE_NULL}
53  {
54  // nothing
55  }
56 
57  Actor::Impl::~Impl ()
58  {
59  if (plugin) {
60  delete get_actor_plugin ()->songinfo;
61  visual_plugin_unload (plugin);
62  }
63  }
64 
65  VisActorPlugin* Actor::Impl::get_actor_plugin () const
66  {
67  return static_cast<VisActorPlugin*> (visual_plugin_get_info (plugin)->plugin);
68  }
69 
70  VisVideoDepth Actor::Impl::get_supported_depths ()
71  {
72  auto actor_plugin = get_actor_plugin ();
73 
74  return actor_plugin ? actor_plugin->vidoptions.depth : VISUAL_VIDEO_DEPTH_NONE;
75  }
76 
77  ActorPtr Actor::load (std::string const& name)
78  {
79  try {
80  return {new Actor (name), false};
81  }
82  catch (std::exception& error) {
83  visual_log (VISUAL_LOG_ERROR, "%s", error.what ());
84  return nullptr;
85  }
86  }
87 
88  Actor::Actor (std::string const& name)
89  : m_impl {new Impl}
90  , m_ref_count {1}
91  {
92  if (!LV::PluginRegistry::instance()->has_plugin (VISUAL_PLUGIN_TYPE_ACTOR, name)) {
93  throw std::runtime_error {"Actor plugin not found"};
94  }
95 
96  m_impl->plugin = visual_plugin_load (VISUAL_PLUGIN_TYPE_ACTOR, name.c_str ());
97  if (!m_impl->plugin) {
98  throw std::runtime_error {"Failed to load actor plugin"};
99  }
100 
101  // FIXME: Hack to initialize songinfo
102  m_impl->get_actor_plugin ()->songinfo = new SongInfo {SONG_INFO_TYPE_NULL};
103  }
104 
105  Actor::~Actor ()
106  {
107  // nothing
108  }
109 
110  VisPluginData* Actor::get_plugin ()
111  {
112  return m_impl->plugin;
113  }
114 
116  {
117  return visual_plugin_realize (m_impl->plugin);
118  }
119 
120  VideoPtr const& Actor::get_video ()
121  {
122  return m_impl->video;
123  }
124 
126  {
127  return m_impl->get_actor_plugin ()->songinfo;
128  }
129 
131  {
132  auto actor_plugin = m_impl->get_actor_plugin ();
133 
134  if (m_impl->run_depth == VISUAL_VIDEO_DEPTH_8BIT) {
135  return actor_plugin->palette (m_impl->plugin);
136  } else {
137  return nullptr;
138  }
139  }
140 
141  bool Actor::video_negotiate (VisVideoDepth run_depth, bool noevent, bool forced)
142  {
143  auto output_width = m_impl->video->get_width ();
144  auto output_height = m_impl->video->get_height ();
145  auto output_depth = m_impl->video->get_depth ();
146 
147  // Ask actor for preferred rendering dimensions
148 
149  int run_width = output_width;
150  int run_height = output_height;
151 
152  m_impl->get_actor_plugin ()->requisition (m_impl->plugin, &run_width, &run_height);
153 
154  // Check to make sure requested run depth is supported. If not, pick the highest.
155 
156  auto supported_depths = get_supported_depths ();
157  m_impl->run_depth = forced ? run_depth : visual_video_depth_get_highest_nogl (supported_depths);
158 
159  if (!visual_video_depth_is_supported (supported_depths, m_impl->run_depth)) {
160  m_impl->run_depth = visual_video_depth_get_highest_nogl (supported_depths);
161  }
162 
163  // Configure proxy videos to convert rendering
164 
165  m_impl->to_scale.reset ();
166  m_impl->to_convert.reset ();
167 
168  visual_log (VISUAL_LOG_DEBUG, "Setting up any necessary video conversions..");
169 
170  if (output_depth != VISUAL_VIDEO_DEPTH_GL) {
171  // Configure any necessary depth conversion
172  if (m_impl->run_depth != output_depth) {
173  visual_log (VISUAL_LOG_DEBUG, "Setting up depth conversion: %s -> %s",
174  visual_video_depth_name (m_impl->run_depth),
175  visual_video_depth_name (output_depth));
176 
177  m_impl->to_convert = Video::create (run_width, run_height, m_impl->run_depth);
178  }
179 
180  // Configure any necessary scaling
181  if (run_width != output_width || run_height != output_height) {
182  visual_log (VISUAL_LOG_DEBUG, "Setting up scaling: (%dx%d) -> (%dx%d)",
183  run_width, run_height, output_width, output_height);
184 
185  m_impl->to_scale = Video::create (run_width, run_height, output_depth);
186  }
187  } else {
188  visual_log (VISUAL_LOG_DEBUG, "Conversions skipped in OpenGL rendering mode");
189  }
190 
191  // FIXME: This should be moved into the if block above. It's out
192  // here because plugins depend on this to receive information
193  // about initial dimensions
194  if (!noevent) {
195  visual_event_queue_add (visual_plugin_get_event_queue (m_impl->plugin),
196  visual_event_new_resize (run_width, run_height));
197  }
198 
199  return true;
200  }
201 
203  {
204  return m_impl->get_supported_depths ();
205  }
206 
207  VisVideoAttrOptions const* Actor::get_video_attribute_options ()
208  {
209  return &m_impl->get_actor_plugin ()->vidoptions;
210  }
211 
212  void Actor::set_video (VideoPtr const& video)
213  {
214  m_impl->video = video;
215  }
216 
217  void Actor::run (Audio const& audio)
218  {
219  visual_return_if_fail (m_impl->video);
220 
221  auto actor_plugin = m_impl->get_actor_plugin ();
222  if (!actor_plugin) {
223  visual_log (VISUAL_LOG_ERROR, "The given actor does not reference any actor plugin");
224  return;
225  }
226 
227  auto plugin = get_plugin ();
228 
229  /* Songinfo handling */
230  if (!visual_songinfo_compare (&m_impl->songcompare, actor_plugin->songinfo) ||
231  m_impl->songcompare.get_elapsed () != actor_plugin->songinfo->get_elapsed ()) {
232 
233  actor_plugin->songinfo->mark ();
234 
235  visual_event_queue_add (visual_plugin_get_event_queue (plugin),
236  visual_event_new_newsong (actor_plugin->songinfo));
237 
238  visual_songinfo_copy (&m_impl->songcompare, actor_plugin->songinfo);
239  }
240 
241  // Get plugin to process all events
242  visual_plugin_events_pump (m_impl->plugin);
243 
244  auto const& video = m_impl->video;
245  auto const& to_convert = m_impl->to_convert;
246  auto const& to_scale = m_impl->to_scale;
247 
248  if (video->get_depth () != VISUAL_VIDEO_DEPTH_GL) {
249  auto palette = get_palette ();
250 
251  if (to_convert) {
252  // Have depth conversion
253 
254  // Setup any palette
255  if (palette) {
256  to_convert->set_palette (*palette);
257  }
258 
259  // Render first
260  actor_plugin->render (m_impl->plugin, to_convert.get (), const_cast<Audio*> (&audio));
261 
262  if (to_scale) {
263  // Convert depth, then scale
264  to_scale->convert_depth (to_convert);
265  video->scale (to_scale, VISUAL_VIDEO_SCALE_NEAREST);
266  }
267  else {
268  // Convert depth only
269  video->convert_depth (to_convert);
270  }
271  } else {
272  // No depth conversion
273 
274  if (to_scale) {
275  // Setup any palette
276  if (palette) {
277  to_scale->set_palette (*palette);
278  }
279 
280  // Render, then scale
281  actor_plugin->render (m_impl->plugin, to_scale.get (), const_cast<Audio*> (&audio));
282  video->scale (to_scale, VISUAL_VIDEO_SCALE_NEAREST);
283  } else {
284  // Setup any palette
285  if (palette) {
286  video->set_palette (*palette);
287  }
288 
289  // Render directly to video target
290  actor_plugin->render (m_impl->plugin, video.get (), const_cast<Audio*> (&audio));
291  }
292  }
293  } else {
294  // Render directly to video target (OpenGL)
295  actor_plugin->render (m_impl->plugin, video.get (), const_cast<Audio*> (&audio));
296  }
297  }
298 
299 } // LV namespace