]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/vidxanm.cpp
implemented (untested) work around for wxScrolledWindow painting bug
[wxWidgets.git] / contrib / src / mmedia / vidxanm.cpp
1 // -------------------------------------------------------------------------
2 // Name: vidxanm.cpp
3 // Purpose: wxMMedia
4 // Author: Guilhem Lavaux
5 // Created: 1997
6 // Updated: 1998
7 // Copyright: (C) 1997, 1998, 1999 Guilhem Lavaux
8 // License: wxWindows license
9 // -------------------------------------------------------------------------
10
11 #ifdef __GNUG__
12 #pragma implementation "vidxanm.h"
13 #endif
14
15 #include <wx/wxprec.h>
16
17 #ifndef WX_PRECOMP
18 #include <wx/wx.h>
19 #endif
20
21 // Pizza !
22 #include <wx/gtk/win_gtk.h>
23
24 #include <X11/Xlib.h>
25 #include <X11/Intrinsic.h>
26 #ifdef __WXGTK__
27 #include <gtk/gtkwidget.h>
28 #include <gtk/gtkwindow.h>
29 #include <gdk/gdk.h>
30 #include <gdk/gdkprivate.h>
31 #endif
32
33 #include <wx/filefn.h>
34 #include <wx/wfstream.h>
35 #include <wx/datstrm.h>
36 #include <wx/tokenzr.h>
37
38 #define WXMMEDIA_INTERNAL
39 #include "wx/mmedia/vidbase.h"
40 #include "wx/mmedia/vidxanm.h"
41
42 IMPLEMENT_DYNAMIC_CLASS(wxVideoXANIM, wxVideoBaseDriver)
43
44 // -------------------------------------------------------------------------
45 // End process detector
46
47 class wxVideoXANIMProcess: public wxProcess {
48 public:
49 wxVideoXANIMProcess(wxVideoXANIM *xanim);
50
51 void OnTerminate(int pid, int status);
52
53 protected:
54 wxVideoXANIM *m_vid_xanim;
55 };
56
57 class wxVideoXANIMOutput: public wxProcess {
58 public:
59 wxVideoXANIMOutput();
60
61 void OnTerminate(int pid, int status);
62
63 bool IsTerminated() const;
64 protected:
65 bool m_terminated;
66 };
67
68 // -------------------------------------------------------------------------
69 // XAnim video driver (process handling implementation)
70
71 wxVideoXANIMProcess::wxVideoXANIMProcess(wxVideoXANIM *xanim)
72 {
73 m_vid_xanim = xanim;
74 }
75
76 void wxVideoXANIMProcess::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
77 {
78 m_vid_xanim->m_xanim_started = FALSE;
79 m_vid_xanim->OnFinished();
80 }
81
82 wxVideoXANIMOutput::wxVideoXANIMOutput()
83 : wxProcess(NULL, -1)
84 {
85 m_terminated = FALSE;
86 Redirect();
87 }
88
89 bool wxVideoXANIMOutput::IsTerminated() const
90 {
91 return m_terminated;
92 }
93
94 void wxVideoXANIMOutput::OnTerminate(int pid, int status)
95 {
96 m_terminated = TRUE;
97 }
98
99 // -------------------------------------------------------------------------
100 // XAnim video driver (implementation)
101
102 wxVideoXANIM::wxVideoXANIM()
103 : wxVideoBaseDriver()
104 {
105 m_internal = new wxXANIMinternal;
106 m_xanim_detector = new wxVideoXANIMProcess(this);
107 m_xanim_started = FALSE;
108 m_paused = FALSE;
109 m_filename = "";
110 m_remove_file = FALSE;
111 }
112
113 wxVideoXANIM::wxVideoXANIM(wxInputStream& str)
114 : wxVideoBaseDriver(str)
115 {
116 m_internal = new wxXANIMinternal;
117 m_xanim_detector = new wxVideoXANIMProcess(this);
118 m_xanim_started = FALSE;
119 m_paused = FALSE;
120 m_size[0] = 0;
121 m_size[1] = 0;
122
123 m_filename = wxGetTempFileName("vidxa");
124 m_remove_file = TRUE;
125 wxFileOutputStream fout(m_filename);
126
127 fout << str;
128
129 CollectInfo();
130 }
131
132 wxVideoXANIM::wxVideoXANIM(const wxString& filename)
133 {
134 m_internal = new wxXANIMinternal;
135 m_xanim_detector = new wxVideoXANIMProcess(this);
136 m_xanim_started = FALSE;
137 m_paused = FALSE;
138
139 m_filename = filename;
140 m_remove_file = FALSE;
141 m_size[0] = 0;
142 m_size[1] = 0;
143
144 CollectInfo();
145 }
146
147 wxVideoXANIM::~wxVideoXANIM()
148 {
149 if (m_xanim_started)
150 Stop();
151 delete m_internal;
152 delete m_xanim_detector;
153
154 if (m_remove_file)
155 wxRemoveFile(m_filename);
156 }
157
158 // -------------------------------------------------------------------------
159 // Movie controller
160
161 bool wxVideoXANIM::Play()
162 {
163 if (!m_paused && m_xanim_started)
164 return TRUE;
165 if (!m_video_output) {
166 wxVideoCreateFrame(this);
167 return TRUE;
168 }
169
170 // The movie starts with xanim
171 if (RestartXANIM()) {
172 m_paused = FALSE;
173 return TRUE;
174 }
175 return FALSE;
176 }
177
178 bool wxVideoXANIM::Pause()
179 {
180 if (!m_paused && SendCommand(" ")) {
181 m_paused = TRUE;
182 return TRUE;
183 }
184 return FALSE;
185 }
186
187 bool wxVideoXANIM::Resume()
188 {
189 if (m_paused && SendCommand(" ")) {
190 m_paused = FALSE;
191 return TRUE;
192 }
193 return FALSE;
194 }
195
196 bool wxVideoXANIM::Stop()
197 {
198 if (!m_xanim_started)
199 return FALSE;
200
201 SendCommand("q");
202
203 // We are waiting for the termination of the subprocess.
204 while (m_xanim_started) {
205 wxYield();
206 }
207
208 m_paused = FALSE;
209
210 return TRUE;
211 }
212
213 // -------------------------------------------------------------------------
214 // Movie size controller
215
216 bool wxVideoXANIM::SetSize(wxSize size)
217 {
218 if (!m_video_output)
219 return FALSE;
220
221 m_video_output->SetSize(size.GetWidth(), size.GetHeight());
222 return FALSE;
223 }
224
225 bool wxVideoXANIM::GetSize(wxSize& size) const
226 {
227 if (m_size[0] == 0)
228 return FALSE;
229 size.Set(m_size[0], m_size[1]);
230 return TRUE;
231 }
232
233 // -------------------------------------------------------------------------
234 // Capabilities of XAnim
235
236 bool wxVideoXANIM::IsCapable(wxVideoType v_type) const
237 {
238 if (v_type == wxVIDEO_MSAVI || v_type == wxVIDEO_MPEG ||
239 v_type == wxVIDEO_QT || v_type == wxVIDEO_GIF || v_type == wxVIDEO_JMOV ||
240 v_type == wxVIDEO_FLI || v_type == wxVIDEO_IFF || v_type == wxVIDEO_SGI)
241 return TRUE;
242 else
243 return FALSE;
244 }
245
246 // -------------------------------------------------------------------------
247 // Movie state
248
249 wxString wxVideoXANIM::GetMovieCodec() const
250 {
251 if (m_size[0] == 0)
252 return wxT("");
253 return m_movieCodec;
254 }
255
256 wxString wxVideoXANIM::GetAudioCodec() const
257 {
258 if (m_size[0] == 0)
259 return wxT("");
260 return m_audioCodec;
261 }
262
263 wxUint32 wxVideoXANIM::GetSampleRate() const
264 {
265 if (m_size[0] == 0)
266 return 0;
267 return m_sampleRate;
268 }
269
270 wxUint8 wxVideoXANIM::GetChannels() const
271 {
272 if (m_size[0] == 0)
273 return 0;
274 return m_channels;
275 }
276
277 wxUint8 wxVideoXANIM::GetBPS() const
278 {
279 if (m_size[0] == 0)
280 return 0;
281 return m_bps;
282 }
283
284 double wxVideoXANIM::GetFrameRate() const
285 {
286 if (m_size[0] == 0)
287 return 0.0;
288 return m_frameRate;
289 }
290
291 wxUint32 wxVideoXANIM::GetNbFrames() const
292 {
293 if (m_size[0] == 0)
294 return 0;
295 return m_frames;
296 }
297
298
299 bool wxVideoXANIM::IsPaused() const
300 {
301 return m_paused;
302 }
303
304 bool wxVideoXANIM::IsStopped() const
305 {
306 return !m_xanim_started;
307 }
308
309 // -------------------------------------------------------------------------
310 // Output management
311
312 bool wxVideoXANIM::AttachOutput(wxWindow& out)
313 {
314 if (!wxVideoBaseDriver::AttachOutput(out))
315 return FALSE;
316
317 return TRUE;
318 }
319
320 void wxVideoXANIM::DetachOutput()
321 {
322 SendCommand("q");
323 m_xanim_started = FALSE;
324 m_paused = FALSE;
325
326 wxVideoBaseDriver::DetachOutput();
327 }
328
329 // -------------------------------------------------------------------------
330 // Lowlevel XAnim controller
331
332 bool wxVideoXANIM::SendCommand(const char *command, char **ret,
333 wxUint32 *size)
334 {
335 if (!m_xanim_started)
336 if (!RestartXANIM())
337 return FALSE;
338
339 // Send a command to XAnim through X11 Property
340 XChangeProperty(m_internal->xanim_dpy, m_internal->xanim_window,
341 m_internal->xanim_atom,
342 XA_STRING, 8, PropModeReplace, (unsigned char *)command,
343 strlen(command));
344 XFlush(m_internal->xanim_dpy);
345 if (ret) {
346 int prop_format;
347 Atom prop_type;
348 unsigned long extra;
349
350 XGetWindowProperty(m_internal->xanim_dpy, m_internal->xanim_window,
351 m_internal->xanim_ret, 0, 16, True, AnyPropertyType,
352 &prop_type, &prop_format, (unsigned long *)size,
353 &extra, (unsigned char **)ret);
354 }
355 return TRUE;
356 }
357
358 bool wxVideoXANIM::CollectInfo()
359 {
360 wxVideoXANIMOutput *xanimProcess;
361 wxString xanim_command;
362 wxStringTokenizer tokenizer;
363
364 xanimProcess = new wxVideoXANIMOutput;
365 xanim_command = wxT("xanim +v +Zv -Ae ");
366 xanim_command += m_filename;
367 if (!wxExecute(xanim_command, FALSE, xanimProcess))
368 return FALSE;
369
370 wxInputStream *infoStream = xanimProcess->GetInputStream();
371 wxString totalOutput;
372
373 while (infoStream->LastError() == wxSTREAM_NOERROR) {
374 char line[100];
375
376 infoStream->Read(line, sizeof(line)-1);
377 if (infoStream->LastRead() == 0)
378 break;
379
380 line[infoStream->LastRead()] = 0;
381
382 totalOutput += line;
383 }
384
385 // This is good for everything ... :-)
386 int position = totalOutput.Find(wxT("Video Codec:"));
387
388 totalOutput.Remove(0, position+13);
389
390 position = totalOutput.Find(wxT("depth="));
391 m_movieCodec = totalOutput(0, position);
392
393 totalOutput.Remove(0, position);
394 tokenizer.SetString(totalOutput, "\n\r");
395
396 // the rest of the line
397 wxString token = tokenizer.GetNextToken();
398 unsigned long my_long;
399
400 #define GETINT(i) \
401 totalOutput.ToULong(&my_long); \
402 i = my_long;
403
404 // 'Audio Codec:'
405 totalOutput = tokenizer.GetString();
406 totalOutput.Remove(0, totalOutput.Find(wxT(":"))+2);
407
408 position = totalOutput.Find(wxT("Rate"));
409 m_audioCodec = totalOutput(0, position-1);
410
411 // 'Rate='
412 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
413 GETINT(m_sampleRate);
414 // 'Chans='
415 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
416 GETINT(m_channels);
417 // 'Bps='
418 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
419 GETINT(m_bps);
420 // 'Frame Stats:'
421 tokenizer.Reinit(totalOutput);
422 tokenizer.GetNextToken();
423 totalOutput = tokenizer.GetString();
424 totalOutput.Remove(0, totalOutput.Find(wxT(":"))+2);
425 // 'Size='
426 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
427 GETINT(m_size[0]);
428 // 'x'
429 totalOutput.Remove(0,1);
430 GETINT(m_size[1]);
431 // 'Frames='
432 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
433 GETINT(m_frames);
434 // 'avfps='
435 totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
436 totalOutput.ToDouble(&m_frameRate);
437
438 // We wait for the conclusion
439 while (!xanimProcess->IsTerminated())
440 wxYield();
441
442 delete xanimProcess;
443
444 return TRUE;
445 }
446
447 bool wxVideoXANIM::RestartXANIM()
448 {
449 wxString xanim_command;
450 int ret;
451 Atom prop_type;
452 int prop_format;
453 unsigned long nitems;
454 unsigned long extra;
455 char prop[4];
456 bool xanim_chg_size;
457
458 if (!m_video_output || m_xanim_started)
459 return FALSE;
460
461 // Check if we can change the size of the window dynamicly
462 xanim_chg_size = TRUE;
463 // Get current display
464 #ifdef __WXGTK__
465 m_internal->xanim_dpy = gdk_display;
466 GtkPizza *pizza = GTK_PIZZA( m_video_output->m_wxwindow );
467 GdkWindow *window = pizza->bin_window;
468
469 m_internal->xanim_window =
470 ((GdkWindowPrivate *)window)->xwindow;
471 #endif
472 // Get the XANIM atom
473 m_internal->xanim_atom = XInternAtom(m_internal->xanim_dpy,
474 "XANIM_PROPERTY", False);
475
476 // Build the command
477 xanim_command.Printf(wxT("xanim -Zr +Ze +Sr +f +W%d +f +q "
478 "+Av70 %s %s"), m_internal->xanim_window,
479 (xanim_chg_size) ? _T("") : _T(""),
480 WXSTRINGCAST m_filename);
481
482 // Execute it
483 if (!wxExecute(xanim_command, FALSE, m_xanim_detector))
484 return FALSE;
485
486 // Wait for XAnim to be ready
487 nitems = 0;
488 m_xanim_started = TRUE;
489 while (nitems == 0 && m_xanim_started) {
490 ret = XGetWindowProperty(m_internal->xanim_dpy, m_internal->xanim_window,
491 m_internal->xanim_atom,
492 0, 4, False, AnyPropertyType, &prop_type,
493 &prop_format, &nitems, &extra,
494 (unsigned char **)&prop);
495 wxYield();
496 }
497
498 wxSize vibrato_size;
499
500 vibrato_size = m_video_output->GetSize();
501
502 vibrato_size.SetWidth(vibrato_size.GetWidth()+1);
503 m_video_output->SetSize(vibrato_size);
504 vibrato_size.SetWidth(vibrato_size.GetWidth()-1);
505 m_video_output->SetSize(vibrato_size);
506 // Very useful ! Actually it "should" sends a SETSIZE event to XAnim
507 // FIXME: This event is not sent !!
508
509 m_paused = FALSE;
510
511 return TRUE;
512 }