Put _something_ there for now....
[wxWidgets.git] / src / unix / mediactrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: unix/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Unix
4 // Author: Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created: 02/04/05
7 // RCS-ID: $Id$
8 // Copyright: (c) 2004-2005 Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 //===========================================================================
13 // DECLARATIONS
14 //===========================================================================
15
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "mediactrl.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 //---------------------------------------------------------------------------
32 // Includes
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
35
36 //---------------------------------------------------------------------------
37 // Compilation guard
38 //---------------------------------------------------------------------------
39 #if wxUSE_MEDIACTRL
40
41 //===========================================================================
42 // BACKEND DECLARATIONS
43 //===========================================================================
44
45 //---------------------------------------------------------------------------
46 //
47 // wxGStreamerMediaBackend
48 //
49 // This won't compile/work without a little work yet...
50 // Uses nanoseconds...
51 //---------------------------------------------------------------------------
52 #if wxUSE_GSTREAMER
53
54 //---------------------------------------------------------------------------
55 // GStreamer Includes
56 //---------------------------------------------------------------------------
57 #include <gst/gst.h>
58 #include <gst/xoverlay/xoverlay.h>
59
60 #include <string.h> //strstr
61
62 #include "wx/log.h"
63
64 #ifdef __WXGTK__
65 //for <gdk/gdkx.h>/related for GDK_WINDOW_XWINDOW
66 # include "wx/gtk/win_gtk.h"
67 #endif
68
69 class WXDLLIMPEXP_MEDIA wxGStreamerMediaBackend : public wxMediaBackend
70 {
71 public:
72
73 wxGStreamerMediaBackend();
74 ~wxGStreamerMediaBackend();
75
76 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
77 wxWindowID id,
78 const wxPoint& pos,
79 const wxSize& size,
80 long style,
81 const wxValidator& validator,
82 const wxString& name);
83
84 virtual bool Play();
85 virtual bool Pause();
86 virtual bool Stop();
87
88 virtual bool Load(const wxString& fileName);
89 virtual bool Load(const wxURI& location);
90
91 virtual wxMediaState GetState();
92
93 virtual bool SetPosition(wxLongLong where);
94 virtual wxLongLong GetPosition();
95 virtual wxLongLong GetDuration();
96
97 virtual void Move(int x, int y, int w, int h);
98 wxSize GetVideoSize() const;
99
100 virtual double GetPlaybackRate();
101 virtual bool SetPlaybackRate(double dRate);
102
103 void Cleanup();
104
105 static void OnFinish(GstElement *play, gpointer data);
106 static void OnError (GstElement *play, GstElement *src,
107 GError *err, gchar *debug,
108 gpointer data);
109
110 GstElement* m_player; //GStreamer media element
111 GstElement* m_audiosink;
112 GstElement* m_videosink;
113
114 DECLARE_DYNAMIC_CLASS(wxGStreamerMediaBackend);
115 };
116
117
118 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
119 //
120 // wxGStreamerMediaBackend
121 //
122 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
123
124 IMPLEMENT_DYNAMIC_CLASS(wxGStreamerMediaBackend, wxMediaBackend);
125
126 wxGStreamerMediaBackend::wxGStreamerMediaBackend()
127 {
128 }
129
130 wxGStreamerMediaBackend::~wxGStreamerMediaBackend()
131 {
132 gst_element_set_state (m_player, GST_STATE_NULL);
133 gst_object_unref (GST_OBJECT (m_player));
134 gst_object_unref (GST_OBJECT (m_videosink));
135 gst_object_unref (GST_OBJECT (m_audiosink));
136 }
137
138 bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
139 wxWindowID id,
140 const wxPoint& pos,
141 const wxSize& size,
142 long style,
143 const wxValidator& validator,
144 const wxString& name)
145 {
146 //init gstreamer
147 gst_init(NULL, NULL);
148
149 //
150 // Create window
151 // By default wxWindow(s) is created with a border -
152 // so we need to get rid of those return Load(
153 //
154 // Since we don't have a child window like most other
155 // backends, we don't need wxCLIP_CHILDREN
156 //
157 if ( !
158 ctrl->wxControl::Create(parent, id, pos, size,
159 style, //remove borders???
160 validator, name)
161 )
162 return false;
163
164 m_player = gst_element_factory_make ("playbin", "play");
165 m_audiosink = gst_element_factory_make ("alsasink", "audiosink");
166 m_videosink = gst_element_factory_make ("xvimagesink", "videosink");
167
168 g_object_set (G_OBJECT (m_player),
169 "video-sink", m_videosink,
170 "audio-sink", m_audiosink,
171 NULL);
172
173 g_signal_connect (m_player, "eos", G_CALLBACK (OnError), this);
174 g_signal_connect (m_player, "error", G_CALLBACK (OnFinish), this);
175
176 if ( ! GST_IS_X_OVERLAY(m_videosink) )
177 return false;
178
179 gst_x_overlay_set_xwindow_id( GST_X_OVERLAY(m_videosink),
180 #ifdef __WXGTK__
181 GDK_WINDOW_XWINDOW(ctrl->GetHandle())
182 #else
183 ctrl->GetHandle()
184 #endif
185 );
186 return true;
187 }
188
189 void wxGStreamerMediaBackend::OnFinish(GstElement *play, gpointer data)
190 {
191 wxGStreamerMediaBackend* m_parent = (wxGStreamerMediaBackend*) data;
192
193 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
194 m_parent->m_ctrl->GetId());
195 m_parent->m_ctrl->ProcessEvent(theEvent);
196
197 if(theEvent.IsAllowed())
198 {
199 bool bOk = m_parent->Stop();
200 wxASSERT(bOk);
201
202 //send the event to our child
203 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
204 m_parent->m_ctrl->GetId());
205 m_parent->m_ctrl->ProcessEvent(theEvent);
206 }
207 }
208
209 void wxGStreamerMediaBackend::OnError(GstElement *play,
210 GstElement *src,
211 GError *err,
212 gchar *debug,
213 gpointer data)
214 {
215 wxLogSysError(wxString::Format(wxT("Error in GStreamer Playback!\nError Message:%s"), wxString(err->message).c_str()));
216 }
217
218
219 bool wxGStreamerMediaBackend::Load(const wxString& fileName)
220 {
221 return Load(
222 wxURI(
223 wxString( wxT("file://") ) + fileName
224 )
225 );
226 }
227
228 bool wxGStreamerMediaBackend::Load(const wxURI& location)
229 {
230 Cleanup();
231 wxString locstring = location.BuildURI();
232
233
234 if ( GST_STATE(m_player) > GST_STATE_READY )
235 gst_element_set_state(m_player, GST_STATE_READY);
236
237 g_object_set (G_OBJECT (m_player), "uri", locstring.c_str(), NULL);
238
239 gst_x_overlay_expose(GST_X_OVERLAY(m_videosink));
240
241 return GST_STATE(m_player) == GST_STATE_READY;
242 }
243
244 bool wxGStreamerMediaBackend::Play()
245 {
246 if (gst_element_set_state (m_player, GST_STATE_PLAYING)
247 != GST_STATE_SUCCESS)
248 return false;
249 return true;
250 }
251
252 bool wxGStreamerMediaBackend::Pause()
253 {
254 if (gst_element_set_state (m_player, GST_STATE_PAUSED)
255 != GST_STATE_SUCCESS)
256 return false;
257 return true;
258 }
259
260 bool wxGStreamerMediaBackend::Stop()
261 {
262 if (gst_element_set_state (m_player,
263 GST_STATE_READY) != GST_STATE_SUCCESS)
264 return false;
265 return true;
266 }
267
268 wxMediaState wxGStreamerMediaBackend::GetState()
269 {
270 switch(GST_STATE(m_player))
271 {
272 case GST_STATE_PLAYING:
273 return wxMEDIASTATE_PLAYING;
274 case GST_STATE_PAUSED:
275 return wxMEDIASTATE_PAUSED;
276 default://case GST_STATE_READY:
277 return wxMEDIASTATE_STOPPED;
278 }
279 }
280
281 bool wxGStreamerMediaBackend::SetPosition(wxLongLong where)
282 {
283 return gst_element_seek (play, (GstSeekType) (GST_SEEK_METHOD_SET |
284 GST_FORMAT_TIME | GST_SEEK_FLAG_FLUSH),
285 where * GST_MSECOND );
286 }
287
288 wxLongLong wxGStreamerMediaBackend::GetPosition()
289 {
290 gint64 pos;
291 GstFormat fmtTime = GST_FORMAT_TIME;
292
293 if (!gst_element_query (play, GST_QUERY_POSITION, &fmtTime, &pos))
294 return 0;
295 return pos / GST_MSECOND ;
296 }
297
298 wxLongLong wxGStreamerMediaBackend::GetDuration()
299 {
300 gint64 length;
301 GstFormat fmtTime = GST_FORMAT_TIME;
302
303 if(!gst_element_query(m_player, GST_QUERY_TOTAL, &fmtTime, &length))
304 return 0;
305 return length / GST_MSECOND ;
306 }
307
308 void wxGStreamerMediaBackend::Move(int x, int y, int w, int h)
309 {
310 }
311
312 wxSize wxGStreamerMediaBackend::GetVideoSize() const
313 {
314 //TODO: check state
315 //TODO: maybe cache size
316 wxSize retSize = wxSize(0,0);
317
318 const GList *list = NULL;
319 g_object_get (G_OBJECT (m_player), "stream-info", &list, NULL);
320
321 for ( ; list != NULL; list = list->next)
322 {
323 GObject *info = (GObject *) list->data;
324 gint type;
325 GParamSpec *pspec;
326 GEnumValue *val;
327 GstPad *pad = NULL;
328
329 g_object_get (info, "type", &type, NULL);
330 pspec = g_object_class_find_property (
331 G_OBJECT_GET_CLASS (info), "type");
332 val = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, type);
333
334 if (strstr (val->value_name, "VIDEO"))
335 {
336 g_object_get (info, "object", &pad, NULL);
337 pad = (GstPad *) GST_PAD_REALIZE (pad);
338 wxAssert(pad);
339
340 GstCaps* caps = GST_PAD_CAPS (pad);
341 wxAssert(caps);
342
343 const GstStructure *s;
344 s = gst_caps_get_structure (caps, 0);
345 wxAssert(s);
346
347 gst_structure_get_int (s, "width", &retSize.x);
348 gst_structure_get_int (s, "height", &retSize.y);
349
350 const GValue *par;
351 par = gst_structure_get_value (s, "pixel-aspect-ratio"));
352
353 if (par)
354 {
355 int num = gst_value_get_fraction_numerator (par),
356 den = gst_value_get_fraction_denominator (par);
357
358 //TODO: maybe better fraction normalization...
359 if (num > den)
360 retSize.x = (int) ((float) num * retSize.x / den);
361 else
362 retSize.y = (int) ((float) den * retSize.y / num);
363 }
364 }
365 }
366 }
367
368 double wxGStreamerMediaBackend::GetPlaybackRate()
369 {
370 //guess...
371 GstClock* theClock = gst_element_get_clock(m_player);
372 wxAssert(theClock);
373 return gst_clock_get_speed(theClock);
374 }
375
376 bool wxGStreamerMediaBackend::SetPlaybackRate(double dRate)
377 {
378 //guess...
379 GstClock* theClock = gst_element_get_clock(m_player);
380 wxAssert(theClock);
381 return gst_clock_change_speed(theClock, GetPlaybackRate(), dRate)==dRate;
382 }
383
384 #endif //wxUSE_GSTREAMER
385
386 //in source file that contains stuff you don't directly use
387 #include <wx/html/forcelnk.h>
388 FORCE_LINK_ME(basewxmediabackends);
389
390 #endif //wxUSE_MEDIACTRL
391
392
393
394
395