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