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