]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/vidxanm.cpp
Various tweaks, fixes, and additions
[wxWidgets.git] / contrib / src / mmedia / vidxanm.cpp
CommitLineData
e8482f24
GL
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
42IMPLEMENT_DYNAMIC_CLASS(wxVideoXANIM, wxVideoBaseDriver)
43
44// -------------------------------------------------------------------------
45// End process detector
46
47class wxVideoXANIMProcess: public wxProcess {
48public:
49 wxVideoXANIMProcess(wxVideoXANIM *xanim);
50
51 void OnTerminate(int pid, int status);
52
53protected:
54 wxVideoXANIM *m_vid_xanim;
55};
56
57class wxVideoXANIMOutput: public wxProcess {
58public:
59 wxVideoXANIMOutput();
60
61 void OnTerminate(int pid, int status);
62
63 bool IsTerminated() const;
64protected:
65 bool m_terminated;
66};
67
68// -------------------------------------------------------------------------
69// XAnim video driver (process handling implementation)
70
71wxVideoXANIMProcess::wxVideoXANIMProcess(wxVideoXANIM *xanim)
72{
73 m_vid_xanim = xanim;
74}
75
76void wxVideoXANIMProcess::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
77{
78 m_vid_xanim->m_xanim_started = FALSE;
79 m_vid_xanim->OnFinished();
80}
81
82wxVideoXANIMOutput::wxVideoXANIMOutput()
83 : wxProcess(NULL, -1)
84{
85 m_terminated = FALSE;
86 Redirect();
87}
88
89bool wxVideoXANIMOutput::IsTerminated() const
90{
91 return m_terminated;
92}
93
94void wxVideoXANIMOutput::OnTerminate(int pid, int status)
95{
96 m_terminated = TRUE;
97}
98
99// -------------------------------------------------------------------------
100// XAnim video driver (implementation)
101
102wxVideoXANIM::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
113wxVideoXANIM::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
132wxVideoXANIM::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
147wxVideoXANIM::~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
161bool 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
178bool wxVideoXANIM::Pause()
179{
180 if (!m_paused && SendCommand(" ")) {
181 m_paused = TRUE;
182 return TRUE;
183 }
184 return FALSE;
185}
186
187bool wxVideoXANIM::Resume()
188{
189 if (m_paused && SendCommand(" ")) {
190 m_paused = FALSE;
191 return TRUE;
192 }
193 return FALSE;
194}
195
196bool 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
216bool 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
225bool 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
236bool 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
249wxString wxVideoXANIM::GetMovieCodec() const
250{
251 if (m_size[0] == 0)
252 return wxT("");
253 return m_movieCodec;
254}
255
256wxString wxVideoXANIM::GetAudioCodec() const
257{
258 if (m_size[0] == 0)
259 return wxT("");
260 return m_audioCodec;
261}
262
263wxUint32 wxVideoXANIM::GetSampleRate() const
264{
265 if (m_size[0] == 0)
266 return 0;
267 return m_sampleRate;
268}
269
270wxUint8 wxVideoXANIM::GetChannels() const
271{
272 if (m_size[0] == 0)
273 return 0;
274 return m_channels;
275}
276
277wxUint8 wxVideoXANIM::GetBPS() const
278{
279 if (m_size[0] == 0)
280 return 0;
281 return m_bps;
282}
283
284double wxVideoXANIM::GetFrameRate() const
285{
286 if (m_size[0] == 0)
287 return 0.0;
288 return m_frameRate;
289}
290
291wxUint32 wxVideoXANIM::GetNbFrames() const
292{
293 if (m_size[0] == 0)
294 return 0;
295 return m_frames;
296}
297
298
299bool wxVideoXANIM::IsPaused() const
300{
301 return m_paused;
302}
303
304bool wxVideoXANIM::IsStopped() const
305{
306 return !m_xanim_started;
307}
308
309// -------------------------------------------------------------------------
310// Output management
311
312bool wxVideoXANIM::AttachOutput(wxWindow& out)
313{
314 if (!wxVideoBaseDriver::AttachOutput(out))
315 return FALSE;
316
317 return TRUE;
318}
319
320void 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
332bool 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
358bool 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) \
401totalOutput.ToULong(&my_long); \
402i = 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
447bool 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);
c42b1de6
GL
506 // Very useful ! Actually it "should" sends a SETSIZE event to XAnim
507 // FIXME: This event is not sent !!
e8482f24
GL
508
509 m_paused = FALSE;
510
511 return TRUE;
512}