]>
Commit | Line | Data |
---|---|---|
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 | ||
92a19c2e | 11 | #include "wx/wxprec.h" |
e8482f24 GL |
12 | |
13 | #ifndef WX_PRECOMP | |
14 | #include <wx/wx.h> | |
15 | #endif | |
16 | ||
c9ce02ac | 17 | #ifdef __WXGTK__ |
e8482f24 GL |
18 | // Pizza ! |
19 | #include <wx/gtk/win_gtk.h> | |
c9ce02ac | 20 | #endif |
e8482f24 GL |
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 | { | |
dea7e44a | 76 | m_vid_xanim->m_xanim_started = false; |
e8482f24 GL |
77 | m_vid_xanim->OnFinished(); |
78 | } | |
79 | ||
80 | wxVideoXANIMOutput::wxVideoXANIMOutput() | |
dea7e44a | 81 | : wxProcess(NULL, wxID_ANY) |
e8482f24 | 82 | { |
dea7e44a | 83 | m_terminated = false; |
e8482f24 GL |
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 | { | |
dea7e44a | 94 | m_terminated = true; |
e8482f24 GL |
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); | |
dea7e44a WS |
105 | m_xanim_started = false; |
106 | m_paused = false; | |
6f568182 | 107 | m_filename = wxEmptyString; |
dea7e44a | 108 | m_remove_file = false; |
e8482f24 GL |
109 | } |
110 | ||
111 | wxVideoXANIM::wxVideoXANIM(wxInputStream& str) | |
112 | : wxVideoBaseDriver(str) | |
113 | { | |
114 | m_internal = new wxXANIMinternal; | |
115 | m_xanim_detector = new wxVideoXANIMProcess(this); | |
dea7e44a WS |
116 | m_xanim_started = false; |
117 | m_paused = false; | |
e8482f24 GL |
118 | m_size[0] = 0; |
119 | m_size[1] = 0; | |
120 | ||
6f568182 | 121 | m_filename = wxGetTempFileName(_T("vidxa")); |
dea7e44a | 122 | m_remove_file = true; |
e8482f24 GL |
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); | |
dea7e44a WS |
134 | m_xanim_started = false; |
135 | m_paused = false; | |
e8482f24 GL |
136 | |
137 | m_filename = filename; | |
dea7e44a | 138 | m_remove_file = false; |
e8482f24 GL |
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) | |
dea7e44a | 162 | return true; |
e8482f24 GL |
163 | if (!m_video_output) { |
164 | wxVideoCreateFrame(this); | |
dea7e44a | 165 | return true; |
e8482f24 GL |
166 | } |
167 | ||
168 | // The movie starts with xanim | |
169 | if (RestartXANIM()) { | |
dea7e44a WS |
170 | m_paused = false; |
171 | return true; | |
e8482f24 | 172 | } |
dea7e44a | 173 | return false; |
e8482f24 GL |
174 | } |
175 | ||
176 | bool wxVideoXANIM::Pause() | |
177 | { | |
178 | if (!m_paused && SendCommand(" ")) { | |
dea7e44a WS |
179 | m_paused = true; |
180 | return true; | |
e8482f24 | 181 | } |
dea7e44a | 182 | return false; |
e8482f24 GL |
183 | } |
184 | ||
185 | bool wxVideoXANIM::Resume() | |
186 | { | |
187 | if (m_paused && SendCommand(" ")) { | |
dea7e44a WS |
188 | m_paused = false; |
189 | return true; | |
e8482f24 | 190 | } |
dea7e44a | 191 | return false; |
e8482f24 GL |
192 | } |
193 | ||
194 | bool wxVideoXANIM::Stop() | |
195 | { | |
196 | if (!m_xanim_started) | |
dea7e44a | 197 | return false; |
e8482f24 GL |
198 | |
199 | SendCommand("q"); | |
200 | ||
201 | // We are waiting for the termination of the subprocess. | |
202 | while (m_xanim_started) { | |
203 | wxYield(); | |
204 | } | |
205 | ||
dea7e44a | 206 | m_paused = false; |
e8482f24 | 207 | |
dea7e44a | 208 | return true; |
e8482f24 GL |
209 | } |
210 | ||
211 | // ------------------------------------------------------------------------- | |
212 | // Movie size controller | |
213 | ||
214 | bool wxVideoXANIM::SetSize(wxSize size) | |
215 | { | |
216 | if (!m_video_output) | |
dea7e44a | 217 | return false; |
e8482f24 GL |
218 | |
219 | m_video_output->SetSize(size.GetWidth(), size.GetHeight()); | |
dea7e44a | 220 | return false; |
e8482f24 GL |
221 | } |
222 | ||
223 | bool wxVideoXANIM::GetSize(wxSize& size) const | |
224 | { | |
225 | if (m_size[0] == 0) | |
dea7e44a | 226 | return false; |
e8482f24 | 227 | size.Set(m_size[0], m_size[1]); |
dea7e44a | 228 | return true; |
e8482f24 GL |
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 || | |
dea7e44a WS |
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; | |
e8482f24 | 240 | else |
dea7e44a | 241 | return false; |
e8482f24 GL |
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)) | |
dea7e44a | 313 | return false; |
e8482f24 | 314 | |
dea7e44a | 315 | return true; |
e8482f24 GL |
316 | } |
317 | ||
318 | void wxVideoXANIM::DetachOutput() | |
319 | { | |
320 | SendCommand("q"); | |
dea7e44a WS |
321 | m_xanim_started = false; |
322 | m_paused = false; | |
e8482f24 GL |
323 | |
324 | wxVideoBaseDriver::DetachOutput(); | |
325 | } | |
326 | ||
327 | // ------------------------------------------------------------------------- | |
328 | // Lowlevel XAnim controller | |
329 | ||
330 | bool wxVideoXANIM::SendCommand(const char *command, char **ret, | |
dea7e44a | 331 | wxUint32 *size) |
e8482f24 GL |
332 | { |
333 | if (!m_xanim_started) | |
334 | if (!RestartXANIM()) | |
dea7e44a | 335 | return false; |
e8482f24 GL |
336 | |
337 | // Send a command to XAnim through X11 Property | |
338 | XChangeProperty(m_internal->xanim_dpy, m_internal->xanim_window, | |
dea7e44a WS |
339 | m_internal->xanim_atom, |
340 | XA_STRING, 8, PropModeReplace, (unsigned char *)command, | |
341 | strlen(command)); | |
e8482f24 GL |
342 | XFlush(m_internal->xanim_dpy); |
343 | if (ret) { | |
344 | int prop_format; | |
dea7e44a WS |
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); | |
e8482f24 | 352 | } |
dea7e44a | 353 | return true; |
e8482f24 GL |
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; | |
dea7e44a WS |
365 | if (!wxExecute(xanim_command, false, xanimProcess)) |
366 | return false; | |
e8482f24 GL |
367 | |
368 | wxInputStream *infoStream = xanimProcess->GetInputStream(); | |
369 | wxString totalOutput; | |
370 | ||
15e8daec | 371 | while (infoStream->GetLastError() == wxSTREAM_NO_ERROR) { |
e8482f24 GL |
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 | ||
6f568182 | 380 | totalOutput += wxString::FromAscii(line); |
e8482f24 GL |
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); | |
6f568182 | 392 | tokenizer.SetString(totalOutput, wxT("\n\r")); |
e8482f24 GL |
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 | ||
dea7e44a | 442 | return true; |
e8482f24 GL |
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) | |
dea7e44a | 457 | return false; |
e8482f24 GL |
458 | |
459 | // Check if we can change the size of the window dynamicly | |
dea7e44a | 460 | xanim_chg_size = true; |
e8482f24 GL |
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 | ||
15e8daec | 467 | m_internal->xanim_window = GDK_WINDOW_XWINDOW(window); |
e8482f24 GL |
468 | #endif |
469 | // Get the XANIM atom | |
470 | m_internal->xanim_atom = XInternAtom(m_internal->xanim_dpy, | |
dea7e44a | 471 | "XANIM_PROPERTY", False); |
e8482f24 GL |
472 | |
473 | // Build the command | |
7c8b87a7 WS |
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); | |
e8482f24 GL |
479 | |
480 | // Execute it | |
dea7e44a WS |
481 | if (!wxExecute(xanim_command, false, m_xanim_detector)) |
482 | return false; | |
e8482f24 GL |
483 | |
484 | // Wait for XAnim to be ready | |
485 | nitems = 0; | |
dea7e44a | 486 | m_xanim_started = true; |
e8482f24 GL |
487 | while (nitems == 0 && m_xanim_started) { |
488 | ret = XGetWindowProperty(m_internal->xanim_dpy, m_internal->xanim_window, | |
dea7e44a WS |
489 | m_internal->xanim_atom, |
490 | 0, 4, False, AnyPropertyType, &prop_type, | |
491 | &prop_format, &nitems, &extra, | |
492 | (unsigned char **)&prop); | |
e8482f24 GL |
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); | |
c42b1de6 GL |
504 | // Very useful ! Actually it "should" sends a SETSIZE event to XAnim |
505 | // FIXME: This event is not sent !! | |
e8482f24 | 506 | |
dea7e44a | 507 | m_paused = false; |
e8482f24 | 508 | |
dea7e44a | 509 | return true; |
e8482f24 | 510 | } |