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