* The Gtk+ interface is now built as a Debian package as well. The Gnome
authorSam Hocevar <sam@videolan.org>
Mon, 26 Feb 2001 12:16:29 +0000 (12:16 +0000)
committerSam Hocevar <sam@videolan.org>
Mon, 26 Feb 2001 12:16:29 +0000 (12:16 +0000)
    package depends on it because of the icon and menu entry.
  * Added an intf_WarnHexDump() function to do raw hexadecimal dumps of
    memory areas. For debugging purposes or for real men, as you wish.
  * Lots of tidying in dvd_ioctl.c, a few comments added.
  * Better error handling in the subpicture decoder.
  * Tidied video_spu.c. More to come later.
  * Fixed subtitle displaying. Will soon work in overlay mode as well.

26 files changed:
Makefile.in
debian/control
debian/rules
debian/vlc-gnome.menu [deleted file]
debian/vlc-gtk.menu [new file with mode: 0644]
debian/vlc.copyright
include/beos_window.h [deleted file]
include/intf_msg.h
include/video_graphics.h [deleted file]
plugins/beos/intf_beos.cpp
plugins/beos/vout_beos.cpp
plugins/beos/window.h [new file with mode: 0644]
plugins/dvd/dvd_ioctl.c
plugins/dvd/input_dvd.c
plugins/gtk/gtk_interface.c
plugins/gtk/intf_gtk.glade
src/interface/intf_msg.c
src/spu_decoder/spu_decoder.c
src/spu_decoder/spu_decoder.h
src/video_output/video_output.c
src/video_output/video_spu.c
src/video_output/video_spu.h
src/video_output/video_text.c
src/video_output/video_text.h
src/video_output/video_yuv.c
src/video_output/video_yuv.h

index 855f40f..546fa78 100644 (file)
@@ -451,7 +451,7 @@ all: vlc @ALIASES@ plugins
 clean:
        rm -f $(C_OBJ) $(CPP_OBJ) $(ASM_OBJ) $(STD_PLUGIN_OBJ)
        rm -f plugins/*/*.o src/*/*.o lib/*.so
-       rm -f vlc @ALIASES@
+       rm -f vlc kvlc gvlc
 
 distclean: clean
        rm -f src/*/*.o plugins/*/*.o **/*~ *.log
index e52a4b5..81e15eb 100644 (file)
@@ -7,8 +7,8 @@ Standards-Version: 3.0.1
 
 Package: vlc
 Architecture: any
-Depends: ${shlibs:Depends}, vlc-gnome
-Suggests: vlc-sdl, vlc-esd
+Depends: ${shlibs:Depends}, vlc-gtk
+Suggests: vlc-sdl, vlc-esd, vlc-gnome
 Description: the free MPEG and DVD player VideoLAN Client
  VideoLAN is a free MPEG, MPEG2 and DVD software solution.
  .
@@ -17,12 +17,20 @@ Description: the free MPEG and DVD player VideoLAN Client
 
 Package: vlc-gnome
 Architecture: any
-Depends: vlc (= ${Source-Version}), ${shlibs:Depends}
+Depends: vlc (= ${Source-Version}), vlc-gtk (= ${Source-Version}), ${shlibs:Depends}
 Description: Gnome plugin for the VideoLAN Client
  VideoLAN is a free MPEG, MPEG2 and DVD software solution.
  .
  This plugin adds a Gnome interface to the VideoLAN Client.
 
+Package: vlc-gtk
+Architecture: any
+Depends: vlc (= ${Source-Version}), ${shlibs:Depends}
+Description: Gtk+ plugin for the VideoLAN Client
+ VideoLAN is a free MPEG, MPEG2 and DVD software solution.
+ .
+ This plugin adds a Gtk+ interface to the VideoLAN Client.
+
 Package: vlc-esd
 Architecture: any
 Depends: vlc (= ${Source-Version}), ${shlibs:Depends}
index 8b2362a..4f49e92 100755 (executable)
@@ -16,13 +16,14 @@ build-stamp:
        ./configure --prefix=/usr \
                --mandir=\$${prefix}/share/man \
                --infodir=\$${prefix}/share/info \
-               --enable-gnome --enable-fb --with-glide --with-ggi \
-               --with-sdl --enable-esd --enable-alsa --disable-ppro ; \
+               --enable-gnome --enable-gtk --enable-fb --with-glide \
+               --with-ggi --with-sdl --enable-esd --enable-alsa \
+               --disable-ppro ; \
        else \
        ./configure --prefix=/usr \
                --mandir=\$${prefix}/share/man \
                --infodir=\$${prefix}/share/info \
-               --enable-gnome --enable-fb --with-ggi \
+               --enable-gnome --enable-gtk --enable-fb --with-ggi \
                --with-sdl --enable-esd --enable-alsa; \
        fi
 
@@ -48,7 +49,7 @@ install: build
        DESTDIR=`pwd`/debian/vlc/ $(MAKE) install prefix=/usr
 
        # make symlinks for packages
-       for alias in ggi gnome glide esd sdl alsa ; do \
+       for alias in ggi gtk gnome glide esd sdl alsa ; do \
                mkdir -p debian/vlc-$$alias/usr/share/doc/ ; \
                ln -s vlc debian/vlc-$$alias/usr/share/doc/vlc-$$alias ; \
                mkdir -p debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \
@@ -56,13 +57,13 @@ install: build
                        debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \
        done
 
-       mkdir -p debian/vlc-gnome/usr/bin/
-       mv debian/vlc/usr/bin/gvlc debian/vlc-gnome/usr/bin/
-       mkdir -p debian/vlc-gnome/usr/share/videolan/
+       mkdir -p debian/vlc-gtk/usr/bin/
+       mv debian/vlc/usr/bin/gvlc debian/vlc-gtk/usr/bin/
+       mkdir -p debian/vlc-gtk/usr/share/videolan/
        mv debian/vlc/usr/share/videolan/gvlc.png \
-               debian/vlc-gnome/usr/share/videolan/
-       mkdir -p debian/vlc-gnome/usr/share/man/man1/
-       ln -s vlc.1.gz debian/vlc-gnome/usr/share/man/man1/gvlc.1.gz
+               debian/vlc-gtk/usr/share/videolan/
+       mkdir -p debian/vlc-gtk/usr/share/man/man1/
+       ln -s vlc.1.gz debian/vlc-gtk/usr/share/man/man1/gvlc.1.gz
 
 # Build architecture-independent files here.
 binary-indep: build install
@@ -81,10 +82,10 @@ binary-arch: build install
 #      dh_installpam
 #      dh_installinit
        dh_installcron
-       dh_installmanpages -Nvlc-gnome -Nvlc-ggi -Nvlc-glide -Nvlc-esd -Nvlc-sdl -Nvlc-alsa
+       dh_installmanpages -Nvlc-gnome -Nvlc-gtk -Nvlc-ggi -Nvlc-glide -Nvlc-esd -Nvlc-sdl -Nvlc-alsa
        dh_installinfo
 #      dh_undocumented
-       dh_installchangelogs -Nvlc-gnome -Nvlc-ggi -Nvlc-glide -Nvlc-esd -Nvlc-sdl -Nvlc-alsa
+       dh_installchangelogs -Nvlc-gnome -Nvlc-gtk -Nvlc-ggi -Nvlc-glide -Nvlc-esd -Nvlc-sdl -Nvlc-alsa
        dh_link
        dh_strip
        dh_compress
diff --git a/debian/vlc-gnome.menu b/debian/vlc-gnome.menu
deleted file mode 100644 (file)
index e886e30..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-?package(vlc-gnome):command="/usr/bin/gvlc" hotkey="V" needs="X11" \
-                    section="Apps/Viewers" title="Gnome VideoLAN Client" \
-                    icon="/usr/share/videolan/gvlc.png"
diff --git a/debian/vlc-gtk.menu b/debian/vlc-gtk.menu
new file mode 100644 (file)
index 0000000..a0c6f7c
--- /dev/null
@@ -0,0 +1,3 @@
+?package(vlc-gtk):command="/usr/bin/gvlc" hotkey="V" needs="X11" \
+                  section="Apps/Viewers" title="Gnome/Gtk VideoLAN Client" \
+                  icon="/usr/share/videolan/gvlc.png"
index f3d5237..1331a58 100644 (file)
@@ -1,11 +1,11 @@
 This package was debianized by Samuel Hocevar <sam@zoy.org> on
 Mon, 13 Mar 2000 02:21:45 +0100.
 
-It was downloaded from ftp://ftp.videolan.org/pub/videolan/
+It was taken from the CVS tree. See http://www.videolan.org/cvs.html
 
 Upstream Author(s): The VideoLAN Team <videolan@videolan.org>
 
-VideoLAN is Copyright 1996, 1997, 1998, 1999, 2000 The VideoLAN Team
+VideoLAN is Copyright 1996, 1997, 1998, 1999, 2000, 2001 The VideoLAN Team
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the
diff --git a/include/beos_window.h b/include/beos_window.h
deleted file mode 100644 (file)
index e0abd47..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************************
- * beos_window.h: beos window class prototype
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors:
- * Jean-Marc Dressler
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-class VideoWindow : public BWindow
-{
-public:
-    // standard constructor and destructor
-    VideoWindow( BRect frame, const char *name,
-                 struct vout_thread_s *p_video_output); 
-    ~VideoWindow();
-
-    // standard window member
-    virtual bool    QuitRequested();
-    virtual void    FrameResized(float width, float height);
-    virtual void    MessageReceived(BMessage *message);
-    struct vout_thread_s   *p_vout;
-    BView * p_view;
-     
-    // additional events
-    bool            b_resized;
-};
-
-class InterfaceWindow : public BWindow
-{
-public:
-    InterfaceWindow( BRect frame, const char *name, intf_thread_t  *p_intf );
-    ~InterfaceWindow();
-
-    // standard window member
-    virtual bool    QuitRequested();
-    virtual void    MessageReceived(BMessage *message);
-    
-    intf_thread_t  *p_intf;
-};
-
-class InterfaceView : public BView
-{
-public:
-    InterfaceView();
-    ~InterfaceView();
-
-    virtual void    MessageReceived(BMessage *message);
-   
-};
index 82d38e4..903fce5 100644 (file)
@@ -85,3 +85,5 @@ void         intf_IntfMsg        ( char *psz_format, ... );
 void         intf_MsgImm         ( char *psz_format, ... );
 void         intf_ErrMsgImm      ( char *psz_format, ... );
 void         intf_WarnMsgImm     ( int i_level, char *psz_format, ... );
+void         intf_WarnHexDump    ( int i_level, void *p_data, int i_size );
+
diff --git a/include/video_graphics.h b/include/video_graphics.h
deleted file mode 100644 (file)
index 1290584..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*****************************************************************************
- * video_graphics.h: pictures manipulation primitives
- * Includes function to compose, convert and display pictures, and also basic
- * functions to copy pictures data or descriptors.
- *****************************************************************************
- * Copyright (C) 1999, 2000 VideoLAN
- *
- * Authors: Vincent Seguin <seguin@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Requires:
- *  "config.h"
- *  "common.h"
- *  "mtime.h"
- *  "video.h"
- *****************************************************************************/
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-
-
index 1ff3d8b..4607724 100644 (file)
@@ -2,7 +2,7 @@
  * intf_beos.cpp: beos interface
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: intf_beos.cpp,v 1.10 2001/02/20 07:49:12 sam Exp $
+ * $Id: intf_beos.cpp,v 1.11 2001/02/26 12:16:28 sam Exp $
  *
  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -61,7 +61,7 @@ extern "C"
 #include "main.h"
 }
 
-#include "beos_window.h"
+#include "window.h"
 
 /*****************************************************************************
  * intf_sys_t: description and status of FB interface
index 7ddd5d2..495a44b 100644 (file)
@@ -54,13 +54,13 @@ extern "C"
 #include "video.h"
 #include "video_output.h"
 
-#include "interface.h" /* XXX maybe to remove if beos_window.h is splitted */
+#include "interface.h" /* XXX maybe to remove if window.h is splitted */
 #include "intf_msg.h"
 
 #include "main.h"
 }
 
-#include "beos_window.h"
+#include "window.h"
 
 #define WIDTH 128
 #define HEIGHT 64
diff --git a/plugins/beos/window.h b/plugins/beos/window.h
new file mode 100644 (file)
index 0000000..af5c6fd
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * window.h: BeOS window class prototype
+ *****************************************************************************
+ * Copyright (C) 1999, 2000 VideoLAN
+ *
+ * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+class VideoWindow : public BWindow
+{
+public:
+    // standard constructor and destructor
+    VideoWindow( BRect frame, const char *name,
+                 struct vout_thread_s *p_video_output); 
+    ~VideoWindow();
+
+    // standard window member
+    virtual bool    QuitRequested();
+    virtual void    FrameResized(float width, float height);
+    virtual void    MessageReceived(BMessage *message);
+    struct vout_thread_s   *p_vout;
+    BView * p_view;
+     
+    // additional events
+    bool            b_resized;
+};
+
+class InterfaceWindow : public BWindow
+{
+public:
+    InterfaceWindow( BRect frame, const char *name, intf_thread_t  *p_intf );
+    ~InterfaceWindow();
+
+    // standard window member
+    virtual bool    QuitRequested();
+    virtual void    MessageReceived(BMessage *message);
+    
+    intf_thread_t  *p_intf;
+};
+
+class InterfaceView : public BView
+{
+public:
+    InterfaceView();
+    ~InterfaceView();
+
+    virtual void    MessageReceived(BMessage *message);
+   
+};
index 1723a2f..eeb9135 100644 (file)
@@ -2,7 +2,7 @@
  * dvd_ioctl.c: DVD ioctl replacement function
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd_ioctl.c,v 1.1 2001/02/20 07:49:12 sam Exp $
+ * $Id: dvd_ioctl.c,v 1.2 2001/02/26 12:16:28 sam Exp $
  *
  * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
  *          Samuel Hocevar <sam@zoy.org>
 #include "dvd_ioctl.h"
 
 /*****************************************************************************
- * Local prototypes
+ * Local prototypes - BeOS specific
  *****************************************************************************/
 #if defined( SYS_BEOS )
-static int  dvd_do_auth          ( int i_fd, dvd_authinfo *p_authinfo );
-static int  dvd_read_struct      ( int i_fd, dvd_struct *p_dvd );
-static int  dvd_read_physical    ( int i_fd, dvd_struct *p_dvd );
-static int  dvd_read_copyright   ( int i_fd, dvd_struct *p_dvd );
-static int  dvd_read_disckey     ( int i_fd, dvd_struct *p_dvd );
-static int  dvd_read_bca         ( int i_fd, dvd_struct *p_dvd );
-static int  dvd_read_manufact    ( int i_fd, dvd_struct *p_dvd );
-static int  communicate_with_dvd ( int i_fd,
-                                   struct cdrom_generic_command *p_cgc );
-static void init_cdrom_command   ( struct cdrom_generic_command *p_cgc,
-                                   void *buf, int i_len, int i_type );
-static void setup_report_key     ( struct cdrom_generic_command *p_cgc,
-                                   unsigned i_agid, unsigned i_type );
-static void setup_send_key       ( struct cdrom_generic_command *p_cgc,
-                                   unsigned i_agid, unsigned i_type );
+static int  ReadData          ( int i_fd, dvd_struct *p_dvd );
+static int  ReadCopyright     ( int i_fd, dvd_struct *p_dvd );
+static int  ReadKey           ( int i_fd, dvd_struct *p_dvd );
+static int  ReadBCA           ( int i_fd, dvd_struct *p_dvd );
+static int  ReadManufacturer  ( int i_fd, dvd_struct *p_dvd );
+
+static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
+                                void *buf, int i_len, int i_type );
+static void InitReadCommand   ( struct cdrom_generic_command *p_cgc,
+                                unsigned i_agid, unsigned i_type );
+static void InitWriteCommand  ( struct cdrom_generic_command *p_cgc,
+                                unsigned i_agid, unsigned i_type );
+
+static int  SendCommand ( int i_fd, struct cdrom_generic_command *p_cgc );
 #endif
 
 /*****************************************************************************
@@ -80,382 +79,262 @@ int dvd_ioctl( int i_fd, unsigned long i_op, void *p_arg )
     return( ioctl( i_fd, i_op, p_arg ) );
 
 #elif defined( SYS_BEOS )
-    switch ( i_op )
-    {
-    case DVD_AUTH:
-        return dvd_do_auth( i_fd, (dvd_authinfo *)p_arg );
 
-    case DVD_READ_STRUCT:
-        return dvd_read_struct( i_fd, (dvd_struct *)p_arg );
-
-    default:
-        intf_ErrMsg( "css error: unknown command 0x%x", i_op );
-        return -1;
-    }
-#else
+    int           i_ret;
+    unsigned char buf[20];
 
-    return -1;
-#endif
-}
+    struct cdrom_generic_command p_cgc;
 
-#if defined( SYS_BEOS )
+    dvd_struct *p_dvd = (dvd_struct *)p_arg;
+    dvd_authinfo *p_authinfo = (dvd_authinfo *)p_arg;
 
-/*****************************************************************************
- * setup_report_key
- *****************************************************************************/
-static void setup_report_key( struct cdrom_generic_command *p_cgc,
-                              unsigned i_agid, unsigned i_type )
-{
-    p_cgc->cmd[0] = GPCMD_REPORT_KEY;
-    p_cgc->cmd[10] = i_type | (i_agid << 6);
-
-    switch( i_type )
+    switch ( i_op )
     {
-        case 0:
-        case 8:
-        case 5:
-            p_cgc->buflen = 8;
-            break;
+        case DVD_AUTH: /* Request type is "authentication" */
+        {
+            memset( buf, 0, sizeof( buf ) );
+            InitGenericCommand( &p_cgc, buf, 0, CGC_DATA_READ );
 
-        case 1:
-            p_cgc->buflen = 16;
-            break;
+            switch( p_authinfo->type )
+            {
+                case DVD_LU_SEND_AGID: /* LU data send */
 
-        case 2:
-        case 4:
-            p_cgc->buflen = 12;
-            break;
-    }
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_AGID" );
 
-    p_cgc->cmd[9] = p_cgc->buflen;
-    p_cgc->data_direction = CGC_DATA_READ;
-}
+                    InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0 );
 
-/*****************************************************************************
- * setup_send_key
- *****************************************************************************/
-static void setup_send_key( struct cdrom_generic_command *p_cgc,
-                            unsigned i_agid, unsigned i_type )
-{
-    p_cgc->cmd[0] = GPCMD_SEND_KEY;
-    p_cgc->cmd[10] = i_type | (i_agid << 6);
+                    i_ret = SendCommand( i_fd, &p_cgc );
 
-    switch( i_type )
-    {
-        case 1:
-            p_cgc->buflen = 16;
-            break;
+                    p_authinfo->lsa.agid = buf[7] >> 6;
 
-        case 3:
-            p_cgc->buflen = 12;
-            break;
+                    return i_ret;
 
-        case 6:
-            p_cgc->buflen = 8;
-            break;
-    }
+                case DVD_LU_SEND_KEY1:
 
-    p_cgc->cmd[9] = p_cgc->buflen;
-    p_cgc->data_direction = CGC_DATA_WRITE;
-}
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY1" );
 
-/*****************************************************************************
- * init_cdrom_command
- *****************************************************************************/
-static void init_cdrom_command( struct cdrom_generic_command *p_cgc,
-                                void *buf, int i_len, int i_type )
-{
-    memset( p_cgc, 0, sizeof(struct cdrom_generic_command) );
+                    InitReadCommand( &p_cgc, p_authinfo->lsk.agid, 2 );
 
-    if (buf)
-    {
-        memset( buf, 0, i_len );
-    }
+                    i_ret = SendCommand( i_fd, &p_cgc );
 
-    p_cgc->buffer = (char *) buf;
-    p_cgc->buflen = i_len;
-    p_cgc->data_direction = i_type;
-    p_cgc->timeout = 255;
-}
+                    /* Copy the key */
+                    memcpy( p_authinfo->lsk.key, &buf[4], sizeof(dvd_key) );
 
-/* DVD handling */
+                    return i_ret;
 
-/*****************************************************************************
- * dvd_do_auth
- *****************************************************************************/
-static int dvd_do_auth( int i_fd, dvd_authinfo *p_authinfo )
-{
-    int i_ret;
-    unsigned char buf[20];
-    struct cdrom_generic_command p_cgc;
+                case DVD_LU_SEND_CHALLENGE:
 
-#define copy_key(dest,src)  memcpy((dest), (src), sizeof(dvd_key))
-#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
 
-#if 0
-    struct rpc_state_t rpc_state;
-#endif
+                    InitReadCommand( &p_cgc, p_authinfo->lsc.agid, 1 );
 
-    memset( buf, 0, sizeof(buf) );
-    init_cdrom_command( &p_cgc, buf, 0, CGC_DATA_READ );
+                    i_ret = SendCommand( i_fd, &p_cgc );
 
-    switch (p_authinfo->type)
-    {
-        /* LU data send */
-        case DVD_LU_SEND_AGID:
+                    /* Copy the challenge */
+                    memcpy( p_authinfo->lsc.chal, &buf[4],
+                            sizeof(dvd_challenge) );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_AGID" );
+                    return i_ret;
 
-            setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0);
+                case DVD_LU_SEND_TITLE_KEY: /* Post-auth key */
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_TITLE_KEY" );
 
-            p_authinfo->lsa.agid = buf[7] >> 6;
-            /* Returning data, let host change state */
+                    InitReadCommand( &p_cgc, p_authinfo->lstk.agid, 4 );
 
-            break;
+                    p_cgc.cmd[5] = p_authinfo->lstk.lba;
+                    p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
+                    p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
+                    p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
 
-        case DVD_LU_SEND_KEY1:
+                    i_ret = SendCommand( i_fd, &p_cgc );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY1" );
+                    p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
+                    p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
+                    p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
 
-            setup_report_key(&p_cgc, p_authinfo->lsk.agid, 2);
+                    /* Copy the key */
+                    memcpy( p_authinfo->lstk.title_key, &buf[5],
+                            sizeof(dvd_key) );
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                    return i_ret;
 
-            copy_key(p_authinfo->lsk.key, &buf[4]);
-            /* Returning data, let host change state */
+                case DVD_LU_SEND_ASF:
 
-            break;
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_ASF" );
 
-        case DVD_LU_SEND_CHALLENGE:
+                    InitReadCommand( &p_cgc, p_authinfo->lsasf.agid, 5 );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
+                    i_ret = SendCommand( i_fd, &p_cgc );
 
-            setup_report_key(&p_cgc, p_authinfo->lsc.agid, 1);
+                    p_authinfo->lsasf.asf = buf[7] & 1;
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
-
-            copy_chal(p_authinfo->lsc.chal, &buf[4]);
-            /* Returning data, let host change state */
+                    return i_ret;
 
-            break;
+                case DVD_HOST_SEND_CHALLENGE: /* LU data receive */
 
-        /* Post-auth key */
-        case DVD_LU_SEND_TITLE_KEY:
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_TITLE_KEY" );
+                    InitWriteCommand( &p_cgc, p_authinfo->hsc.agid, 1 );
+                    buf[1] = 0xe;
 
-            setup_report_key(&p_cgc, p_authinfo->lstk.agid, 4);
-            p_cgc.cmd[5] = p_authinfo->lstk.lba;
-            p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8;
-            p_cgc.cmd[3] = p_authinfo->lstk.lba >> 16;
-            p_cgc.cmd[2] = p_authinfo->lstk.lba >> 24;
-
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
-
-            p_authinfo->lstk.cpm = (buf[4] >> 7) & 1;
-            p_authinfo->lstk.cp_sec = (buf[4] >> 6) & 1;
-            p_authinfo->lstk.cgms = (buf[4] >> 4) & 3;
-            copy_key(p_authinfo->lstk.title_key, &buf[5]);
-            /* Returning data, let host change state */
-
-            break;
+                    /* Copy the challenge */
+                    memcpy( &buf[4], p_authinfo->hsc.chal,
+                            sizeof(dvd_challenge) );
 
-        case DVD_LU_SEND_ASF:
+                    if( (i_ret = SendCommand(i_fd, &p_cgc)) )
+                    {
+                        return i_ret;
+                    }
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_ASF" );
+                    p_authinfo->type = DVD_LU_SEND_KEY1;
 
-            setup_report_key(&p_cgc, p_authinfo->lsasf.agid, 5);
+                    return 0;
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                case DVD_HOST_SEND_KEY2:
 
-            p_authinfo->lsasf.asf = buf[7] & 1;
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY2" );
 
-            break;
+                    InitWriteCommand( &p_cgc, p_authinfo->hsk.agid, 3 );
+                    buf[1] = 0xa;
 
-        /* LU data receive (LU changes state) */
-        case DVD_HOST_SEND_CHALLENGE:
+                    /* Copy the key */
+                    memcpy( &buf[4], p_authinfo->hsk.key, sizeof(dvd_key) );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_CHALLENGE" );
+                    if( (i_ret = SendCommand(i_fd, &p_cgc)) )
+                    {
+                        p_authinfo->type = DVD_AUTH_FAILURE;
+                        return i_ret;
+                    }
 
-            setup_send_key(&p_cgc, p_authinfo->hsc.agid, 1);
-            buf[1] = 0xe;
-            copy_chal(&buf[4], p_authinfo->hsc.chal);
+                    p_authinfo->type = DVD_AUTH_ESTABLISHED;
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                    return 0;
 
-            p_authinfo->type = DVD_LU_SEND_KEY1;
+                case DVD_INVALIDATE_AGID: /* Misc */
 
-            break;
+                    intf_WarnMsg( 2, "css DoAuth: DVD_INVALIDATE_AGID" );
 
-        case DVD_HOST_SEND_KEY2:
+                    InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0x3f );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_KEY2" );
+                   return SendCommand( i_fd, &p_cgc );
 
-            setup_send_key(&p_cgc, p_authinfo->hsk.agid, 3);
-            buf[1] = 0xa;
-            copy_key(&buf[4], p_authinfo->hsk.key);
+                case DVD_LU_SEND_RPC_STATE: /* Get region settings */
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                p_authinfo->type = DVD_AUTH_FAILURE;
-                return i_ret;
-            }
-            p_authinfo->type = DVD_AUTH_ESTABLISHED;
+                    intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_RPC_STATE "
+                                     "(unimplemented)" );
 
-            break;
+        #if 0
+                    p_dvdetup_report_key( &p_cgc, 0, 8 );
+                    memset( &rpc_state, 0, sizeof(rpc_state_t) );
+                    p_cgc.buffer = (char *) &rpc_state;
 
-        /* Misc */
-        case DVD_INVALIDATE_AGID:
+                    if( (i_ret = SendCommand(i_fd, &p_cgc)) )
+                    {
+                        return i_ret;
+                    }
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_INVALIDATE_AGID" );
+                    p_authinfo->lrpcs.type = rpc_state.type_code;
+                    p_authinfo->lrpcs.vra = rpc_state.vra;
+                    p_authinfo->lrpcs.ucca = rpc_state.ucca;
+                    p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
+                    p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
+        #endif
 
-            setup_report_key(&p_cgc, p_authinfo->lsa.agid, 0x3f);
+                    return 0;
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                case DVD_HOST_SEND_RPC_STATE: /* Set region settings */
 
-            break;
+                    intf_WarnMsg( 2, "css DoAuth: DVD_HOST_SEND_RPC_STATE" );
 
-        /* Get region settings */
-        case DVD_LU_SEND_RPC_STATE:
+                    InitWriteCommand( &p_cgc, 0, 6 );
+                    buf[1] = 6;
+                    buf[4] = p_authinfo->hrpcs.pdrc;
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_RPC_STATE "
-                             "(unimplemented)" );
+                    return SendCommand( i_fd, &p_cgc );
 
-#if 0
-            p_dvdetup_report_key(&p_cgc, 0, 8);
-            memset(&rpc_state, 0, sizeof(rpc_state_t));
-            p_cgc.buffer = (char *) &rpc_state;
+                default:
+                    intf_ErrMsg( "css DoAuth: invalid DVD key ioctl" );
+                    return -1;
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
             }
+        }
 
-            p_authinfo->lrpcs.type = rpc_state.type_code;
-            p_authinfo->lrpcs.vra = rpc_state.vra;
-            p_authinfo->lrpcs.ucca = rpc_state.ucca;
-            p_authinfo->lrpcs.region_mask = rpc_state.region_mask;
-            p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
-#endif
+        case DVD_READ_STRUCT: /* Request type is "read structure" */
+        {
+            switch( p_dvd->type )
+            {
+                case DVD_STRUCT_PHYSICAL:
 
-            break;
+                    intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_PHYSICAL" );
 
-        /* Set region settings */
-        case DVD_HOST_SEND_RPC_STATE:
+                    return ReadData( i_fd, p_dvd );
 
-            intf_WarnMsg( 2, "css dvd_do_auth: DVD_HOST_SEND_RPC_STATE" );
+                case DVD_STRUCT_COPYRIGHT:
 
-            setup_send_key(&p_cgc, 0, 6);
-            buf[1] = 6;
-            buf[4] = p_authinfo->hrpcs.pdrc;
+                    intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_COPYRIGHT" );
 
-            /* handle uniform packets for scsi type devices (scsi,atapi) */
-            if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
-            {
-                return i_ret;
-            }
+                    return ReadCopyright( i_fd, p_dvd );
 
-            break;
+                case DVD_STRUCT_DISCKEY:
 
-        default:
-            intf_ErrMsg( "css dvd_do_auth: invalid DVD key ioctl" );
-            return -1;
+                    intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_DISCKEY" );
 
-    }
+                    return ReadKey( i_fd, p_dvd );
 
-    return 0;
-}
+                case DVD_STRUCT_BCA:
 
-/*****************************************************************************
- * dvd_read_struct
- *****************************************************************************/
-static int dvd_read_struct( int i_fd, dvd_struct *p_dvd )
-{
-    switch (p_dvd->type)
-    {
-        case DVD_STRUCT_PHYSICAL:
-
-            intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_PHYSICAL" );
-            return dvd_read_physical(i_fd, p_dvd);
-
-        case DVD_STRUCT_COPYRIGHT:
-
-            intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_COPYRIGHT" );
-            return dvd_read_copyright(i_fd, p_dvd);
+                    intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_BCA" );
 
-        case DVD_STRUCT_DISCKEY:
+                    return ReadBCA( i_fd, p_dvd );
 
-            intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_DISCKEY" );
-            return dvd_read_disckey(i_fd, p_dvd);
+                case DVD_STRUCT_MANUFACT:
 
-        case DVD_STRUCT_BCA:
+                    intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_MANUFACT" );
 
-            intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_BCA" );
-            return dvd_read_bca(i_fd, p_dvd);
+                    return ReadManufacturer( i_fd, p_dvd );
 
-        case DVD_STRUCT_MANUFACT:
+                default:
+                    intf_WarnMsg( 2, "css ReadStruct: invalid request (%d)",
+                                  p_dvd->type );
 
-            intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_MANUFACT" );
-            return dvd_read_manufact(i_fd, p_dvd);
+                    return -1;
+            }
+        }
 
-        default:
-            intf_WarnMsg( 2, "css dvd_read_struct: invalid request (%d)",
-                          p_dvd->type );
+        default: /* Unknown request type */
+        {
+            intf_ErrMsg( "css error: unknown command 0x%x", i_op );
             return -1;
+        }
     }
+#else
+
+    return -1;
+#endif
 }
 
+/* Local prototypes */
+
+#if defined( SYS_BEOS )
 /*****************************************************************************
- * dvd_read_physical
+ * ReadData: Get data structure information from the DVD.
  *****************************************************************************/
-static int dvd_read_physical( int i_fd, dvd_struct *p_dvd )
+static int ReadData( int i_fd, dvd_struct *p_dvd )
 {
     int i_ret, i;
     u_char buf[4 + 4 * 20], *base;
     struct dvd_layer *layer;
     struct cdrom_generic_command cgc;
 
-    init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+    InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
 
     cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
     cgc.cmd[6] = p_dvd->physical.layer_num;
     cgc.cmd[7] = p_dvd->type;
     cgc.cmd[9] = cgc.buflen & 0xff;
 
-    /* handle uniform packets for scsi type devices (scsi,atapi) */
-    if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
+    if( (i_ret = SendCommand(i_fd, &cgc)) )
     {
         return i_ret;
     }
@@ -488,15 +367,15 @@ static int dvd_read_physical( int i_fd, dvd_struct *p_dvd )
 }
 
 /*****************************************************************************
- * dvd_read_copyright
+ * ReadCopyright: get copyright information from the DVD.
  *****************************************************************************/
-static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
+static int ReadCopyright( int i_fd, dvd_struct *p_dvd )
 {
     int i_ret;
     u_char buf[8];
     struct cdrom_generic_command cgc;
 
-    init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+    InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
 
     cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
     cgc.cmd[6] = p_dvd->copyright.layer_num;
@@ -504,8 +383,7 @@ static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
     cgc.cmd[8] = cgc.buflen >> 8;
     cgc.cmd[9] = cgc.buflen & 0xff;
 
-    /* handle uniform packets for scsi type devices (scsi,atapi) */
-    if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
+    if( (i_ret = SendCommand(i_fd, &cgc)) )
     {
         return i_ret;
     }
@@ -517,9 +395,9 @@ static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
 }
 
 /*****************************************************************************
- * dvd_read_disckey
+ * ReadKey: get a key from the DVD.
  *****************************************************************************/
-static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
+static int ReadKey( int i_fd, dvd_struct *p_dvd )
 {
     int i_ret, size;
     u_char *buf;
@@ -533,17 +411,17 @@ static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
         return -ENOMEM;
     }
 #endif
-    buf = (u_char *) malloc(size);
+    buf = (u_char *) malloc( size );
+
+    InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
 
-    init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);
     cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
     cgc.cmd[7] = p_dvd->type;
     cgc.cmd[8] = size >> 8;
     cgc.cmd[9] = size & 0xff;
     cgc.cmd[10] = p_dvd->disckey.agid << 6;
 
-    /* handle uniform packets for scsi type devices (scsi,atapi) */
-    if( !(i_ret = communicate_with_dvd(i_fd, &cgc)) )
+    if( !(i_ret = SendCommand(i_fd, &cgc)) )
     {
         memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) );
     }
@@ -553,21 +431,24 @@ static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
 }
 
 /*****************************************************************************
- * dvd_read_bca
+ * ReadBCA: read the Burst Cutting Area of a DVD.
+ *****************************************************************************
+ * The BCA is a special part of the DVD which is used to burn additional
+ * data after it has been manufactured. DIVX is an exemple.
  *****************************************************************************/
-static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
+static int ReadBCA( int i_fd, dvd_struct *p_dvd )
 {
     int i_ret;
     u_char buf[4 + 188];
     struct cdrom_generic_command cgc;
 
-    init_cdrom_command( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+    InitGenericCommand( &cgc, buf, sizeof(buf), CGC_DATA_READ );
+
     cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
     cgc.cmd[7] = p_dvd->type;
     cgc.cmd[9] = cgc.buflen = 0xff;
 
-    /* handle uniform packets for scsi type devices (scsi,atapi) */
-    if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
+    if( (i_ret = SendCommand(i_fd, &cgc)) )
     {
         return i_ret;
     }
@@ -575,7 +456,7 @@ static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
     p_dvd->bca.len = buf[0] << 8 | buf[1];
     if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 )
     {
-        intf_ErrMsg("css error: invalid BCA length (%d)", p_dvd->bca.len );
+        intf_ErrMsg( "css error: invalid BCA length (%d)", p_dvd->bca.len );
         return -1;
     }
 
@@ -585,15 +466,15 @@ static int dvd_read_bca( int i_fd, dvd_struct *p_dvd )
 }
 
 /*****************************************************************************
- * dvd_read_manufact
+ * ReadManufacturer: get manufacturer information from the DVD.
  *****************************************************************************/
-static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
+static int ReadManufacturer( int i_fd, dvd_struct *p_dvd )
 {
     int i_ret = 0, size;
     u_char *buf;
     struct cdrom_generic_command cgc;
 
-    size = sizeof(p_dvd->manufact.value) + 4;
+    size = sizeof( p_dvd->manufact.value ) + 4;
 
 #if 0
     if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL )
@@ -603,14 +484,14 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
 #endif
     buf = (u_char *) malloc(size);
 
-    init_cdrom_command( &cgc, buf, size, CGC_DATA_READ );
+    InitGenericCommand( &cgc, buf, size, CGC_DATA_READ );
+
     cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
     cgc.cmd[7] = p_dvd->type;
     cgc.cmd[8] = size >> 8;
     cgc.cmd[9] = size & 0xff;
 
-    /* handle uniform packets for scsi type devices (scsi,atapi) */
-    if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
+    if( (i_ret = SendCommand(i_fd, &cgc)) )
     {
         return i_ret;
     }
@@ -618,8 +499,8 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
     p_dvd->manufact.len = buf[0] << 8 | buf[1];
     if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
     {
-        intf_ErrMsg( "css error: invalid manufacturer info length "
-                     "(%d)\n", p_dvd->bca.len );
+        intf_ErrMsg( "css error: invalid manufacturer info length (%d)",
+                     p_dvd->bca.len );
         i_ret = -1;
     }
     else
@@ -632,11 +513,104 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
 }
 
 /*****************************************************************************
- * communicate_with_dvd
+ * InitGenericCommand: initialize a CGC structure
+ *****************************************************************************
+ * This function initializes a CDRom Generic Command structure for
+ * future use, either a read command or a write command.
  *****************************************************************************/
-static int communicate_with_dvd( int i_fd,
-                                 struct cdrom_generic_command *p_cgc )
+static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
+                                void *buf, int i_len, int i_type )
 {
+    memset( p_cgc, 0, sizeof( struct cdrom_generic_command ) );
+
+    if( buf != NULL )
+    {
+        memset( buf, 0, i_len );
+    }
+
+    p_cgc->buffer = ( char * )buf;
+    p_cgc->buflen = i_len;
+    p_cgc->data_direction = i_type;
+    p_cgc->timeout = 255;
+}
+
+/*****************************************************************************
+ * InitReadCommand: fill a CGC structure for reading purposes.
+ *****************************************************************************
+ * This function fills a CDRom Generic Command for a command which will
+ * read data from the DVD.
+ *****************************************************************************/
+static void InitReadCommand( struct cdrom_generic_command *p_cgc,
+                             unsigned i_agid, unsigned i_type )
+{
+    p_cgc->cmd[0] = GPCMD_REPORT_KEY;
+    p_cgc->cmd[10] = i_type | (i_agid << 6);
+
+    /* FIXME: check what i_type means */
+    switch( i_type )
+    {
+        case 0:
+        case 8:
+        case 5:
+            p_cgc->buflen = 8;
+            break;
+
+        case 1:
+            p_cgc->buflen = 16;
+            break;
+
+        case 2:
+        case 4:
+            p_cgc->buflen = 12;
+            break;
+    }
+
+    p_cgc->cmd[9] = p_cgc->buflen;
+    p_cgc->data_direction = CGC_DATA_READ;
+}
+
+/*****************************************************************************
+ * InitWriteCommand: fill a CGC structure for writing purposes.
+ *****************************************************************************
+ * This function fills a CDRom Generic Command for a command which will
+ * send data to the DVD.
+ *****************************************************************************/
+static void InitWriteCommand( struct cdrom_generic_command *p_cgc,
+                              unsigned i_agid, unsigned i_type )
+{
+    p_cgc->cmd[0] = GPCMD_SEND_KEY;
+    p_cgc->cmd[10] = i_type | (i_agid << 6);
+
+    /* FIXME: check what i_type means */
+    switch( i_type )
+    {
+        case 1:
+            p_cgc->buflen = 16;
+            break;
+
+        case 3:
+            p_cgc->buflen = 12;
+            break;
+
+        case 6:
+            p_cgc->buflen = 8;
+            break;
+    }
+
+    p_cgc->cmd[9] = p_cgc->buflen;
+    p_cgc->data_direction = CGC_DATA_WRITE;
+}
+
+/*****************************************************************************
+ * SendCommand: send a raw device command to the DVD drive.
+ *****************************************************************************
+ * This is the most important part of the ioctl emulation, the place where
+ * data is really sent to the DVD.
+ *****************************************************************************/
+static int SendCommand( int i_fd, struct cdrom_generic_command *p_cgc )
+{
+    int i;
+
     raw_device_command rdc;
     memset( &rdc, 0, sizeof( rdc ) );
 
@@ -654,22 +628,14 @@ static int communicate_with_dvd( int i_fd,
     }
 
     rdc.command_length = 12;
-    rdc.command[0] = p_cgc->cmd[0];
-    rdc.command[1] = p_cgc->cmd[1];
-    rdc.command[2] = p_cgc->cmd[2];
-    rdc.command[3] = p_cgc->cmd[3];
-    rdc.command[4] = p_cgc->cmd[4];
-    rdc.command[5] = p_cgc->cmd[5];
-    rdc.command[6] = p_cgc->cmd[6];
-    rdc.command[7] = p_cgc->cmd[7];
-    rdc.command[8] = p_cgc->cmd[8];
-    rdc.command[9] = p_cgc->cmd[9];
-    rdc.command[10] = p_cgc->cmd[10];
-    rdc.command[11] = p_cgc->cmd[11];
-    rdc.command[12] = p_cgc->cmd[12];
+
+    /* FIXME: check if this _really_ should go up to [12] */
+    for( i = 0 ; i < 13 ; i++ )
+    {
+        rdc.command[i] = p_cgc->cmd[i];
+    }
 
     return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
 }
-
 #endif
 
index 07f8fc5..cc74c3a 100644 (file)
@@ -10,7 +10,7 @@
  *  -dvd_udf to find files
  *****************************************************************************
  * Copyright (C) 1998-2001 VideoLAN
- * $Id: input_dvd.c,v 1.20 2001/02/22 08:59:54 stef Exp $
+ * $Id: input_dvd.c,v 1.21 2001/02/26 12:16:28 sam Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -711,7 +711,7 @@ static void DVDInit( input_thread_t * p_input )
     /* FIXME: We consider here that one title is one title set
      * it is not true !!! */
 
-    intf_WarnMsg( 2, "DVD: Number of titles: %d\n",
+    intf_WarnMsg( 2, "DVD: Number of titles: %d",
                   p_method->ifo.vmg.mat.i_tts_nb );
 
 #define area p_input->stream.pp_areas
index 5dd7196..7376498 100644 (file)
@@ -634,8 +634,7 @@ create_intf_about (void)
   GtkWidget *vbox3;
   GtkWidget *label14;
   GtkWidget *label18;
-  GtkWidget *hbox1;
-  GtkWidget *label15;
+  GtkWidget *frame1;
   GtkWidget *label16;
   GtkWidget *label17;
   GtkWidget *dialog_action_area;
@@ -673,40 +672,32 @@ create_intf_about (void)
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label18);
   gtk_box_pack_start (GTK_BOX (vbox3), label18, FALSE, FALSE, 0);
+  gtk_label_set_justify (GTK_LABEL (label18), GTK_JUSTIFY_LEFT);
+  gtk_misc_set_padding (GTK_MISC (label18), 0, 5);
 
-  hbox1 = gtk_hbox_new (FALSE, 0);
-  gtk_widget_ref (hbox1);
-  gtk_object_set_data_full (GTK_OBJECT (intf_about), "hbox1", hbox1,
+  frame1 = gtk_frame_new (_("Authors"));
+  gtk_widget_ref (frame1);
+  gtk_object_set_data_full (GTK_OBJECT (intf_about), "frame1", frame1,
                             (GtkDestroyNotify) gtk_widget_unref);
-  gtk_widget_show (hbox1);
-  gtk_box_pack_start (GTK_BOX (vbox3), hbox1, FALSE, FALSE, 0);
-
-  label15 = gtk_label_new (_("Authors:"));
-  gtk_widget_ref (label15);
-  gtk_object_set_data_full (GTK_OBJECT (intf_about), "label15", label15,
-                            (GtkDestroyNotify) gtk_widget_unref);
-  gtk_widget_show (label15);
-  gtk_box_pack_start (GTK_BOX (hbox1), label15, FALSE, FALSE, 0);
-  gtk_label_set_justify (GTK_LABEL (label15), GTK_JUSTIFY_RIGHT);
-  gtk_misc_set_alignment (GTK_MISC (label15), 0.5, 1.67638e-08);
-  gtk_misc_set_padding (GTK_MISC (label15), 0, 10);
+  gtk_widget_show (frame1);
+  gtk_box_pack_start (GTK_BOX (vbox3), frame1, FALSE, FALSE, 0);
 
   label16 = gtk_label_new (_("Régis Duchesne <regis@via.ecp.fr>\nMichel Lespinasse <walken@zoy.org>\nOlivier Pomel <pomel@via.ecp.fr>\nPierre Baillet <oct@zoy.org>\nJean-Philippe Grimaldi <jeanphi@via.ecp.fr>\nAndres Krapf <dae@via.ecp.fr>\nChristophe Massiot <massiot@via.ecp.fr>\nVincent Seguin <seguin@via.ecp.fr>\nBenoit Steiner <benny@via.ecp.fr>\nArnaud de Bossoreille de Ribou <bozo@via.ecp.fr>\nJean-Marc Dressler <polux@via.ecp.fr>\nGaël Hendryckx <jimmy@via.ecp.fr>\nSamuel Hocevar <sam@zoy.org>\nBrieuc Jeunhomme <bbp@via.ecp.fr>\nMichel Kaempf <maxx@via.ecp.fr>\nStéphane Borel <stef@via.ecp.fr>\nRenaud Dartus <reno@via.ecp.fr>\nHenri Fallon <henri@via.ecp.fr>"));
   gtk_widget_ref (label16);
   gtk_object_set_data_full (GTK_OBJECT (intf_about), "label16", label16,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label16);
-  gtk_box_pack_start (GTK_BOX (hbox1), label16, FALSE, FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (frame1), label16);
   gtk_label_set_justify (GTK_LABEL (label16), GTK_JUSTIFY_LEFT);
   gtk_misc_set_alignment (GTK_MISC (label16), 0.5, 0);
-  gtk_misc_set_padding (GTK_MISC (label16), 10, 10);
+  gtk_misc_set_padding (GTK_MISC (label16), 5, 5);
 
   label17 = gtk_label_new (_("This is the VideoLAN client, a DVD and MPEG player. It can play MPEG and MPEG 2 files from a file or from a network source."));
   gtk_widget_ref (label17);
   gtk_object_set_data_full (GTK_OBJECT (intf_about), "label17", label17,
                             (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (label17);
-  gtk_box_pack_start (GTK_BOX (vbox3), label17, FALSE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox3), label17, FALSE, FALSE, 0);
   gtk_label_set_justify (GTK_LABEL (label17), GTK_JUSTIFY_LEFT);
   gtk_label_set_line_wrap (GTK_LABEL (label17), TRUE);
   gtk_misc_set_padding (GTK_MISC (label17), 0, 5);
index 476b38d..8f4205f 100644 (file)
        <class>GtkLabel</class>
        <name>label18</name>
        <label>(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team</label>
-       <justify>GTK_JUSTIFY_CENTER</justify>
+       <justify>GTK_JUSTIFY_LEFT</justify>
        <wrap>False</wrap>
        <xalign>0.5</xalign>
        <yalign>0.5</yalign>
        <xpad>0</xpad>
-       <ypad>0</ypad>
+       <ypad>5</ypad>
        <child>
          <padding>0</padding>
          <expand>False</expand>
       </widget>
 
       <widget>
-       <class>GtkHBox</class>
-       <name>hbox1</name>
-       <homogeneous>False</homogeneous>
-       <spacing>0</spacing>
+       <class>GtkFrame</class>
+       <name>frame1</name>
+       <label>Authors</label>
+       <label_xalign>0</label_xalign>
+       <shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
        <child>
          <padding>0</padding>
          <expand>False</expand>
          <fill>False</fill>
        </child>
 
-       <widget>
-         <class>GtkLabel</class>
-         <name>label15</name>
-         <label>Authors:</label>
-         <justify>GTK_JUSTIFY_RIGHT</justify>
-         <wrap>False</wrap>
-         <xalign>0.5</xalign>
-         <yalign>1.67638e-08</yalign>
-         <xpad>0</xpad>
-         <ypad>10</ypad>
-         <child>
-           <padding>0</padding>
-           <expand>False</expand>
-           <fill>False</fill>
-         </child>
-       </widget>
-
        <widget>
          <class>GtkLabel</class>
          <name>label16</name>
@@ -722,13 +706,8 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label>
          <wrap>False</wrap>
          <xalign>0.5</xalign>
          <yalign>0</yalign>
-         <xpad>10</xpad>
-         <ypad>10</ypad>
-         <child>
-           <padding>0</padding>
-           <expand>False</expand>
-           <fill>False</fill>
-         </child>
+         <xpad>5</xpad>
+         <ypad>5</ypad>
        </widget>
       </widget>
 
@@ -745,7 +724,7 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label>
        <child>
          <padding>0</padding>
          <expand>False</expand>
-         <fill>True</fill>
+         <fill>False</fill>
        </child>
       </widget>
     </widget>
index 68c3b63..c2eaec6 100644 (file)
@@ -348,6 +348,43 @@ void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
 }
 #endif
 
+/*****************************************************************************
+ * intf_WarnHexDump : print a hexadecimal dump of a memory area
+ *****************************************************************************
+ * This is convenient for debugging purposes.
+ *****************************************************************************/
+void intf_WarnHexDump( int i_level, void *p_data, int i_size )
+{
+    int   i_index = 0;
+    int   i_subindex;
+    char  p_string[75];
+    u8   *p_area = (u8 *)p_data;
+
+    intf_WarnMsg( i_level, "hexdump: dumping %i bytes at address %p",
+                           i_size, p_data );
+
+    while( i_index < i_size )
+    {
+        i_subindex = 0;
+
+        while( ( i_subindex < 24 ) && ( i_index + i_subindex < i_size ) )
+        {
+            sprintf( p_string + 3 * i_subindex, "%.2x ",
+                     p_area[ i_index + i_subindex ] );
+
+            i_subindex++;
+        }
+
+        /* -1 here is safe because we know we printed at least one */
+        p_string[ 3 * i_subindex - 1 ] = '\0';
+        intf_WarnMsg( i_level, "0x%.4x: %s", i_index, p_string );
+
+        i_index += 24;
+    }
+
+    intf_WarnMsg( i_level, "hexdump: %i bytes dumped", i_size );
+}
+
 /*****************************************************************************
  * intf_FlushMsg                                                        (ok ?)
  *****************************************************************************
index b7e7109..e1a43fa 100644 (file)
@@ -3,7 +3,7 @@
  *****************************************************************************
  * Copyright (C) 2000 VideoLAN
  *
- * Authors:
+ * Authors: Samuel Hocevar <sam@zoy.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,7 +34,6 @@
 #include "mtime.h"
 
 #include "intf_msg.h"
-#include "debug.h"                                                 /* ASSERT */
 
 #include "stream_control.h"
 #include "input_ext-dec.h"
 
 #include "spu_decoder.h"
 
-/*
+/*****************************************************************************
  * Local prototypes
- */
-static int      InitThread          ( spudec_thread_t *p_spudec );
-static void     RunThread           ( spudec_thread_t *p_spudec );
-static void     ErrorThread         ( spudec_thread_t *p_spudec );
-static void     EndThread           ( spudec_thread_t *p_spudec );
+ *****************************************************************************/
+static int  InitThread  ( spudec_thread_t * );
+static void RunThread   ( spudec_thread_t * );
+static void ErrorThread ( spudec_thread_t * );
+static void EndThread   ( spudec_thread_t * );
+
+static int  SyncPacket           ( spudec_thread_t * );
+static void ParsePacket          ( spudec_thread_t * );
+static int  ParseRLE             ( spudec_thread_t *, subpicture_t * );
+static int  ParseControlSequences( spudec_thread_t *, subpicture_t * );
 
 /*****************************************************************************
  * spudec_CreateThread: create a spu decoder thread
@@ -59,8 +63,6 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
 {
     spudec_thread_t *     p_spudec;
 
-    intf_DbgMsg("spudec debug: creating spu decoder thread");
-
     /* Allocate the memory needed to store the thread's structure */
     p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
 
@@ -84,12 +86,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
     if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
          (vlc_thread_func_t)RunThread, (void *)p_spudec) )
     {
-        intf_ErrMsg("spudec error: can't spawn spu decoder thread");
+        intf_ErrMsg( "spudec error: can't spawn spu decoder thread" );
         free( p_spudec );
         return( 0 );
     }
 
-    intf_DbgMsg("spudec debug: spu decoder thread (%p) created", p_spudec);
     return( p_spudec->thread_id );
 }
 
@@ -104,14 +105,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
  *****************************************************************************/
 static int InitThread( spudec_thread_t *p_spudec )
 {
-    intf_DbgMsg("spudec debug: initializing spu decoder thread %p", p_spudec);
-
     p_spudec->p_config->decoder_config.pf_init_bit_stream(
             &p_spudec->bit_stream,
             p_spudec->p_config->decoder_config.p_decoder_fifo );
 
     /* Mark thread as running and return */
-    intf_DbgMsg( "spudec debug: InitThread(%p) succeeded", p_spudec );
     return( 0 );
 }
 
@@ -123,8 +121,7 @@ static int InitThread( spudec_thread_t *p_spudec )
  *****************************************************************************/
 static void RunThread( spudec_thread_t *p_spudec )
 {
-    intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)",
-        p_spudec, getpid());
+    intf_WarnMsg( 1, "spudec: spu decoder thread %i spawned", getpid() );
 
     /*
      * Initialize thread and free configuration
@@ -137,165 +134,9 @@ static void RunThread( spudec_thread_t *p_spudec )
      */
     while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
     {
-        int i_packet_size;
-        int i_rle_size;
-        int i_index, i_next;
-        boolean_t b_valid;
-        subpicture_t * p_spu = NULL;
-
-        /* wait for the next SPU ID.
-         * XXX: We trash 0xff bytes since they probably come from
-         * an incomplete previous packet */
-        do
-        {
-            i_packet_size = GetBits( &p_spudec->bit_stream, 8 );
-        }
-        while( i_packet_size == 0xff );
-
-        if( p_spudec->p_fifo->b_die )
-        {
-            break;
-        }
-
-        /* the total size - should equal the sum of the
-         * PES packet size that form the SPU packet */
-        i_packet_size = i_packet_size << 8
-                         | GetBits( &p_spudec->bit_stream, 8 );
-
-        /* the RLE stuff size */
-        i_rle_size = GetBits( &p_spudec->bit_stream, 16 );
-
-        /* if the values we got aren't too strange, decode the data */
-        if( i_rle_size < i_packet_size )
-        {
-            /* allocate the subpicture.
-             * FIXME: we should check if the allocation failed */
-            p_spu = vout_CreateSubPicture( p_spudec->p_vout,
-                                           DVD_SUBPICTURE, i_rle_size );
-            /* get display time */
-            p_spu->begin_date = p_spu->end_date
-                            = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
-
-            /* get RLE data, skip 4 bytes for the first two read offsets */
-            GetChunk( &p_spudec->bit_stream, p_spu->p_data,
-                      i_rle_size - 4 );
-
-            if( p_spudec->p_fifo->b_die )
-            {
-                break;
-            }
-
-            /* continue parsing after the RLE part */
-            i_index = i_rle_size;
-
-            /* assume packet is valid */
-            b_valid = 1;
-
-            /* getting the control part */
-            do
-            {
-                unsigned char   i_cmd;
-                u16             i_date;
-
-                /* Get the sequence date */
-                i_date = GetBits( &p_spudec->bit_stream, 16 );
-
-                /* Next offset */
-                i_next = GetBits( &p_spudec->bit_stream, 16 );
-
-                i_index += 4;
-
-                do
-                {
-                    i_cmd = GetBits( &p_spudec->bit_stream, 8 );
-                    i_index++;
-
-                    switch( i_cmd )
-                    {
-                        case SPU_CMD_FORCE_DISPLAY:
-                            /* 00 (force displaying) */
-                            break;
-                        /* FIXME: here we have to calculate dates. It's
-                         * around i_date * 12000 but I don't know
-                         * how much exactly.
-                         */
-                        case SPU_CMD_START_DISPLAY:
-                            /* 01 (start displaying) */
-                            p_spu->begin_date += ( i_date * 12000 );
-                            break;
-                        case SPU_CMD_STOP_DISPLAY:
-                            /* 02 (stop displaying) */
-                            p_spu->end_date += ( i_date * 12000 );
-                            break;
-                        case SPU_CMD_SET_PALETTE:
-                            /* 03xxxx (palette) - trashed */
-                            RemoveBits( &p_spudec->bit_stream, 16 );
-                            i_index += 2;
-                            break;
-                        case SPU_CMD_SET_ALPHACHANNEL:
-                            /* 04xxxx (alpha channel) - trashed */
-                            RemoveBits( &p_spudec->bit_stream, 16 );
-                            i_index += 2;
-                            break;
-                        case SPU_CMD_SET_COORDINATES:
-                            /* 05xxxyyyxxxyyy (coordinates) */
-                            p_spu->i_x =
-                                GetBits( &p_spudec->bit_stream, 12 );
-
-                            p_spu->i_width = p_spu->i_x -
-                                GetBits( &p_spudec->bit_stream, 12 ) + 1;
-
-                            p_spu->i_y =
-                                GetBits( &p_spudec->bit_stream, 12 );
-
-                            p_spu->i_height = p_spu->i_y -
-                                GetBits( &p_spudec->bit_stream, 12 ) + 1;
-
-                            i_index += 6;
-                            break;
-                        case SPU_CMD_SET_OFFSETS:
-                            /* 06xxxxyyyy (byte offsets) */
-                            p_spu->type.spu.i_offset[0] =
-                                GetBits( &p_spudec->bit_stream, 16 ) - 4;
-                            p_spu->type.spu.i_offset[1] =
-                                GetBits( &p_spudec->bit_stream, 16 ) - 4;
-                            i_index += 4;
-                            break;
-                        case SPU_CMD_END:
-                            /* ff (end) */
-                            break;
-                        default:
-                            /* ?? (unknown command) */
-                            intf_ErrMsg( "spudec: unknown command 0x%.2x",
-                                         i_cmd );
-                            b_valid = 0;
-                            break;
-                    }
-                }
-                while( b_valid && ( i_cmd != SPU_CMD_END ) );
-            }
-            while( b_valid && ( i_index == i_next ) );
-
-            if( b_valid )
-            {
-                /* SPU is finished - we can tell the video output
-                 * to display it */
-                vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
-            }
-            else
-            {
-                vout_DestroySubPicture( p_spudec->p_vout, p_spu );
-            }
-        }
-        else 
+        if( !SyncPacket( p_spudec ) )
         {
-            /* Unexpected PES packet - trash it */
-            intf_ErrMsg( "spudec: trying to recover from bad packet" );
-            vlc_mutex_lock( &p_spudec->p_fifo->data_lock );
-            p_spudec->p_fifo->pf_delete_pes( p_spudec->p_fifo->p_packets_mgt,
-                                  DECODER_FIFO_START(*p_spudec->p_fifo) );
-            DECODER_FIFO_INCSTART( *p_spudec->p_fifo );
-            vlc_mutex_unlock( &p_spudec->p_fifo->data_lock );
+            ParsePacket( p_spudec );
         }
     }
 
@@ -308,6 +149,7 @@ static void RunThread( spudec_thread_t *p_spudec )
     }
 
     /* End of thread */
+    intf_WarnMsg( 1, "spudec: destroying spu decoder thread %i", getpid() );
     EndThread( p_spudec );
 }
 
@@ -336,7 +178,8 @@ static void ErrorThread( spudec_thread_t *p_spudec )
         }
 
         /* Waiting for the input thread to put new PES packets in the fifo */
-        vlc_cond_wait( &p_spudec->p_fifo->data_wait, &p_spudec->p_fifo->data_lock );
+        vlc_cond_wait( &p_spudec->p_fifo->data_wait,
+                       &p_spudec->p_fifo->data_lock );
     }
 
     /* We can release the lock before leaving */
@@ -351,9 +194,272 @@ static void ErrorThread( spudec_thread_t *p_spudec )
  *****************************************************************************/
 static void EndThread( spudec_thread_t *p_spudec )
 {
-    intf_DbgMsg( "spudec debug: destroying spu decoder thread %p", p_spudec );
     free( p_spudec->p_config );
     free( p_spudec );
-    intf_DbgMsg( "spudec debug: spu decoder thread %p destroyed", p_spudec);
+}
+
+/*****************************************************************************
+ * SyncPacket: get in sync with the stream
+ *****************************************************************************
+ * This function makes a few sanity checks and returns 0 if it looks like we
+ * are at the beginning of a subpicture packet.
+ *****************************************************************************/
+static int SyncPacket( spudec_thread_t *p_spudec )
+{
+    /* Re-align the buffer on an 8-bit boundary */
+    RealignBits( &p_spudec->bit_stream );
+
+    /* The total SPU packet size, often bigger than a PS packet */
+    p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
+
+    /* The RLE stuff size */
+    p_spudec->i_rle_size = GetBits( &p_spudec->bit_stream, 16 );
+
+    /* If the values we got are a bit strange, skip packet */
+    if( p_spudec->i_rle_size >= p_spudec->i_spu_size )
+    {
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * ParsePacket: parse an SPU packet and send it to the video output
+ *****************************************************************************
+ * This function parses the SPU packet and, if valid, sends it to the
+ * video output.
+ *****************************************************************************/
+static void ParsePacket( spudec_thread_t *p_spudec )
+{
+    subpicture_t * p_spu;
+
+    /* Allocate the subpicture internal data. */
+    p_spu = vout_CreateSubPicture( p_spudec->p_vout, DVD_SUBPICTURE,
+                                   p_spudec->i_rle_size );
+
+    if( p_spu == NULL )
+    {
+        return;
+    }
+
+    /* Get display time */
+    p_spu->begin_date = p_spu->end_date
+                    = DECODER_FIFO_START(*p_spudec->p_fifo)->i_pts;
+
+    if( ParseRLE( p_spudec, p_spu ) )
+    {
+        /* There was a parse error, delete the subpicture */
+        vout_DestroySubPicture( p_spudec->p_vout, p_spu );
+        return;
+    }
+
+    /* Dump the subtitle info */
+    intf_WarnHexDump( 0, p_spu->p_data, p_spudec->i_rle_size - 4 );
+
+    /* Getting the control part */
+    if( ParseControlSequences( p_spudec, p_spu ) )
+    {
+        /* There was a parse error, delete the subpicture */
+        vout_DestroySubPicture( p_spudec->p_vout, p_spu );
+        return;
+    }
+
+    intf_WarnMsg( 1, "spudec: got a valid %ix%i subtitle at (%i,%i), "
+                     "RLE offsets: 0x%x 0x%x",
+                  p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y,
+                  p_spu->type.spu.i_offset[0], p_spu->type.spu.i_offset[1] );
+
+    /* SPU is finished - we can tell the video output to display it */
+    vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
+}
+
+/*****************************************************************************
+ * ParseRLE: parse the RLE part of the subtitle
+ *****************************************************************************
+ * This part parses the subtitle graphical data and stores it in a more
+ * convenient structure for later decoding. For more information on the
+ * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
+ * TODO: pre-parse the RLE stuff here.
+ *****************************************************************************/
+static int ParseRLE( spudec_thread_t *p_spudec, subpicture_t * p_spu )
+{
+    /* Get RLE data, skip 4 bytes for the first two read offsets */
+    GetChunk( &p_spudec->bit_stream, p_spu->p_data, p_spudec->i_rle_size - 4 );
+
+    if( p_spudec->p_fifo->b_die )
+    {
+        return( 1 );
+    }
+
+    return( 0 );
+}
+
+ /*****************************************************************************
+ * ParseControlSequences: parse all SPU control sequences
+ *****************************************************************************
+ * This is the most important part in SPU decoding. We get dates, palette
+ * information, coordinates, and so on. For more information on the
+ * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
+ *****************************************************************************/
+static int ParseControlSequences( spudec_thread_t *p_spudec,
+                                  subpicture_t * p_spu )
+{
+    int i_index = p_spudec->i_rle_size;
+    int i_next_index = 0, i_prev_index;
+
+    int i_date;
+    u8  i_command;
+
+    do
+    {
+        /* Get the control sequence date */
+        i_date = GetBits( &p_spudec->bit_stream, 16 );
+        /* Next offset */
+        i_prev_index = i_next_index;
+        i_next_index = GetBits( &p_spudec->bit_stream, 16 );
+        /* Current offset */
+        i_index += 4;
+        do
+        {
+            i_command = GetBits( &p_spudec->bit_stream, 8 );
+            i_index++;
+            switch( i_command )
+            {
+                case SPU_CMD_FORCE_DISPLAY:
+                    /* 00 (force displaying) */
+                    break;
+                /* FIXME: here we have to calculate dates. It's around
+                 * i_date * 12000 but I don't know how much exactly. */
+                case SPU_CMD_START_DISPLAY:
+                    /* 01 (start displaying) */
+                    p_spu->begin_date += ( i_date * 12000 );
+                    break;
+                case SPU_CMD_STOP_DISPLAY:
+                    /* 02 (stop displaying) */
+                    p_spu->end_date += ( i_date * 12000 );
+                    break;
+                case SPU_CMD_SET_PALETTE:
+                    /* 03xxxx (palette) - trashed */
+                    RemoveBits( &p_spudec->bit_stream, 16 );
+                    i_index += 2;
+                    break;
+                case SPU_CMD_SET_ALPHACHANNEL:
+                    /* 04xxxx (alpha channel) - trashed */
+                    RemoveBits( &p_spudec->bit_stream, 16 );
+                    i_index += 2;
+                    break;
+                case SPU_CMD_SET_COORDINATES:
+                    /* 05xxxyyyxxxyyy (coordinates) */
+                    p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 );
+                    p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 )
+                                      - p_spu->i_x + 1;
+                    p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 );
+                    p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 )
+                                       - p_spu->i_y + 1;
+                    i_index += 6;
+                    break;
+                case SPU_CMD_SET_OFFSETS:
+                    /* 06xxxxyyyy (byte offsets) */
+                    p_spu->type.spu.i_offset[0] =
+                        GetBits( &p_spudec->bit_stream, 16 ) - 4;
+                    p_spu->type.spu.i_offset[1] =
+                        GetBits( &p_spudec->bit_stream, 16 ) - 4;
+                    i_index += 4;
+                    break;
+                case SPU_CMD_END:
+                    /* ff (end) */
+                    break;
+                default:
+                    /* ?? (unknown command) */
+                    intf_ErrMsg( "spudec error: unknown command 0x%.2x",
+                                 i_command );
+                    return( 1 );
+            }
+
+        } while( i_command != SPU_CMD_END );
+
+    } while( i_index == i_next_index );
+
+    /* Check that the last index matches the previous one */
+    if( i_next_index != i_prev_index )
+    {
+        intf_ErrMsg( "spudec error: index mismatch (0x%.4x != 0x%.4x)",
+                     i_next_index, i_prev_index );
+        return( 1 );
+    }
+
+    if( i_index > p_spudec->i_spu_size )
+    {
+        intf_ErrMsg( "spudec error: uh-oh, we went too far (0x%.4x > 0x%.4x)",
+                     i_index, p_spudec->i_spu_size );
+        return( 1 );
+    }
+
+    /* Get rid of padding bytes */
+    switch( p_spudec->i_spu_size - i_index )
+    {
+        case 1:
+
+            RemoveBits( &p_spudec->bit_stream, 8 );
+            i_index++;
+
+        case 0:
+
+            /* Zero or one padding byte, quite usual */
+
+            break;
+
+        default:
+
+            /* More than one padding byte - this is very strange, but
+             * we can deal with it */
+            intf_WarnMsg( 2, "spudec warning: %i padding bytes",
+                          p_spudec->i_spu_size - i_index );
+
+            while( i_index < p_spudec->i_spu_size )
+            {
+                RemoveBits( &p_spudec->bit_stream, 8 );
+                i_index++;
+            }
+
+            break;
+    }
+
+    /* Successfully parsed ! */
+    return( 0 );
 }
 
index 6f56fd2..12c1753 100644 (file)
@@ -3,7 +3,7 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Samuel Hocevar <sam@zoy.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -43,6 +43,13 @@ typedef struct spudec_thread_s
      */
     vout_thread_t *     p_vout;          /* needed to create the spu objects */
 
+    /*
+     * Private properties
+     */
+    int                 i_spu_size;            /* size of current SPU packet */
+    int                 i_rle_size;                  /* size of the RLE part */
+    subpicture_t *      p_spu;
+
 } spudec_thread_t;
 
 /*****************************************************************************
index e358705..7589e4c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************
  * Copyright (C) 2000 VideoLAN
  *
- * Authors:
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index bc9aa9c..e00b392 100644 (file)
@@ -1,11 +1,10 @@
 /*****************************************************************************
- * video_spu.h : DVD subpicture units functions
+ * video_spu.c : DVD subpicture units functions
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
- * Samuel "Sam" Hocevar <sam@via.ecp.fr>
- * Henri Fallon <henri@via.ecp.fr>
+ * Authors: Samuel Hocevar <sam@zoy.org>
+ *          Henri Fallon <henri@via.ecp.fr>
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "intf_msg.h"
 
-typedef struct vout_spu_s
-{
-    int i_id;
-    byte_t *p_data;
-
-    /* drawing coordinates inside the spu */
-    int i_x;
-    int i_y;
-    /* target size */
-    int i_width;
-    int i_height;
-
-} vout_spu_t;
+/* FIXME: fake palette - the real one has to be sought in the .IFO */
+static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 };
 
-static int NewLine  ( vout_spu_t *p_vspu, int *i_id );
-
-/* i = get_nibble(); */
-#define GET_NIBBLE( i ) \
-    if( b_aligned ) \
-    { \
-        i_next = *p_from[i_id]; \
-        p_from[ i_id ]++; \
-        b_aligned = 0; \
-        i = i_next >> 4; \
-    } \
-    else \
-    { \
-        b_aligned = 1; \
-        i = i_next & 0xf; \
+static __inline__ u8 GetNibble( u8 *p_source, int *pi_index )
+{
+    if( *pi_index & 0x1 )
+    {
+        return( p_source[(*pi_index)++ >> 1] & 0xf );
     }
-
-/* i = j + get_nibble(); */
-#define ADD_NIBBLE( i, j ) \
-    if( b_aligned ) \
-    { \
-        i_next = *p_from[i_id]; \
-        p_from[ i_id ]++; \
-        b_aligned = 0; \
-        i = (j) + (i_next >> 4); \
-    } \
-    else \
-    { \
-        b_aligned = 1; \
-        i = (j) + (i_next & 0xf); \
+    else
+    {
+        return( p_source[(*pi_index)++ >> 1] >> 4 );
     }
+}
 
 /*****************************************************************************
- * vout_RenderSPU: draws an SPU on a picture
+ * vout_RenderSPU: draw an SPU on a picture
  *****************************************************************************
  * 
  *****************************************************************************/
-void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_subpic,
+void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
                      int i_bytes_per_pixel, int i_bytes_per_line )
 {
     int i_code = 0x00;
-    int i_next = 0;
     int i_id = 0;
     int i_color;
 
+    /* SPU size */
+    int i_width = p_spu->i_width;
+    int i_height = p_spu->i_height;
+
+    /* Drawing coordinates inside the SPU */
+    int i_x = 0, i_y = 0;
+
     /* FIXME: we need a way to get this information from the stream */
     #define TARGET_WIDTH     720
     #define TARGET_HEIGHT    576
-    int i_x_scale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH;
-    int i_y_scale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT;
+    int i_xscale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH;
+    int i_yscale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT;
 
-    /* FIXME: fake palette - the real one has to be sought in the .IFO */
-    static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 };
+    u8 *p_source = p_spu->p_data;
+    u8 *p_dest;
+    int pi_index[2];
 
-    boolean_t b_aligned = 1;
-    byte_t *p_from[2];
-    vout_spu_t vspu;
+    pi_index[0] = ( p_spu->type.spu.i_offset[0] - 2 ) << 1;
+    pi_index[1] = ( p_spu->type.spu.i_offset[1] - 2 ) << 1;
 
-    p_from[1] = p_subpic->p_data + p_subpic->type.spu.i_offset[1];
-    p_from[0] = p_subpic->p_data + p_subpic->type.spu.i_offset[0];
+    p_dest = p_buffer->p_data
+                /* add the picture coordinates and the SPU coordinates */
+                + ( p_buffer->i_pic_x + ((p_spu->i_x * i_xscale) >> 6))
+                     * i_bytes_per_pixel
+                + ( p_buffer->i_pic_y + ((p_spu->i_y * i_yscale) >> 6))
+                     * i_bytes_per_line;
 
-    vspu.i_x = 0;
-    vspu.i_y = 0;
-    vspu.i_width = TARGET_WIDTH;
-    vspu.i_height = TARGET_HEIGHT;
-    vspu.p_data = p_buffer->p_data
-                    /* add the picture coordinates and the SPU coordinates */
-                    + ( p_buffer->i_pic_x + ((p_subpic->i_x * i_x_scale) >> 6))
-                        * i_bytes_per_pixel
-                    + ( p_buffer->i_pic_y + ((p_subpic->i_y * i_y_scale) >> 6))
-                        * i_bytes_per_line;
-
-    /* Do we need scaling ? 
-     * This is mostly dupliucate code except a few lines.
-     * This test was put out of the loop to avoid testing it
-     * each time.
-     */
-    if ( i_y_scale >= (1 << 6) )
+    while( pi_index[0] >> 1 < p_spu->type.spu.i_offset[1] )
     {
-        while( p_from[0] < (byte_t *)p_subpic->p_data
-                             + p_subpic->type.spu.i_offset[1] )
+        i_code = GetNibble( p_source, pi_index + i_id );
+
+        if( i_code >= 0x04 )
         {
-            GET_NIBBLE( i_code );
-    
-            if( i_code >= 0x04 )
-            {
-                found_code_with_scale:
-    
-                if( ((i_code >> 2) + vspu.i_x + vspu.i_y * vspu.i_width)
-                        > vspu.i_height * vspu.i_width )
-                {
-                    intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
-                                  i_code >> 2, vspu.i_height * vspu.i_width
-                                   - ( (i_code >> 2) + vspu.i_x
-                                       + vspu.i_y * vspu.i_width ) );
-                    return;
-                }
-                else
-                {
-                    if( (i_color = i_code & 0x3) )
-                    {
-                        u8 *p_target = &vspu.p_data[
-                            i_bytes_per_pixel * ((vspu.i_x * i_x_scale) >> 6)
-                            + i_bytes_per_line * ((vspu.i_y * i_y_scale) >> 6) ];
-    
-                        memset( p_target, p_palette[i_color],
-                                ((((i_code - 1) * i_x_scale) >> 8) + 1)
-                                * i_bytes_per_pixel );
-    
-                        /* here we need some horizontal scaling (unlikely )
-                         * we only scale up to 2x, someone watching a DVD
-                         * with more than 2x zoom must be braindead */
-                            p_target += i_bytes_per_line;
-    
-                            memset( p_target, p_palette[i_color],
-                                    ((((i_code - 1) * i_x_scale) >> 8) + 1)
-                                    * i_bytes_per_pixel );
-                    }
-                    vspu.i_x += i_code >> 2;
-                }
-    
-                if( vspu.i_x >= vspu.i_width )
-                {
-                    /* byte-align the stream */
-                    b_aligned = 1;
-                    /* finish the line */
-                    NewLine( &vspu, &i_id );
-                }
-                continue;
-            }
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x10 )   /* 00 11 xx cc */
-                goto found_code_with_scale;   /* 00 01 xx cc */
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x040 )  /* 00 00 11 xx xx cc */
-                goto found_code_with_scale;   /* 00 00 01 xx xx cc */
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
-                goto found_code_with_scale;   /* 00 00 00 01 xx xx xx cc */
-    
-            /* if the 14 first bits are 0, then it's a newline */
-            if( i_code <= 0x0003 )
+            found_code:
+
+            if( ((i_code >> 2) + i_x + i_y * i_width) > i_height * i_width )
             {
-                if( NewLine( &vspu, &i_id ) < 0 )
-                    return;
-    
-                if( !b_aligned )
-                    b_aligned = 1;
+                intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
+                              i_code >> 2, i_height * i_width
+                               - ( (i_code >> 2) + i_x + i_y * i_width ) );
+                return;
             }
             else
             {
-                /* we have a boo boo ! */
-                intf_DbgMsg( "video_spu: unknown code 0x%x "
-                             "(dest %x side %x, x=%d, y=%d)",
-                             i_code, p_from[i_id], i_id, vspu.i_x, vspu.i_y );
-                if( NewLine( &vspu, &i_id ) < 0 )
-                    return;
-                continue;
-            }
-        }
-    }
-    else
-    {
-        while( p_from[0] < (byte_t *)p_subpic->p_data
-                             + p_subpic->type.spu.i_offset[1] )
-        {
-            GET_NIBBLE( i_code );
-    
-            if( i_code >= 0x04 )
-            {
-                found_code:
-    
-                if( ((i_code >> 2) + vspu.i_x + vspu.i_y * vspu.i_width)
-                        > vspu.i_height * vspu.i_width )
+                if( (i_color = i_code & 0x3) )
                 {
-                    intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
-                                  i_code >> 2, vspu.i_height * vspu.i_width
-                                   - ( (i_code >> 2) + vspu.i_x
-                                       + vspu.i_y * vspu.i_width ) );
-                    return;
+                    u8 *p_target = p_dest
+                        + i_bytes_per_pixel * ((i_x * i_xscale) >> 6)
+                        + i_bytes_per_line * ((i_y * i_yscale) >> 6);
+
+                    memset( p_target, p_palette[i_color],
+                            ((((i_code >> 2) * i_xscale) >> 6) + 1)
+                            * i_bytes_per_pixel );
                 }
-                else
+                i_x += i_code >> 2;
+            }
+
+            if( i_x >= i_width )
+            {
+                /* byte-align the stream */
+                if( pi_index[i_id] & 0x1 )
                 {
-                    if( (i_color = i_code & 0x3) )
-                    {
-                        u8 *p_target = &vspu.p_data[
-                            i_bytes_per_pixel * ((vspu.i_x * i_x_scale) >> 6)
-                            + i_bytes_per_line * ((vspu.i_y * i_y_scale) >> 6) ];
-    
-                        memset( p_target, p_palette[i_color],
-                                ((((i_code - 1) * i_x_scale) >> 8) + 1)
-                                * i_bytes_per_pixel );
-                    }
-                    vspu.i_x += i_code >> 2;
+                    pi_index[i_id]++;
                 }
-    
-                if( vspu.i_x >= vspu.i_width )
+
+                i_id = ~i_id & 0x1;
+
+                i_y++;
+                i_x = 0;
+
+                if( i_width <= i_y )
                 {
-                    /* byte-align the stream */
-                    b_aligned = 1;
-                    /* finish the line */
-                    NewLine( &vspu, &i_id );
+                    return;
                 }
-                continue;
             }
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x10 )   /* 00 11 xx cc */
-                goto found_code;   /* 00 01 xx cc */
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x040 )  /* 00 00 11 xx xx cc */
-                goto found_code;   /* 00 00 01 xx xx cc */
-    
-            ADD_NIBBLE( i_code, (i_code << 4) );
-            if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
-                goto found_code;   /* 00 00 00 01 xx xx xx cc */
-    
-            /* if the 14 first bits are 0, then it's a newline */
-            if( i_code <= 0x0003 )
+            continue;
+        }
+
+        i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
+
+        if( i_code >= 0x10 )   /* 00 11 xx cc */
+        {
+            goto found_code;   /* 00 01 xx cc */
+        }
+
+        i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
+        if( i_code >= 0x040 )  /* 00 00 11 xx xx cc */
+        {
+            goto found_code;   /* 00 00 01 xx xx cc */
+        }
+
+        i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
+        if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
+        {
+            goto found_code;   /* 00 00 00 01 xx xx xx cc */
+        }
+
+        if( i_code & ~0x0003 )
+        {
+            /* we have a boo boo ! */
+            intf_ErrMsg( "video_spu: unknown code 0x%x "
+                         "(dest %x side %x, x=%d, y=%d)",
+                         i_code, p_source, i_id, i_x, i_y );
+            return;
+        }
+        else
+        {
+            /* if the 14 first bits are 0, then it's a new line */
+            if( pi_index[i_id] & 0x1 )
             {
-                if( NewLine( &vspu, &i_id ) < 0 )
-                    return;
-    
-                if( !b_aligned )
-                    b_aligned = 1;
+                pi_index[i_id]++;
             }
-            else
+
+            i_id = ~i_id & 0x1;
+
+            i_y++;
+            i_x = 0;
+
+            if( i_width <= i_y )
             {
-                /* we have a boo boo ! */
-                intf_DbgMsg( "video_spu: unknown code 0x%x "
-                             "(dest %x side %x, x=%d, y=%d)",
-                             i_code, p_from[i_id], i_id, vspu.i_x, vspu.i_y );
-                if( NewLine( &vspu, &i_id ) < 0 )
-                    return;
-                continue;
+                return;
             }
         }
     }
 }
 
-static int NewLine( vout_spu_t *p_vspu, int *i_id )
-{
-    *i_id = 1 - *i_id;
-
-    p_vspu->i_x = 0;
-    p_vspu->i_y++;
-
-    return( p_vspu->i_width - p_vspu->i_y );
-
-}
-
index 2af7443..fa80e83 100644 (file)
@@ -3,7 +3,8 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Samuel Hocevar <sam@zoy.org>
+ *          Henri Fallon <henri@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index b1e3d8a..25a7f23 100644 (file)
@@ -3,7 +3,8 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
+ *          Samuel Hocevar <sam@zoy.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index af9189c..6a0ac2f 100644 (file)
@@ -3,7 +3,8 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
+ *          Samuel Hocevar <sam@zoy.org>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 594310c..3b125eb 100644 (file)
@@ -4,7 +4,7 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index 6a49c10..e9d4eb7 100644 (file)
@@ -4,7 +4,7 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors:
+ * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by