]> git.saurik.com Git - wxWidgets.git/commitdiff
Major changes in wxVidXANIM (support for output filtering)
authorGuilhem Lavaux <lavaux@easynet.fr>
Fri, 25 Feb 2000 09:08:52 +0000 (09:08 +0000)
committerGuilhem Lavaux <lavaux@easynet.fr>
Fri, 25 Feb 2000 09:08:52 +0000 (09:08 +0000)
Several API addings
Added process.cpp, process.h and utilsunx.cpp in wxMMedia directory
They should be moved to src/unix, src/common and include/wx to use them

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6280 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

17 files changed:
utils/wxMMedia2/README
utils/wxMMedia2/board/Makefile.in
utils/wxMMedia2/board/mmbman.cpp
utils/wxMMedia2/board/mmboard.cpp
utils/wxMMedia2/lib/Makefile.in
utils/wxMMedia2/lib/sndaiff.cpp
utils/wxMMedia2/lib/sndaiff.h
utils/wxMMedia2/lib/sndfile.cpp
utils/wxMMedia2/lib/sndfile.h
utils/wxMMedia2/lib/sndwav.cpp
utils/wxMMedia2/lib/sndwav.h
utils/wxMMedia2/lib/vidbase.h
utils/wxMMedia2/lib/vidxanm.cpp
utils/wxMMedia2/lib/vidxanm.h
utils/wxMMedia2/process.cpp [new file with mode: 0644]
utils/wxMMedia2/process.h [new file with mode: 0644]
utils/wxMMedia2/utilsunx.cpp [new file with mode: 0644]

index c77db4f392d6b7f984005eaf6f6137b08ab6854c..bf90fb56cd5404be6c44faaf81e021ee735f7e6e 100644 (file)
@@ -30,10 +30,18 @@ Video features:
     time
 
 Video bugs:
-  * Recode windows port
+  * AVI file works on Windows
 
 CD features:
   * standard access to the CDAUDIO interface
 
 CD bugs:
 
+----------------
+| INSTALLATION |
+----------------
+
+You need to move the three files included in this directory:
+  - utilsunx.cpp => src/unix
+  - process.cpp => src/common
+  - process.h => include/wx
index c2d3ac1c619e124543351a4092f05cb2176c35b2..5a78dfddebe7a51be1d1195ac8c9c531786df82a 100644 (file)
@@ -15,22 +15,22 @@ program_dir = utils/wxMMedia2/board
 
 PROGRAM=mmboard
 
-OBJECTS=$(PROGRAM).o
+OBJECTS=mmboard.o mmbman.o
 
 EXTRA_CPPFLAGS= -I$(top_srcdir)/utils/wxMMedia2/lib
 
-EXTRA_LIBS= ../lib/libwxmmedia2.a
+EXTRA_LIBS= ../lib/libwxmmedia2.a -lesd
 # the comment at the end of the next line is needed because otherwise autoconf
 # would remove this line completely - it contains a built-in hack to remove
 # any VPATH assignment not containing ':'
-VPATH = @PATH_IFS@$(top_srcdir)/utils/wxMMedia2/sample # ':' for autoconf
+VPATH = @PATH_IFS@$(top_srcdir)/utils/wxMMedia2/board # ':' for autoconf
 
 include ../../../src/make.env
 
 .SUFFIXES: .o .cpp .c
 
 .cpp.o:
-       $(CC) $(CPPFLAGS) $(EXTRA_CPPFLAGS) -o $@ $<
+       $(CC) -c $(CPPFLAGS) $(EXTRA_CPPFLAGS) -o $@ $<
 
 all: $(PROGRAM)
 
index 1c813e1624c17e2fb0e1c1718a6f6e3c5b78695d..61f5f29b85987deea6d603b0758b31a48b406ce4 100644 (file)
@@ -126,7 +126,6 @@ public:
 
 protected:
   wxWindow *m_output_window;
-  wxInputStream *m_input_stream;
   wxVideoBaseDriver *m_video_driver;
 };
 
@@ -333,8 +332,6 @@ MMBoardVideoFile::~MMBoardVideoFile()
 {
     if (m_video_driver)
         delete m_video_driver;
-
-    delete m_input_stream;
 }
 
 bool MMBoardVideoFile::NeedWindow()
@@ -346,6 +343,12 @@ void MMBoardVideoFile::SetWindow(wxWindow *window)
 {
     m_output_window = window;
     m_video_driver->AttachOutput(*window);
+
+    wxSize size;
+    m_video_driver->GetSize(size);
+    window->SetSize(size);
+    // BAD BAD
+    window->GetParent()->GetSizer()->Fit(window->GetParent());
 }
 
 void MMBoardVideoFile::Play()
@@ -379,9 +382,13 @@ MMBoardTime MMBoardVideoFile::GetPosition()
 MMBoardTime MMBoardVideoFile::GetLength()
 {
     MMBoardTime btime;
+    int frameTime;
 
-    btime.seconds = 1;
-    btime.minutes = btime.hours = 0;
+    frameTime = (int)( m_video_driver->GetNbFrames() / m_video_driver->GetFrameRate());
+    
+    btime.seconds = frameTime % 60;
+    btime.minutes = (frameTime / 60) % 60;
+    btime.hours   = frameTime / 3600;
     return btime;
 }
 
@@ -402,7 +409,16 @@ wxString MMBoardVideoFile::GetStringType()
 
 wxString MMBoardVideoFile::GetStringInformation()
 {
-    return wxString(wxT("No info"));
+    wxString info;
+
+    info = wxT("Video codec: ");
+    info += m_video_driver->GetMovieCodec() + "\n";
+    info += wxT("Audio codec: ");
+    info += m_video_driver->GetAudioCodec();
+    info += wxString::Format(" Sample rate: %d Channels: %d\n", m_video_driver->GetSampleRate(),
+                             m_video_driver->GetBPS());
+    info += wxString::Format(" Frame rate: %.01f", m_video_driver->GetFrameRate());
+    return info;
 }
 
 // ----------------------------------------------------------------------------
index 4291ca950aa65a6f52c31289bcd6a7a75271f2f2..15e70bc960d64d271c34f7d30ac5528bb34c78b8 100644 (file)
@@ -205,11 +205,13 @@ wxUint8 MMBoardApp::TestMultimediaCaps()
 
   // We test the OSS (Open Sound System) support.
 
+#if 0
   dev = new wxSoundStreamOSS();
   if (dev->GetError() == wxSOUND_NOERR)
     caps |= MM_SOUND_OSS;
   delete dev;
 #endif
+#endif
 
 #ifdef __WIN32__
   // We test the Windows sound support.
index 9b11ab675de0ee10747290f9399133ff22363bb1..511e832f467624177596c5218df5386b2501b489 100644 (file)
@@ -17,7 +17,7 @@ VPATH= $(top_srcdir)/utils/wxMMedia2/lib
 LIBTARGET=libwxmmedia2
 
 OBJECTS=sndbase.o sndcodec.o sndpcm.o sndcpcm.o sndulaw.o sndfile.o sndoss.o\
-       sndaiff.o sndwav.o sndg72x.o \
+       sndesd.o sndaiff.o sndwav.o sndg72x.o \
        g711.o g721.o g723_24.o g723_40.o g72x.o \
        cdbase.o cdunix.o \
        vidbase.o vidxanm.o
index 1d450edfa4ceca582d52ebeb36eb2efa6c9710f9..2242cc263d3cae09e32ae16c409c06af58df100e 100644 (file)
@@ -42,6 +42,11 @@ wxSoundAiff::~wxSoundAiff()
 {
 }
 
+wxString wxSoundAiff::GetCodecName() const
+{
+    return "wxSoundAiff codec";
+}
+
 bool wxSoundAiff::CanRead()
 {
   wxUint32 signature1, signature2, len;
index bd9750380b9b9a2bd474332daef9fa9bf33ca7b2..20539e6fb04f7257215956be78d7c0611177951c 100644 (file)
 
 class wxSoundAiff: public wxSoundFileStream {
  public:
-  wxSoundAiff(wxInputStream& stream, wxSoundStream& io_sound);
-  wxSoundAiff(wxOutputStream& stream, wxSoundStream& io_sound);
-  ~wxSoundAiff();
-
-  bool CanRead();
-
+    wxSoundAiff(wxInputStream& stream, wxSoundStream& io_sound);
+    wxSoundAiff(wxOutputStream& stream, wxSoundStream& io_sound);
+    ~wxSoundAiff();
+    
+    bool CanRead();
+    wxString GetCodecName() const;
+    
  protected:
-  bool PrepareToPlay(); 
-  bool PrepareToRecord(unsigned long time);
-  bool FinishRecording();
-
-  wxUint32 GetData(void *buffer, wxUint32 len);
-  wxUint32 PutData(const void *buffer, wxUint32 len);
+    bool PrepareToPlay(); 
+    bool PrepareToRecord(unsigned long time);
+    bool FinishRecording();
+    
+    wxUint32 GetData(void *buffer, wxUint32 len);
+    wxUint32 PutData(const void *buffer, wxUint32 len);
 };
 
 #endif
index d5cec0e66f7949b8081250a25f0b9a74697cee6c..eea2ec9043a26b818c203e856e2c49abb55c77d8 100644 (file)
@@ -317,6 +317,11 @@ void wxSoundFileStream::FinishPreparation(wxUint32 len)
   m_prepared = TRUE;
 }
 
+wxString wxSoundFileStream::GetCodecName() const
+{
+    return wxString(wxT("wxSoundFileStream base codec"));
+}
+
 wxUint32 wxSoundFileStream::GetLength()
 {
   if (m_input && !m_prepared && GetError() == wxSOUND_NOERR)
index e6efd74780ce774c6aae110289fe1cb7be1465a3..c6fc91ad2c29e954981bd6132d42143d14e5c524 100644 (file)
@@ -90,6 +90,10 @@ class wxSoundFileStream: public wxSoundStream {
   // For this action, you must use wxSoundRouterStream applied to wxSoundFileStream. 
   bool SetSoundFormat(const wxSoundFormatBase& format);
 
+  // This function returns the Codec name. This is useful for those who want to build
+  // a player (But also in some other case).
+  virtual wxString GetCodecName() const;
+  
   // You should use this function to test whether this file codec can read the stream you passed
   // to it.
   virtual bool CanRead() { return FALSE; }
index 509a004009ea504e6021e15aa59d7f0bb41dcfc0..f1dbc0eca8c8ebe9a494ad4b9b9234a9d2022e9d 100644 (file)
@@ -48,6 +48,11 @@ wxSoundWave::~wxSoundWave()
 {
 }
 
+wxString wxSoundWave::GetCodecName() const
+{
+    return wxString(wxT("wxSoundWave codec"));
+}
+
 #define FAIL_WITH(condition, err) if (condition) { m_snderror = err; return FALSE; }
 
 bool wxSoundWave::CanRead()
index 7d4e380fe2a167e9f9bf7069f7a6f6b796bd1c0c..f9930c192dcd6e42ea2cefff7005bf9b3824b557 100644 (file)
 
 class wxSoundWave: public wxSoundFileStream {
  public:
-  wxSoundWave(wxInputStream& stream, wxSoundStream& io_sound);
-  wxSoundWave(wxOutputStream& stream, wxSoundStream& io_sound);
-  ~wxSoundWave();
-
-  bool CanRead();
-
+    wxSoundWave(wxInputStream& stream, wxSoundStream& io_sound);
+    wxSoundWave(wxOutputStream& stream, wxSoundStream& io_sound);
+    ~wxSoundWave();
+    
+    bool CanRead();
+    wxString GetCodecName() const;
+    
  protected:
-  bool PrepareToPlay(); 
-  bool PrepareToRecord(unsigned long time);
-  bool FinishRecording();
-
-  wxUint32 GetData(void *buffer, wxUint32 len);
-  wxUint32 PutData(const void *buffer, wxUint32 len);
-
-  bool HandleOutputPCM(wxDataInputStream& data, wxUint16 channels,
-                 wxUint32 sample_fq, wxUint32 byte_p_sec,
-                 wxUint16 byte_p_spl, wxUint16 bits_p_spl);
-  bool HandleOutputG721(wxDataInputStream& data, wxUint16 channels,
-                  wxUint32 sample_fq, wxUint32 byte_p_sec,
-                  wxUint16 byte_p_spl, wxUint16 bits_p_spl);
-  wxSoundFormatBase *HandleInputPCM(wxDataOutputStream& data);
-  wxSoundFormatBase *HandleInputG72X(wxDataOutputStream& data);
+    bool PrepareToPlay(); 
+    bool PrepareToRecord(unsigned long time);
+    bool FinishRecording();
+    
+    wxUint32 GetData(void *buffer, wxUint32 len);
+    wxUint32 PutData(const void *buffer, wxUint32 len);
+    
+    bool HandleOutputPCM(wxDataInputStream& data, wxUint16 channels,
+                         wxUint32 sample_fq, wxUint32 byte_p_sec,
+                         wxUint16 byte_p_spl, wxUint16 bits_p_spl);
+    bool HandleOutputG721(wxDataInputStream& data, wxUint16 channels,
+                          wxUint32 sample_fq, wxUint32 byte_p_sec,
+                          wxUint16 byte_p_spl, wxUint16 bits_p_spl);
+    wxSoundFormatBase *HandleInputPCM(wxDataOutputStream& data);
+    wxSoundFormatBase *HandleInputG72X(wxDataOutputStream& data);
 };
 
 #endif
index 7dd24aa09d61262b42afa68bf19151178b746f27..8d5d1d55eda06d2c7f402430eee1c1503dcd6139 100644 (file)
@@ -73,11 +73,24 @@ public:
     virtual bool Resume() = 0;
     
     // Size management
-    virtual bool Resize(wxUint16 w, wxUint16 h) = 0;
+    virtual bool SetSize(wxSize size) = 0;
     virtual bool GetSize(wxSize& size) const = 0;
     
     // Test the capability of the driver to handle the specified type
-    virtual bool IsCapable(wxVideoType WXUNUSED(v_type)) { return FALSE; }
+    virtual bool IsCapable(wxVideoType WXUNUSED(v_type)) const { return FALSE; }
+
+    // Return the video codec name
+    virtual wxString GetMovieCodec() const = 0;
+    // Return the audio codec name
+    virtual wxString GetAudioCodec() const = 0;
+    // Return misc info about audio
+    virtual wxUint32 GetSampleRate() const = 0;
+    virtual wxUint8 GetChannels() const = 0;
+    virtual wxUint8 GetBPS() const = 0;
+    // Return frame rate
+    virtual double GetFrameRate() const = 0;
+    // Return number of frames
+    virtual wxUint32 GetNbFrames() const = 0;
     
     // Called when the movie finished
     virtual void OnFinished() {}
@@ -87,8 +100,8 @@ public:
     virtual void DetachOutput();
     
     // They return the state of the movie.
-    virtual bool IsPaused() = 0;
-    virtual bool IsStopped() = 0;
+    virtual bool IsPaused() const = 0;
+    virtual bool IsStopped() const = 0;
 };
 
 WXDLLEXPORT wxFrame *wxVideoCreateFrame(wxVideoBaseDriver *vid_drv);
index a4ca4ef074a9426ecbcf22e84de26b109e548911..413f0c2e8bf6fc27ff8b3052bcae81a0dc52a85c 100644 (file)
@@ -32,6 +32,8 @@
 
 #include <wx/filefn.h>
 #include <wx/wfstream.h>
+#include <wx/datstrm.h>
+#include <wx/tokenzr.h>
 
 #define WXMMEDIA_INTERNAL
 #include "vidbase.h"
@@ -52,8 +54,19 @@ protected:
     wxVideoXANIM *m_vid_xanim;
 };
 
+class wxVideoXANIMOutput: public wxProcess {
+public:
+    wxVideoXANIMOutput();
+
+    void OnTerminate(int pid, int status);
+    
+    bool IsTerminated() const;
+protected:
+    bool m_terminated;
+};
+
 // -------------------------------------------------------------------------
-// XAnim video driver (implementation)
+// XAnim video driver (process handling implementation)
 
 wxVideoXANIMProcess::wxVideoXANIMProcess(wxVideoXANIM *xanim)
 {
@@ -66,6 +79,25 @@ void wxVideoXANIMProcess::OnTerminate(int WXUNUSED(pid), int WXUNUSED(status))
     m_vid_xanim->OnFinished();
 }
 
+wxVideoXANIMOutput::wxVideoXANIMOutput()
+        : wxProcess(NULL, TRUE, -1)
+{
+    m_terminated = FALSE;
+}
+
+bool wxVideoXANIMOutput::IsTerminated() const
+{
+    return m_terminated;
+}
+
+void wxVideoXANIMOutput::OnTerminate(int pid, int status)
+{
+    m_terminated = TRUE;
+}
+
+// -------------------------------------------------------------------------
+// XAnim video driver (implementation)
+
 wxVideoXANIM::wxVideoXANIM()
  : wxVideoBaseDriver()
 {
@@ -84,12 +116,16 @@ wxVideoXANIM::wxVideoXANIM(wxInputStream& str)
     m_xanim_detector = new wxVideoXANIMProcess(this);
     m_xanim_started  = FALSE;
     m_paused         = FALSE;
+    m_size[0]        = 0;
+    m_size[1]        = 0;
     
     m_filename       = wxGetTempFileName("vidxa");
     m_remove_file    = TRUE;
     wxFileOutputStream fout(m_filename);
     
     fout << str;
+
+    CollectInfo();
 }
 
 wxVideoXANIM::wxVideoXANIM(const wxString& filename)
@@ -101,6 +137,10 @@ wxVideoXANIM::wxVideoXANIM(const wxString& filename)
 
     m_filename       = filename;
     m_remove_file    = FALSE;
+    m_size[0]        = 0;
+    m_size[1]        = 0;
+    
+    CollectInfo();
 }
 
 wxVideoXANIM::~wxVideoXANIM()
@@ -114,6 +154,9 @@ wxVideoXANIM::~wxVideoXANIM()
         wxRemoveFile(m_filename);
 }
 
+// -------------------------------------------------------------------------
+// Movie controller
+
 bool wxVideoXANIM::Play()
 {
     if (!m_paused && m_xanim_started)
@@ -166,21 +209,30 @@ bool wxVideoXANIM::Stop()
     return TRUE;
 }
 
-bool wxVideoXANIM::Resize(wxUint16 w, wxUint16 h)
+// -------------------------------------------------------------------------
+// Movie size controller
+
+bool wxVideoXANIM::SetSize(wxSize size)
 {
     if (!m_video_output)
       return FALSE;
 
-    m_video_output->SetSize(w, h);
+    m_video_output->SetSize(size.GetWidth(), size.GetHeight());
     return FALSE;
 }
 
 bool wxVideoXANIM::GetSize(wxSize& size) const
 {
-    return FALSE;
+    if (m_size[0] == 0)
+        return FALSE;
+    size.Set(m_size[0], m_size[1]);
+    return TRUE;
 }
 
-bool wxVideoXANIM::IsCapable(wxVideoType v_type)
+// -------------------------------------------------------------------------
+// Capabilities of XAnim
+
+bool wxVideoXANIM::IsCapable(wxVideoType v_type) const
 {
     if (v_type == wxVIDEO_MSAVI || v_type == wxVIDEO_MPEG ||
        v_type == wxVIDEO_QT || v_type == wxVIDEO_GIF || v_type == wxVIDEO_JMOV ||
@@ -190,21 +242,77 @@ bool wxVideoXANIM::IsCapable(wxVideoType v_type)
         return FALSE;
 }
 
-bool wxVideoXANIM::IsPaused()
+// -------------------------------------------------------------------------
+// Movie state
+
+wxString wxVideoXANIM::GetMovieCodec() const
+{
+    if (m_size[0] == 0)
+        return wxT("");
+    return m_movieCodec;
+}
+
+wxString wxVideoXANIM::GetAudioCodec() const
+{
+    if (m_size[0] == 0)
+        return wxT("");
+    return m_audioCodec;
+}
+
+wxUint32 wxVideoXANIM::GetSampleRate() const
+{
+    if (m_size[0] == 0)
+        return 0;
+    return m_sampleRate;
+}
+
+wxUint8 wxVideoXANIM::GetChannels() const
+{
+    if (m_size[0] == 0)
+        return 0;
+    return m_channels;
+}
+
+wxUint8 wxVideoXANIM::GetBPS() const
+{
+    if (m_size[0] == 0)
+        return 0;
+    return m_bps;
+}
+
+double wxVideoXANIM::GetFrameRate() const
+{
+    if (m_size[0] == 0)
+        return 0.0;
+    return m_frameRate;
+}
+
+wxUint32 wxVideoXANIM::GetNbFrames() const
+{
+    if (m_size[0] == 0)
+        return 0;
+    return m_frames;
+}
+
+
+bool wxVideoXANIM::IsPaused() const
 {
     return m_paused;
 }
 
-bool wxVideoXANIM::IsStopped()
+bool wxVideoXANIM::IsStopped() const
 {
     return !m_xanim_started;
 }
 
+// -------------------------------------------------------------------------
+// Output management
+
 bool wxVideoXANIM::AttachOutput(wxWindow& out)
 {
     if (!wxVideoBaseDriver::AttachOutput(out))
         return FALSE;
-
+    
     return TRUE;
 }
 
@@ -217,6 +325,9 @@ void wxVideoXANIM::DetachOutput()
     wxVideoBaseDriver::DetachOutput();
 }
 
+// -------------------------------------------------------------------------
+// Lowlevel XAnim controller
+
 bool wxVideoXANIM::SendCommand(const char *command, char **ret,
                               wxUint32 *size)
 {
@@ -243,6 +354,95 @@ bool wxVideoXANIM::SendCommand(const char *command, char **ret,
     return TRUE;
 }
 
+bool wxVideoXANIM::CollectInfo()
+{
+    wxVideoXANIMOutput *xanimProcess;
+    wxString xanim_command;
+    wxStringTokenizer tokenizer;
+    
+    xanimProcess = new wxVideoXANIMOutput;
+    xanim_command = wxT("xanim +v +Zv -Ae ");
+    xanim_command += m_filename;
+    if (!wxExecute(xanim_command, FALSE, xanimProcess))
+        return FALSE;
+
+    wxInputStream *infoStream = xanimProcess->GetInputStream();
+    wxString totalOutput;
+        
+    while (infoStream->LastError() == wxSTREAM_NOERROR) {
+        char line[100];
+
+        infoStream->Read(line, sizeof(line)-1);
+        if (infoStream->LastRead() == 0)
+            break;
+        
+        line[infoStream->LastRead()] = 0;
+       
+        totalOutput += line;        
+    }
+
+    // This is good for everything ... :-)
+    int position = totalOutput.Find(wxT("Video Codec:"));
+    
+    totalOutput.Remove(0, position+13);
+
+    position = totalOutput.Find(wxT("depth="));
+    m_movieCodec = totalOutput(0, position);
+
+    totalOutput.Remove(0, position);
+    tokenizer.SetString(totalOutput, "\n\r");
+
+    // the rest of the line
+    wxString token = tokenizer.GetNextToken();
+    unsigned long my_long;
+    
+#define GETINT(i) \
+totalOutput.ToULong(&my_long); \
+i = my_long;
+    
+    // 'Audio Codec:'
+    totalOutput = tokenizer.GetString();
+    totalOutput.Remove(0, totalOutput.Find(wxT(":"))+2);
+
+    position = totalOutput.Find(wxT("Rate"));
+    m_audioCodec = totalOutput(0, position-1);
+
+    // 'Rate='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    GETINT(m_sampleRate);
+    // 'Chans='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    GETINT(m_channels);
+    // 'Bps='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    GETINT(m_bps);
+    // 'Frame Stats:'
+    tokenizer.Reinit(totalOutput);
+    tokenizer.GetNextToken();
+    totalOutput = tokenizer.GetString();
+    totalOutput.Remove(0, totalOutput.Find(wxT(":"))+2);
+    // 'Size='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    GETINT(m_size[0]);
+    // 'x'
+    totalOutput.Remove(0,1);
+    GETINT(m_size[1]);
+    // 'Frames='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    GETINT(m_frames);
+    // 'avfps='
+    totalOutput.Remove(0, totalOutput.Find(wxT("="))+1);
+    totalOutput.ToDouble(&m_frameRate);
+
+    // We wait for the conclusion
+    while (!xanimProcess->IsTerminated())
+        wxYield();
+
+    delete xanimProcess;
+
+    return TRUE;
+}
+
 bool wxVideoXANIM::RestartXANIM()
 {
     wxString xanim_command;
@@ -278,7 +478,7 @@ bool wxVideoXANIM::RestartXANIM()
                         (xanim_chg_size) ? _T("") : _T(""),
                         WXSTRINGCAST m_filename);
     
-    // Execute it
+        // Execute it
     if (!wxExecute(xanim_command, FALSE, m_xanim_detector))
         return FALSE;
     
@@ -294,8 +494,15 @@ bool wxVideoXANIM::RestartXANIM()
       wxYield();
     }
 
-    m_video_output->SetSize(m_video_output->GetSize());
-       // Very useful ! Actually it sends a SETSIZE event to XAnim
+    wxSize vibrato_size;
+    
+    vibrato_size = m_video_output->GetSize();
+    
+    vibrato_size.SetWidth(vibrato_size.GetWidth()+1);
+    m_video_output->SetSize(vibrato_size);
+    vibrato_size.SetWidth(vibrato_size.GetWidth()-1);
+    m_video_output->SetSize(vibrato_size);
+    // Very useful ! Actually it sends a SETSIZE event to XAnim
     
     m_paused = FALSE;
     
index 648e8816db8878fbbac33abab7b3d942d6de6189..6c82f2e0897c1a1eb97bd6d35693d907a02fc7fb 100644 (file)
@@ -67,7 +67,7 @@ typedef struct wxXANIMinternal {
 
 class WXDLLEXPORT wxVideoXANIM : public wxVideoBaseDriver {
     DECLARE_DYNAMIC_CLASS(wxVideoXANIM)
-protected:
+ protected:
     // Remember the state of the subprocess
     bool m_xanim_started, m_paused;
     // Pure X11 variables
@@ -76,7 +76,15 @@ protected:
     wxProcess *m_xanim_detector;
     // Remember to delete the temporary file when necessary
     bool m_remove_file;
-public:
+    wxUint32 m_size[2];
+    wxUint32 m_sampleRate;
+    wxUint8 m_channels;
+    wxUint8 m_bps;
+    wxUint32 m_frames;
+    double m_frameRate;
+    wxString m_movieCodec, m_audioCodec;
+    
+ public:
     wxVideoXANIM();
     wxVideoXANIM(wxInputStream& str);
     wxVideoXANIM(const wxString& filename);
@@ -88,16 +96,29 @@ public:
     bool Stop();
     
     bool SetVolume(wxUint8 vol);
-    bool Resize(wxUint16 w, wxUint16 h);
+    bool SetSize(wxSize size);
     bool GetSize(wxSize& size) const;
 
-    bool IsCapable(wxVideoType v_type);
+    // Return the video codec name
+    wxString GetMovieCodec() const;
+    // Return the audio codec name
+    wxString GetAudioCodec() const;
+    // Return misc info about audio
+    wxUint32 GetSampleRate() const;
+    wxUint8 GetChannels() const;
+    wxUint8 GetBPS() const;
+    // Return frame rate
+    double GetFrameRate() const;
+    // Return number of frames in the movie
+    wxUint32 GetNbFrames() const;
+    
+    bool IsCapable(wxVideoType v_type) const;
     
     bool AttachOutput(wxWindow& output);
     void DetachOutput();
     
-    bool IsPaused();
-    bool IsStopped();
+    bool IsPaused() const;
+    bool IsStopped() const;
     
     friend class wxVideoXANIMProcess;
     
@@ -107,6 +128,9 @@ protected:
     // Send a command to the subprocess
     bool SendCommand(const char *command,char **ret = NULL,
                      wxUint32 *size = NULL);
+
+    // Collect informations from XAnim
+    bool CollectInfo();
 };
 
 #endif
diff --git a/utils/wxMMedia2/process.cpp b/utils/wxMMedia2/process.cpp
new file mode 100644 (file)
index 0000000..e573fe8
--- /dev/null
@@ -0,0 +1,85 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        process.cpp
+// Purpose:     Process termination classes
+// Author:      Guilhem Lavaux
+// Modified by: Vadim Zeitlin to check error codes, added Detach() method
+// Created:     24/06/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Guilhem Lavaux
+// Licence:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+    #pragma implementation "process.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+    #include "wx/defs.h"
+#endif
+
+#include "wx/process.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler)
+IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent)
+
+wxProcess::wxProcess(wxEvtHandler *parent, bool needPipe, int id)
+{
+    if (parent)
+        SetNextHandler(parent);
+
+    m_id         = id;
+    m_needPipe   = needPipe;
+    m_in_stream  = NULL;
+    m_out_stream = NULL;
+}
+
+wxProcess::~wxProcess()
+{
+    if (m_in_stream)
+      delete m_in_stream;
+    if (m_out_stream)
+      delete m_out_stream;
+}
+
+void wxProcess::OnTerminate(int pid, int status)
+{
+    wxProcessEvent event(m_id, pid, status);
+
+    if ( !ProcessEvent(event) )
+        delete this;
+    //else: the object which processed the event is responsible for deleting
+    //      us!
+}
+
+void wxProcess::Detach()
+{
+    SetNextHandler(NULL);
+}
+
+void wxProcess::SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream)
+{
+    m_in_stream  = in_stream;
+    m_out_stream = out_stream;
+}
+
+wxInputStream *wxProcess::GetInputStream() const
+{
+    return m_in_stream;
+}
+
+wxOutputStream *wxProcess::GetOutputStream() const
+{
+    return m_out_stream;
+}
+
+bool wxProcess::NeedPipe() const
+{
+    return m_needPipe;
+}
diff --git a/utils/wxMMedia2/process.h b/utils/wxMMedia2/process.h
new file mode 100644 (file)
index 0000000..19ae35c
--- /dev/null
@@ -0,0 +1,86 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        process.h
+// Purpose:     wxProcess class
+// Author:      Guilhem Lavaux
+// Modified by: Vadim Zeitlin to check error codes, added Detach() method
+// Created:     24/06/98
+// RCS-ID:      $Id$
+// Copyright:   (c) 1998 Guilhem Lavaux
+// Licence:     wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_PROCESSH__
+#define _WX_PROCESSH__
+
+#ifdef __GNUG__
+    #pragma interface "process.h"
+#endif
+
+#include "wx/defs.h"
+#include "wx/object.h"
+#include "wx/event.h"
+#include "wx/stream.h"
+
+// Process Event handling
+class WXDLLEXPORT wxProcessEvent : public wxEvent
+{
+DECLARE_DYNAMIC_CLASS(wxProcessEvent)
+
+public:
+    wxProcessEvent(int id = 0, int pid = 0, int exitcode = 0) : wxEvent(id)
+    {
+        m_eventType = wxEVT_END_PROCESS;
+        m_pid = pid;
+        m_exitcode = exitcode;
+    }
+
+    // accessors
+        // PID of process which terminated
+    int GetPid() { return m_pid; }
+
+        // the exit code
+    int GetExitCode() { return m_exitcode; }
+
+public:
+    int m_pid, m_exitcode;
+};
+
+// A wxProcess object should be passed to wxExecute - than its OnTerminate()
+// function will be called when the process terminates.
+class WXDLLEXPORT wxProcess : public wxEvtHandler
+{
+DECLARE_DYNAMIC_CLASS(wxProcess)
+
+public:
+    wxProcess(wxEvtHandler *parent = (wxEvtHandler *) NULL, bool needPipe = FALSE, int id = -1);
+    ~wxProcess();
+
+    virtual void OnTerminate(int pid, int status);
+
+    // detach from the parent - should be called by the parent if it's deleted
+    // before the process it started terminates
+    void Detach();
+
+    // Pipe handling
+    wxInputStream *GetInputStream() const;
+    wxOutputStream *GetOutputStream() const;
+
+    // These functions should not be called by the usual user. They are only
+    // intended to be used by wxExecute.
+    // Install pipes
+    void SetPipeStreams(wxInputStream *in_stream, wxOutputStream *out_stream);
+    bool NeedPipe() const;
+
+protected:
+    int m_id;
+    bool m_needPipe;
+    wxInputStream *m_in_stream;
+    wxOutputStream *m_out_stream;
+};
+
+typedef void (wxObject::*wxProcessEventFunction)(wxProcessEvent&);
+
+#define EVT_END_PROCESS(id, func) { wxEVT_END_PROCESS, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxProcessEventFunction) & func, NULL},
+
+#endif
+    // _WX_PROCESSH__
diff --git a/utils/wxMMedia2/utilsunx.cpp b/utils/wxMMedia2/utilsunx.cpp
new file mode 100644 (file)
index 0000000..8e68bef
--- /dev/null
@@ -0,0 +1,798 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        utilsunx.cpp
+// Purpose:     generic Unix implementation of many wx functions
+// Author:      Vadim Zeitlin
+// Id:          $Id$
+// Copyright:   (c) 1998 Robert Roebling, Vadim Zeitlin
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/defs.h"
+#include "wx/string.h"
+
+#include "wx/intl.h"
+#include "wx/log.h"
+
+#include "wx/utils.h"
+#include "wx/process.h"
+#include "wx/thread.h"
+
+#include "wx/stream.h"
+
+#if wxUSE_GUI
+    #include "wx/unix/execute.h"
+#endif
+
+#include <stdarg.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <fcntl.h>          // for O_WRONLY and friends
+#include <time.h>           // nanosleep() and/or usleep()
+#include <ctype.h>          // isspace()
+#include <sys/time.h>       // needed for FD_SETSIZE
+
+#ifdef HAVE_UNAME
+    #include <sys/utsname.h> // for uname()
+#endif // HAVE_UNAME
+
+// ----------------------------------------------------------------------------
+// conditional compilation
+// ----------------------------------------------------------------------------
+
+// many versions of Unices have this function, but it is not defined in system
+// headers - please add your system here if it is the case for your OS.
+// SunOS < 5.6 (i.e. Solaris < 2.6) and DG-UX are like this.
+#if !defined(HAVE_USLEEP) && \
+    (defined(__SUN__) && !defined(__SunOs_5_6) && \
+                         !defined(__SunOs_5_7) && !defined(__SUNPRO_CC)) || \
+     defined(__osf__) || defined(__EMX__)
+    extern "C"
+    {
+        #ifdef __SUN__
+            int usleep(unsigned int usec);
+        #else // !Sun
+            #ifdef __EMX__
+                /* I copied this from the XFree86 diffs. AV. */
+                #define INCL_DOSPROCESS
+                #include <os2.h>
+                inline void usleep(unsigned long delay)
+                {
+                    DosSleep(delay ? (delay/1000l) : 1l);
+                }
+            #else // !Sun && !EMX
+                void usleep(unsigned long usec);
+            #endif
+        #endif // Sun/EMX/Something else
+    };
+
+    #define HAVE_USLEEP 1
+#endif // Unices without usleep()
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// sleeping
+// ----------------------------------------------------------------------------
+
+void wxSleep(int nSecs)
+{
+    sleep(nSecs);
+}
+
+void wxUsleep(unsigned long milliseconds)
+{
+#if defined(HAVE_NANOSLEEP)
+    timespec tmReq;
+    tmReq.tv_sec = (time_t)(milliseconds / 1000);
+    tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000;
+
+    // we're not interested in remaining time nor in return value
+    (void)nanosleep(&tmReq, (timespec *)NULL);
+#elif defined(HAVE_USLEEP)
+    // uncomment this if you feel brave or if you are sure that your version
+    // of Solaris has a safe usleep() function but please notice that usleep()
+    // is known to lead to crashes in MT programs in Solaris 2.[67] and is not
+    // documented as MT-Safe
+    #if defined(__SUN__) && wxUSE_THREADS
+        #error "usleep() cannot be used in MT programs under Solaris."
+    #endif // Sun
+
+    usleep(milliseconds * 1000); // usleep(3) wants microseconds
+#elif defined(HAVE_SLEEP)
+    // under BeOS sleep() takes seconds (what about other platforms, if any?)
+    sleep(milliseconds * 1000);
+#else // !sleep function
+    #error "usleep() or nanosleep() function required for wxUsleep"
+#endif // sleep function
+}
+
+// ----------------------------------------------------------------------------
+// process management
+// ----------------------------------------------------------------------------
+
+int wxKill(long pid, wxSignal sig)
+{
+    return kill((pid_t)pid, (int)sig);
+}
+
+#define WXEXECUTE_NARGS   127
+
+long wxExecute( const wxString& command, bool sync, wxProcess *process )
+{
+    wxCHECK_MSG( !command.IsEmpty(), 0, wxT("can't exec empty command") );
+
+    int argc = 0;
+    wxChar *argv[WXEXECUTE_NARGS];
+    wxString argument;
+    const wxChar *cptr = command.c_str();
+    wxChar quotechar = wxT('\0'); // is arg quoted?
+    bool escaped = FALSE;
+
+    // split the command line in arguments
+    do
+    {
+        argument=wxT("");
+        quotechar = wxT('\0');
+
+        // eat leading whitespace:
+        while ( wxIsspace(*cptr) )
+            cptr++;
+
+        if ( *cptr == wxT('\'') || *cptr == wxT('"') )
+            quotechar = *cptr++;
+
+        do
+        {
+            if ( *cptr == wxT('\\') && ! escaped )
+            {
+                escaped = TRUE;
+                cptr++;
+                continue;
+            }
+
+            // all other characters:
+            argument += *cptr++;
+            escaped = FALSE;
+
+            // have we reached the end of the argument?
+            if ( (*cptr == quotechar && ! escaped)
+                 || (quotechar == wxT('\0') && wxIsspace(*cptr))
+                 || *cptr == wxT('\0') )
+            {
+                wxASSERT_MSG( argc < WXEXECUTE_NARGS,
+                              wxT("too many arguments in wxExecute") );
+
+                argv[argc] = new wxChar[argument.length() + 1];
+                wxStrcpy(argv[argc], argument.c_str());
+                argc++;
+
+                // if not at end of buffer, swallow last character:
+                if(*cptr)
+                    cptr++;
+
+                break; // done with this one, start over
+            }
+        } while(*cptr);
+    } while(*cptr);
+    argv[argc] = NULL;
+
+    // do execute the command
+    long lRc = wxExecute(argv, sync, process);
+
+    // clean up
+    argc = 0;
+    while( argv[argc] )
+        delete [] argv[argc++];
+
+    return lRc;
+}
+
+bool wxShell(const wxString& command)
+{
+    wxString cmd;
+    if ( !!command )
+        cmd.Printf(wxT("xterm -e %s"), command.c_str());
+    else
+        cmd = command;
+
+    return wxExecute(cmd) != 0;
+}
+
+#if wxUSE_GUI
+
+void wxHandleProcessTermination(wxEndProcessData *proc_data)
+{
+    int pid = (proc_data->pid > 0) ? proc_data->pid : -(proc_data->pid);
+
+    // waitpid is POSIX so should be available everywhere, however on older
+    // systems wait() might be used instead in a loop (until the right pid
+    // terminates)
+    int status = 0;
+    int rc;
+
+    // wait for child termination and if waitpid() was interrupted, try again
+    do
+    {
+       rc = waitpid(pid, &status, 0);
+    }
+    while ( rc == -1 && errno == EINTR );
+
+
+    if( rc == -1 || ! (WIFEXITED(status) || WIFSIGNALED(status)) )
+    {
+       wxLogSysError(_("Waiting for subprocess termination failed"));
+       /* AFAIK, this can only happen if something went wrong within
+          wxGTK, i.e. due to a race condition or some serious bug.
+          After having fixed the order of statements in
+          GTK_EndProcessDetector(). (KB)
+       */
+    }
+    else
+    {
+        // notify user about termination if required
+        if (proc_data->process)
+        {
+            proc_data->process->OnTerminate(proc_data->pid,
+                                            WEXITSTATUS(status));
+        }
+        // clean up
+        if ( proc_data->pid > 0 )
+        {
+           delete proc_data;
+        }
+        else
+        {
+           // wxExecute() will know about it
+           proc_data->exitcode = status;
+
+           proc_data->pid = 0;
+        }
+    }
+}
+
+#endif // wxUSE_GUI
+
+#if wxUSE_GUI
+    #define WXUNUSED_UNLESS_GUI(p)  p
+#else
+    #define WXUNUSED_UNLESS_GUI(p)
+#endif
+
+// New wxStream classes to clean up the data when the process terminates
+
+#if wxUSE_GUI
+class wxProcessFileInputStream: public wxInputStream {
+ public:
+    wxProcessFileInputStream(int fd);
+    ~wxProcessFileInputStream();
+
+ protected: 
+    size_t OnSysRead(void *buffer, size_t bufsize);
+    off_t OnSysSeek(off_t seek, wxSeekMode mode);
+    off_t OnSysTell() const;
+
+ protected:
+    int m_fd;
+};
+
+class wxProcessFileOutputStream: public wxOutputStream {
+ public:
+    wxProcessFileOutputStream(int fd);
+    ~wxProcessFileOutputStream();
+
+ protected:
+    size_t OnSysWrite(const void *buffer, size_t bufsize);
+    off_t OnSysSeek(off_t seek, wxSeekMode mode);
+    off_t OnSysTell() const;
+
+ protected:
+    int m_fd;
+};
+
+wxProcessFileInputStream::wxProcessFileInputStream(int fd)
+{
+    m_fd = fd;
+}
+
+wxProcessFileInputStream::~wxProcessFileInputStream()
+{
+    close(m_fd);
+}
+
+size_t wxProcessFileInputStream::OnSysRead(void *buffer, size_t bufsize)
+{
+    int ret;
+
+    ret = read(m_fd, buffer, bufsize);
+    m_lasterror = wxSTREAM_NOERROR;
+    if (ret == 0)
+      m_lasterror = wxSTREAM_EOF;
+    if (ret == -1) {
+      m_lasterror = wxSTREAM_READ_ERROR;
+      ret = 0;
+    }
+    return ret;
+}
+
+off_t wxProcessFileInputStream::OnSysSeek(off_t WXUNUSED(seek),
+                                          wxSeekMode WXUNUSED(mode))
+{
+   return wxInvalidOffset;
+}
+
+off_t wxProcessFileInputStream::OnSysTell() const
+{
+   return wxInvalidOffset;
+}
+
+
+wxProcessFileOutputStream::wxProcessFileOutputStream(int fd)
+{
+    m_fd = fd;
+}
+
+wxProcessFileOutputStream::~wxProcessFileOutputStream()
+{
+    close(m_fd);
+}
+
+size_t wxProcessFileOutputStream::OnSysWrite(const void *buffer, size_t bufsize)
+{
+    int ret;
+
+    ret = write(m_fd, buffer, bufsize);
+    m_lasterror = wxSTREAM_NOERROR;
+    if (ret == -1) {
+      m_lasterror = wxSTREAM_WRITE_ERROR;
+      ret = 0;
+    }
+    return ret;
+}
+
+off_t wxProcessFileOutputStream::OnSysSeek(off_t WXUNUSED(seek),
+                                          wxSeekMode WXUNUSED(mode))
+{
+   return wxInvalidOffset;
+}
+
+off_t wxProcessFileOutputStream::OnSysTell() const
+{
+   return wxInvalidOffset;
+}
+
+#endif
+      
+long wxExecute(wxChar **argv,
+               bool sync,
+               wxProcess * WXUNUSED_UNLESS_GUI(process))
+{
+    wxCHECK_MSG( *argv, 0, wxT("can't exec empty command") );
+
+#if wxUSE_UNICODE
+    int mb_argc = 0;
+    char *mb_argv[WXEXECUTE_NARGS];
+
+    while (argv[mb_argc])
+    {
+      wxWX2MBbuf mb_arg = wxConvertWX2MB(argv[mb_argc]);
+      mb_argv[mb_argc] = strdup(mb_arg);
+      mb_argc++;
+    }
+    mb_argv[mb_argc] = (char *) NULL;
+
+    // this macro will free memory we used above
+    #define ARGS_CLEANUP                                 \
+        for ( mb_argc = 0; mb_argv[mb_argc]; mb_argc++ ) \
+            free(mb_argv[mb_argc])
+#else // ANSI
+    // no need for cleanup
+    #define ARGS_CLEANUP
+
+    wxChar **mb_argv = argv;
+#endif // Unicode/ANSI
+
+#if wxUSE_GUI
+    // create pipes
+    int end_proc_detect[2];
+    if (pipe(end_proc_detect) == -1)
+    {
+        wxLogSysError( _("Pipe creation failed") );
+
+        ARGS_CLEANUP;
+
+        return 0;
+    }
+#endif // wxUSE_GUI
+
+#if wxUSE_GUI
+    int in_pipe[2] = { -1, -1 };
+    int out_pipe[2] = { -1, -1 };
+    // Only asynchronous mode is interresting
+    if (!sync && process && process->NeedPipe())
+    {
+        if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1)
+        {
+            /* Free fds */
+            close(end_proc_detect[0]);
+            close(end_proc_detect[1]);
+            wxLogSysError( _("Pipe creation failed (Console pipes)") );
+
+            ARGS_CLEANUP;
+
+            return 0;
+        }
+    }
+#endif // wxUSE_GUI
+
+    // fork the process
+#ifdef HAVE_VFORK
+    pid_t pid = vfork();
+#else
+    pid_t pid = fork();
+#endif
+    if (pid == -1)
+    {
+#if wxUSE_GUI
+        close(end_proc_detect[0]);
+        close(end_proc_detect[1]);
+        close(in_pipe[0]);
+        close(in_pipe[1]);
+        close(out_pipe[0]);
+        close(out_pipe[1]);
+#endif
+        wxLogSysError( _("Fork failed") );
+
+        ARGS_CLEANUP;
+
+        return 0;
+    }
+    else if (pid == 0)
+    {
+#if wxUSE_GUI
+        // we're in child
+        close(end_proc_detect[0]); // close reading side
+#endif // wxUSE_GUI
+
+        // These three lines close the open file descriptors to to avoid any
+        // input/output which might block the process or irritate the user. If
+        // one wants proper IO for the subprocess, the right thing to do is
+        // to start an xterm executing it.
+        if (sync == 0)
+        {
+            // leave stderr opened, it won't do any hurm
+            for ( int fd = 0; fd < FD_SETSIZE; fd++ )
+            {
+#if wxUSE_GUI
+                if ( fd == end_proc_detect[1] || fd == in_pipe[0] || fd == out_pipe[1] )
+                    continue;
+#endif // wxUSE_GUI
+
+                if ( fd != STDERR_FILENO )
+                    close(fd);
+            }
+        }
+
+        // Fake a console by duplicating pipes
+#if wxUSE_GUI
+        if (in_pipe[0] != -1) {
+            dup2(in_pipe[0], STDIN_FILENO);
+            dup2(out_pipe[1], STDOUT_FILENO);
+            close(in_pipe[0]);
+            close(out_pipe[1]);
+        }
+#endif // wxUSE_GUI
+
+#if 0
+        close(STDERR_FILENO);
+
+        // some programs complain about stderr not being open, so redirect
+        // them:
+        open("/dev/null", O_RDONLY);  // stdin
+        open("/dev/null", O_WRONLY);  // stdout
+        open("/dev/null", O_WRONLY);  // stderr
+#endif
+
+        execvp (*mb_argv, mb_argv);
+
+        // there is no return after successful exec()
+        wxFprintf(stderr, _("Can't execute '%s'\n"), *argv);
+
+        _exit(-1);
+    }
+    else
+    {
+#if wxUSE_GUI
+        wxEndProcessData *data = new wxEndProcessData;
+
+        ARGS_CLEANUP;
+
+        if ( sync )
+        {
+            wxASSERT_MSG( !process, wxT("wxProcess param ignored for sync exec") );
+            data->process = NULL;
+
+            // sync execution: indicate it by negating the pid
+            data->pid      = -pid;
+            data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
+            // we're in parent
+            close(end_proc_detect[1]); // close writing side
+
+            // it will be set to 0 from GTK_EndProcessDetector
+            while (data->pid != 0)
+                wxYield();
+
+            int exitcode = data->exitcode;
+
+            delete data;
+
+            return exitcode;
+        }
+        else
+        {
+            // pipe initialization: construction of the wxStreams
+            if (process && process->NeedPipe()) {
+                // These two streams are relative to this process.
+                wxOutputStream *my_output_stream;
+                wxInputStream *my_input_stream;
+
+                my_output_stream = new wxProcessFileOutputStream(in_pipe[1]);
+                my_input_stream = new wxProcessFileInputStream(out_pipe[0]);
+                close(in_pipe[0]); // close reading side
+                close(out_pipe[1]); // close writing side
+
+                process->SetPipeStreams(my_input_stream, my_output_stream);
+            }
+
+            // async execution, nothing special to do - caller will be
+            // notified about the process termination if process != NULL, data
+            // will be deleted in GTK_EndProcessDetector
+            data->process  = process;
+            data->pid      = pid;
+            data->tag      = wxAddProcessCallback(data, end_proc_detect[0]);
+            // we're in parent
+            close(end_proc_detect[1]); // close writing side
+
+            return pid;
+        }
+#else // !wxUSE_GUI
+        wxASSERT_MSG( sync, wxT("async execution not supported yet") );
+
+        int exitcode = 0;
+        if ( waitpid(pid, &exitcode, 0) == -1 || !WIFEXITED(exitcode) )
+        {
+            wxLogSysError(_("Waiting for subprocess termination failed"));
+        }
+
+        return exitcode;
+#endif // wxUSE_GUI
+    }
+   return 0;
+
+    #undef ARGS_CLEANUP
+}
+
+// ----------------------------------------------------------------------------
+// file and directory functions
+// ----------------------------------------------------------------------------
+
+const wxChar* wxGetHomeDir( wxString *home  )
+{
+    *home = wxGetUserHome( wxString() );
+    if ( home->IsEmpty() )
+        *home = wxT("/");
+
+    return home->c_str();
+}
+
+#if wxUSE_UNICODE
+const wxMB2WXbuf wxGetUserHome( const wxString &user )
+#else // just for binary compatibility -- there is no 'const' here
+char *wxGetUserHome( const wxString &user )
+#endif
+{
+    struct passwd *who = (struct passwd *) NULL;
+
+    if ( !user )
+    {
+        wxChar *ptr;
+
+        if ((ptr = wxGetenv(wxT("HOME"))) != NULL)
+        {
+            return ptr;
+        }
+        if ((ptr = wxGetenv(wxT("USER"))) != NULL || (ptr = wxGetenv(wxT("LOGNAME"))) != NULL)
+        {
+            who = getpwnam(wxConvertWX2MB(ptr));
+        }
+
+        // We now make sure the the user exists!
+        if (who == NULL)
+        {
+            who = getpwuid(getuid());
+        }
+    }
+    else
+    {
+      who = getpwnam (user.mb_str());
+    }
+
+    return wxConvertMB2WX(who ? who->pw_dir : 0);
+}
+
+// ----------------------------------------------------------------------------
+// network and user id routines
+// ----------------------------------------------------------------------------
+
+// retrieve either the hostname or FQDN depending on platform (caller must
+// check whether it's one or the other, this is why this function is for
+// private use only)
+static bool wxGetHostNameInternal(wxChar *buf, int sz)
+{
+    wxCHECK_MSG( buf, FALSE, wxT("NULL pointer in wxGetHostNameInternal") );
+
+    *buf = wxT('\0');
+
+    // we're using uname() which is POSIX instead of less standard sysinfo()
+#if defined(HAVE_UNAME)
+    struct utsname uts;
+    bool ok = uname(&uts) != -1;
+    if ( ok )
+    {
+        wxStrncpy(buf, wxConvertMB2WX(uts.nodename), sz - 1);
+        buf[sz] = wxT('\0');
+    }
+#elif defined(HAVE_GETHOSTNAME)
+    bool ok = gethostname(buf, sz) != -1;
+#else // no uname, no gethostname
+    wxFAIL_MSG(wxT("don't know host name for this machine"));
+
+    bool ok = FALSE;
+#endif // uname/gethostname
+
+    if ( !ok )
+    {
+        wxLogSysError(_("Cannot get the hostname"));
+    }
+
+    return ok;
+}
+
+bool wxGetHostName(wxChar *buf, int sz)
+{
+    bool ok = wxGetHostNameInternal(buf, sz);
+
+    if ( ok )
+    {
+        // BSD systems return the FQDN, we only want the hostname, so extract
+        // it (we consider that dots are domain separators)
+        wxChar *dot = wxStrchr(buf, wxT('.'));
+        if ( dot )
+        {
+            // nuke it
+            *dot = wxT('\0');
+        }
+    }
+
+    return ok;
+}
+
+bool wxGetFullHostName(wxChar *buf, int sz)
+{
+    bool ok = wxGetHostNameInternal(buf, sz);
+
+    if ( ok )
+    {
+        if ( !wxStrchr(buf, wxT('.')) )
+        {
+            struct hostent *host = gethostbyname(wxConvertWX2MB(buf));
+            if ( !host )
+            {
+                wxLogSysError(_("Cannot get the official hostname"));
+
+                ok = FALSE;
+            }
+            else
+            {
+                // the canonical name
+                wxStrncpy(buf, wxConvertMB2WX(host->h_name), sz);
+            }
+        }
+        //else: it's already a FQDN (BSD behaves this way)
+    }
+
+    return ok;
+}
+
+bool wxGetUserId(wxChar *buf, int sz)
+{
+    struct passwd *who;
+
+    *buf = wxT('\0');
+    if ((who = getpwuid(getuid ())) != NULL)
+    {
+        wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+bool wxGetUserName(wxChar *buf, int sz)
+{
+    struct passwd *who;
+
+    *buf = wxT('\0');
+    if ((who = getpwuid (getuid ())) != NULL)
+    {
+        // pw_gecos field in struct passwd is not standard
+#if HAVE_PW_GECOS
+       char *comma = strchr(who->pw_gecos, ',');
+       if (comma)
+           *comma = '\0'; // cut off non-name comment fields
+       wxStrncpy (buf, wxConvertMB2WX(who->pw_gecos), sz - 1);
+#else // !HAVE_PW_GECOS
+       wxStrncpy (buf, wxConvertMB2WX(who->pw_name), sz - 1);
+#endif // HAVE_PW_GECOS/!HAVE_PW_GECOS
+       return TRUE;
+    }
+
+    return FALSE;
+}
+
+wxString wxGetOsDescription()
+{
+#ifndef WXWIN_OS_DESCRIPTION
+    #error WXWIN_OS_DESCRIPTION should be defined in config.h by configure
+#else
+    return WXWIN_OS_DESCRIPTION;
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// error and debug output routines (deprecated, use wxLog)
+// ----------------------------------------------------------------------------
+
+void wxDebugMsg( const char *format, ... )
+{
+  va_list ap;
+  va_start( ap, format );
+  vfprintf( stderr, format, ap );
+  fflush( stderr );
+  va_end(ap);
+}
+
+void wxError( const wxString &msg, const wxString &title )
+{
+  wxFprintf( stderr, _("Error ") );
+  if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
+  if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
+  wxFprintf( stderr, wxT(".\n") );
+}
+
+void wxFatalError( const wxString &msg, const wxString &title )
+{
+  wxFprintf( stderr, _("Error ") );
+  if (!title.IsNull()) wxFprintf( stderr, wxT("%s "), WXSTRINGCAST(title) );
+  if (!msg.IsNull()) wxFprintf( stderr, wxT(": %s"), WXSTRINGCAST(msg) );
+  wxFprintf( stderr, wxT(".\n") );
+  exit(3); // the same exit code as for abort()
+}
+