Commit 31d966e0 authored by Sam Hocevar's avatar Sam Hocevar

  * The Gtk+ interface is now built as a Debian package as well. The Gnome
    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.
parent 4875485d
...@@ -451,7 +451,7 @@ all: vlc @ALIASES@ plugins ...@@ -451,7 +451,7 @@ all: vlc @ALIASES@ plugins
clean: clean:
rm -f $(C_OBJ) $(CPP_OBJ) $(ASM_OBJ) $(STD_PLUGIN_OBJ) rm -f $(C_OBJ) $(CPP_OBJ) $(ASM_OBJ) $(STD_PLUGIN_OBJ)
rm -f plugins/*/*.o src/*/*.o lib/*.so rm -f plugins/*/*.o src/*/*.o lib/*.so
rm -f vlc @ALIASES@ rm -f vlc kvlc gvlc
distclean: clean distclean: clean
rm -f src/*/*.o plugins/*/*.o **/*~ *.log rm -f src/*/*.o plugins/*/*.o **/*~ *.log
......
...@@ -7,8 +7,8 @@ Standards-Version: 3.0.1 ...@@ -7,8 +7,8 @@ Standards-Version: 3.0.1
Package: vlc Package: vlc
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, vlc-gnome Depends: ${shlibs:Depends}, vlc-gtk
Suggests: vlc-sdl, vlc-esd Suggests: vlc-sdl, vlc-esd, vlc-gnome
Description: the free MPEG and DVD player VideoLAN Client Description: the free MPEG and DVD player VideoLAN Client
VideoLAN is a free MPEG, MPEG2 and DVD software solution. VideoLAN is a free MPEG, MPEG2 and DVD software solution.
. .
...@@ -17,12 +17,20 @@ Description: the free MPEG and DVD player VideoLAN Client ...@@ -17,12 +17,20 @@ Description: the free MPEG and DVD player VideoLAN Client
Package: vlc-gnome Package: vlc-gnome
Architecture: any 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 Description: Gnome plugin for the VideoLAN Client
VideoLAN is a free MPEG, MPEG2 and DVD software solution. VideoLAN is a free MPEG, MPEG2 and DVD software solution.
. .
This plugin adds a Gnome interface to the VideoLAN Client. 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 Package: vlc-esd
Architecture: any Architecture: any
Depends: vlc (= ${Source-Version}), ${shlibs:Depends} Depends: vlc (= ${Source-Version}), ${shlibs:Depends}
......
...@@ -16,13 +16,14 @@ build-stamp: ...@@ -16,13 +16,14 @@ build-stamp:
./configure --prefix=/usr \ ./configure --prefix=/usr \
--mandir=\$${prefix}/share/man \ --mandir=\$${prefix}/share/man \
--infodir=\$${prefix}/share/info \ --infodir=\$${prefix}/share/info \
--enable-gnome --enable-fb --with-glide --with-ggi \ --enable-gnome --enable-gtk --enable-fb --with-glide \
--with-sdl --enable-esd --enable-alsa --disable-ppro ; \ --with-ggi --with-sdl --enable-esd --enable-alsa \
--disable-ppro ; \
else \ else \
./configure --prefix=/usr \ ./configure --prefix=/usr \
--mandir=\$${prefix}/share/man \ --mandir=\$${prefix}/share/man \
--infodir=\$${prefix}/share/info \ --infodir=\$${prefix}/share/info \
--enable-gnome --enable-fb --with-ggi \ --enable-gnome --enable-gtk --enable-fb --with-ggi \
--with-sdl --enable-esd --enable-alsa; \ --with-sdl --enable-esd --enable-alsa; \
fi fi
...@@ -48,7 +49,7 @@ install: build ...@@ -48,7 +49,7 @@ install: build
DESTDIR=`pwd`/debian/vlc/ $(MAKE) install prefix=/usr DESTDIR=`pwd`/debian/vlc/ $(MAKE) install prefix=/usr
# make symlinks for packages # 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/ ; \ mkdir -p debian/vlc-$$alias/usr/share/doc/ ; \
ln -s vlc debian/vlc-$$alias/usr/share/doc/vlc-$$alias ; \ ln -s vlc debian/vlc-$$alias/usr/share/doc/vlc-$$alias ; \
mkdir -p debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \ mkdir -p debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \
...@@ -56,13 +57,13 @@ install: build ...@@ -56,13 +57,13 @@ install: build
debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \ debian/vlc-$$alias/usr/lib/videolan/vlc/ ; \
done done
mkdir -p debian/vlc-gnome/usr/bin/ mkdir -p debian/vlc-gtk/usr/bin/
mv debian/vlc/usr/bin/gvlc debian/vlc-gnome/usr/bin/ mv debian/vlc/usr/bin/gvlc debian/vlc-gtk/usr/bin/
mkdir -p debian/vlc-gnome/usr/share/videolan/ mkdir -p debian/vlc-gtk/usr/share/videolan/
mv debian/vlc/usr/share/videolan/gvlc.png \ mv debian/vlc/usr/share/videolan/gvlc.png \
debian/vlc-gnome/usr/share/videolan/ debian/vlc-gtk/usr/share/videolan/
mkdir -p debian/vlc-gnome/usr/share/man/man1/ mkdir -p debian/vlc-gtk/usr/share/man/man1/
ln -s vlc.1.gz debian/vlc-gnome/usr/share/man/man1/gvlc.1.gz ln -s vlc.1.gz debian/vlc-gtk/usr/share/man/man1/gvlc.1.gz
# Build architecture-independent files here. # Build architecture-independent files here.
binary-indep: build install binary-indep: build install
...@@ -81,10 +82,10 @@ binary-arch: build install ...@@ -81,10 +82,10 @@ binary-arch: build install
# dh_installpam # dh_installpam
# dh_installinit # dh_installinit
dh_installcron 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_installinfo
# dh_undocumented # 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_link
dh_strip dh_strip
dh_compress dh_compress
......
?package(vlc-gnome):command="/usr/bin/gvlc" hotkey="V" needs="X11" \
section="Apps/Viewers" title="Gnome VideoLAN Client" \
icon="/usr/share/videolan/gvlc.png"
?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"
This package was debianized by Samuel Hocevar <sam@zoy.org> on This package was debianized by Samuel Hocevar <sam@zoy.org> on
Mon, 13 Mar 2000 02:21:45 +0100. 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> 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 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 under the terms of the GNU General Public License as published by the
......
...@@ -85,3 +85,5 @@ void intf_IntfMsg ( char *psz_format, ... ); ...@@ -85,3 +85,5 @@ void intf_IntfMsg ( char *psz_format, ... );
void intf_MsgImm ( char *psz_format, ... ); void intf_MsgImm ( char *psz_format, ... );
void intf_ErrMsgImm ( char *psz_format, ... ); void intf_ErrMsgImm ( char *psz_format, ... );
void intf_WarnMsgImm ( int i_level, char *psz_format, ... ); void intf_WarnMsgImm ( int i_level, char *psz_format, ... );
void intf_WarnHexDump ( int i_level, void *p_data, int i_size );
/*****************************************************************************
* 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
*****************************************************************************/
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* intf_beos.cpp: beos interface * intf_beos.cpp: beos interface
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN * 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> * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org> * Samuel Hocevar <sam@zoy.org>
...@@ -61,7 +61,7 @@ extern "C" ...@@ -61,7 +61,7 @@ extern "C"
#include "main.h" #include "main.h"
} }
#include "beos_window.h" #include "window.h"
/***************************************************************************** /*****************************************************************************
* intf_sys_t: description and status of FB interface * intf_sys_t: description and status of FB interface
......
...@@ -54,13 +54,13 @@ extern "C" ...@@ -54,13 +54,13 @@ extern "C"
#include "video.h" #include "video.h"
#include "video_output.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 "intf_msg.h"
#include "main.h" #include "main.h"
} }
#include "beos_window.h" #include "window.h"
#define WIDTH 128 #define WIDTH 128
#define HEIGHT 64 #define HEIGHT 64
......
/***************************************************************************** /*****************************************************************************
* beos_window.h: beos window class prototype * window.h: BeOS window class prototype
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* *
* Authors: * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Jean-Marc Dressler
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* dvd_ioctl.c: DVD ioctl replacement function * dvd_ioctl.c: DVD ioctl replacement function
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * 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> * Authors: Markus Kuespert <ltlBeBoy@beosmail.com>
* Samuel Hocevar <sam@zoy.org> * Samuel Hocevar <sam@zoy.org>
...@@ -48,24 +48,23 @@ ...@@ -48,24 +48,23 @@
#include "dvd_ioctl.h" #include "dvd_ioctl.h"
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes - BeOS specific
*****************************************************************************/ *****************************************************************************/
#if defined( SYS_BEOS ) #if defined( SYS_BEOS )
static int dvd_do_auth ( int i_fd, dvd_authinfo *p_authinfo ); static int ReadData ( int i_fd, dvd_struct *p_dvd );
static int dvd_read_struct ( int i_fd, dvd_struct *p_dvd ); static int ReadCopyright ( int i_fd, dvd_struct *p_dvd );
static int dvd_read_physical ( int i_fd, dvd_struct *p_dvd ); static int ReadKey ( int i_fd, dvd_struct *p_dvd );
static int dvd_read_copyright ( int i_fd, dvd_struct *p_dvd ); static int ReadBCA ( int i_fd, dvd_struct *p_dvd );
static int dvd_read_disckey ( int i_fd, dvd_struct *p_dvd ); static int ReadManufacturer ( 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 void InitGenericCommand( struct cdrom_generic_command *p_cgc,
static int communicate_with_dvd ( int i_fd, void *buf, int i_len, int i_type );
struct cdrom_generic_command *p_cgc ); static void InitReadCommand ( struct cdrom_generic_command *p_cgc,
static void init_cdrom_command ( struct cdrom_generic_command *p_cgc, unsigned i_agid, unsigned i_type );
void *buf, int i_len, int i_type ); static void InitWriteCommand ( struct cdrom_generic_command *p_cgc,
static void setup_report_key ( struct cdrom_generic_command *p_cgc, unsigned i_agid, unsigned i_type );
unsigned i_agid, unsigned i_type );
static void setup_send_key ( struct cdrom_generic_command *p_cgc, static int SendCommand ( int i_fd, struct cdrom_generic_command *p_cgc );
unsigned i_agid, unsigned i_type );
#endif #endif
/***************************************************************************** /*****************************************************************************
...@@ -80,382 +79,262 @@ int dvd_ioctl( int i_fd, unsigned long i_op, void *p_arg ) ...@@ -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 ) ); return( ioctl( i_fd, i_op, p_arg ) );
#elif defined( SYS_BEOS ) #elif defined( SYS_BEOS )
switch ( i_op )
{
case DVD_AUTH:
return dvd_do_auth( i_fd, (dvd_authinfo *)p_arg );
case DVD_READ_STRUCT: int i_ret;
return dvd_read_struct( i_fd, (dvd_struct *)p_arg ); unsigned char buf[20];
default:
intf_ErrMsg( "css error: unknown command 0x%x", i_op );
return -1;
}
#else
return -1; struct cdrom_generic_command p_cgc;
#endif
}
#if defined( SYS_BEOS ) dvd_struct *p_dvd = (dvd_struct *)p_arg;
dvd_authinfo *p_authinfo = (dvd_authinfo *)p_arg;
/***************************************************************************** switch ( i_op )
* 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 )
{ {
case 0: case DVD_AUTH: /* Request type is "authentication" */
case 8: {
case 5: memset( buf, 0, sizeof( buf ) );
p_cgc->buflen = 8; InitGenericCommand( &p_cgc, buf, 0, CGC_DATA_READ );
break;
case 1: switch( p_authinfo->type )
p_cgc->buflen = 16; {
break; case DVD_LU_SEND_AGID: /* LU data send */
case 2: intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_AGID" );
case 4:
p_cgc->buflen = 12;
break;
}
p_cgc->cmd[9] = p_cgc->buflen; InitReadCommand( &p_cgc, p_authinfo->lsa.agid, 0 );
p_cgc->data_direction = CGC_DATA_READ;
}
/***************************************************************************** i_ret = SendCommand( i_fd, &p_cgc );
* 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);
switch( i_type ) p_authinfo->lsa.agid = buf[7] >> 6;
{
case 1:
p_cgc->buflen = 16;
break;
case 3: return i_ret;
p_cgc->buflen = 12;
break;
case 6: case DVD_LU_SEND_KEY1:
p_cgc->buflen = 8;
break;
}
p_cgc->cmd[9] = p_cgc->buflen; intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_KEY1" );
p_cgc->data_direction = CGC_DATA_WRITE;
}
/***************************************************************************** InitReadCommand( &p_cgc, p_authinfo->lsk.agid, 2 );
* 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) );
if (buf) i_ret = SendCommand( i_fd, &p_cgc );
{
memset( buf, 0, i_len );
}
p_cgc->buffer = (char *) buf; /* Copy the key */
p_cgc->buflen = i_len; memcpy( p_authinfo->lsk.key, &buf[4], sizeof(dvd_key) );
p_cgc->data_direction = i_type;
p_cgc->timeout = 255;
}
/* DVD handling */ return i_ret;
/***************************************************************************** case DVD_LU_SEND_CHALLENGE:
* 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;
#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
#if 0 InitReadCommand( &p_cgc, p_authinfo->lsc.agid, 1 );
struct rpc_state_t rpc_state;
#endif
memset( buf, 0, sizeof(buf) ); i_ret = SendCommand( i_fd, &p_cgc );
init_cdrom_command( &p_cgc, buf, 0, CGC_DATA_READ );
switch (p_authinfo->type) /* Copy the challenge */
{ memcpy( p_authinfo->lsc.chal, &buf[4],
/* LU data send */ sizeof(dvd_challenge) );
case DVD_LU_SEND_AGID:
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) */ intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_TITLE_KEY" );
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
p_authinfo->lsa.agid = buf[7] >> 6; InitReadCommand( &p_cgc, p_authinfo->lstk.agid, 4 );
/* Returning data, let host change state */
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) */ return i_ret;
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
copy_key(p_authinfo->lsk.key, &buf[4]); case DVD_LU_SEND_ASF:
/* Returning data, let host change state */
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) */ return i_ret;
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 */
break; case DVD_HOST_SEND_CHALLENGE: /* LU data receive */
/* Post-auth key */ intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_CHALLENGE" );
case DVD_LU_SEND_TITLE_KEY:
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); /* Copy the challenge */
p_cgc.cmd[5] = p_authinfo->lstk.lba; memcpy( &buf[4], p_authinfo->hsc.chal,
p_cgc.cmd[4] = p_authinfo->lstk.lba >> 8; sizeof(dvd_challenge) );
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;
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) */ case DVD_HOST_SEND_KEY2:
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
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) */ /* Copy the key */
case DVD_HOST_SEND_CHALLENGE: 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); p_authinfo->type = DVD_AUTH_ESTABLISHED;
buf[1] = 0xe;
copy_chal(&buf[4], p_authinfo->hsc.chal);
/* handle uniform packets for scsi type devices (scsi,atapi) */ return 0;
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
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); case DVD_LU_SEND_RPC_STATE: /* Get region settings */
buf[1] = 0xa;
copy_key(&buf[4], p_authinfo->hsk.key);
/* handle uniform packets for scsi type devices (scsi,atapi) */ intf_WarnMsg( 2, "css DoAuth: DVD_LU_SEND_RPC_STATE "
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc))) "(unimplemented)" );
{
p_authinfo->type = DVD_AUTH_FAILURE;
return i_ret;
}
p_authinfo->type = DVD_AUTH_ESTABLISHED;
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 */ if( (i_ret = SendCommand(i_fd, &p_cgc)) )
case DVD_INVALIDATE_AGID: {
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) */ case DVD_HOST_SEND_RPC_STATE: /* Set region settings */
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
break; intf_WarnMsg( 2, "css DoAuth: DVD_HOST_SEND_RPC_STATE" );
/* Get region settings */ InitWriteCommand( &p_cgc, 0, 6 );
case DVD_LU_SEND_RPC_STATE: buf[1] = 6;
buf[4] = p_authinfo->hrpcs.pdrc;
intf_WarnMsg( 2, "css dvd_do_auth: DVD_LU_SEND_RPC_STATE " return SendCommand( i_fd, &p_cgc );
"(unimplemented)" );
#if 0 default:
p_dvdetup_report_key(&p_cgc, 0, 8); intf_ErrMsg( "css DoAuth: invalid DVD key ioctl" );
memset(&rpc_state, 0, sizeof(rpc_state_t)); return -1;
p_cgc.buffer = (char *) &rpc_state;
/* 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; case DVD_READ_STRUCT: /* Request type is "read structure" */
p_authinfo->lrpcs.vra = rpc_state.vra; {
p_authinfo->lrpcs.ucca = rpc_state.ucca; switch( p_dvd->type )
p_authinfo->lrpcs.region_mask = rpc_state.region_mask; {
p_authinfo->lrpcs.rpc_scheme = rpc_state.rpc_scheme; case DVD_STRUCT_PHYSICAL:
#endif
break; intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_PHYSICAL" );
/* Set region settings */ return ReadData( i_fd, p_dvd );
case DVD_HOST_SEND_RPC_STATE:
intf_WarnMsg( 2, "css dvd_do_auth: DVD_HOST_SEND_RPC_STATE" ); case DVD_STRUCT_COPYRIGHT:
setup_send_key(&p_cgc, 0, 6); intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_COPYRIGHT" );
buf[1] = 6;
buf[4] = p_authinfo->hrpcs.pdrc;
/* handle uniform packets for scsi type devices (scsi,atapi) */ return ReadCopyright( i_fd, p_dvd );
if ((i_ret = communicate_with_dvd(i_fd, &p_cgc)))
{
return i_ret;
}
break; case DVD_STRUCT_DISCKEY:
default: intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_DISCKEY" );
intf_ErrMsg( "css dvd_do_auth: invalid DVD key ioctl" );
return -1;
} return ReadKey( i_fd, p_dvd );
return 0; case DVD_STRUCT_BCA:
}
/***************************************************************************** intf_WarnMsg( 2, "css ReadStruct: 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);
case DVD_STRUCT_DISCKEY: return ReadBCA( i_fd, p_dvd );
intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_DISCKEY" ); case DVD_STRUCT_MANUFACT:
return dvd_read_disckey(i_fd, p_dvd);
case DVD_STRUCT_BCA: intf_WarnMsg( 2, "css ReadStruct: DVD_STRUCT_MANUFACT" );
intf_WarnMsg( 2, "css dvd_read_struct: DVD_STRUCT_BCA" ); return ReadManufacturer( i_fd, p_dvd );
return dvd_read_bca(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 -1;
return dvd_read_manufact(i_fd, p_dvd); }
}
default: default: /* Unknown request type */
intf_WarnMsg( 2, "css dvd_read_struct: invalid request (%d)", {
p_dvd->type ); intf_ErrMsg( "css error: unknown command 0x%x", i_op );
return -1; 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; int i_ret, i;
u_char buf[4 + 4 * 20], *base; u_char buf[4 + 4 * 20], *base;
struct dvd_layer *layer; struct dvd_layer *layer;
struct cdrom_generic_command cgc; 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[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[6] = p_dvd->physical.layer_num; cgc.cmd[6] = p_dvd->physical.layer_num;
cgc.cmd[7] = p_dvd->type; cgc.cmd[7] = p_dvd->type;
cgc.cmd[9] = cgc.buflen & 0xff; cgc.cmd[9] = cgc.buflen & 0xff;
/* handle uniform packets for scsi type devices (scsi,atapi) */ if( (i_ret = SendCommand(i_fd, &cgc)) )
if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
{ {
return i_ret; return i_ret;
} }
...@@ -488,15 +367,15 @@ static int dvd_read_physical( int i_fd, dvd_struct *p_dvd ) ...@@ -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; int i_ret;
u_char buf[8]; u_char buf[8];
struct cdrom_generic_command cgc; 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[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[6] = p_dvd->copyright.layer_num; cgc.cmd[6] = p_dvd->copyright.layer_num;
...@@ -504,8 +383,7 @@ static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd ) ...@@ -504,8 +383,7 @@ static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd )
cgc.cmd[8] = cgc.buflen >> 8; cgc.cmd[8] = cgc.buflen >> 8;
cgc.cmd[9] = cgc.buflen & 0xff; cgc.cmd[9] = cgc.buflen & 0xff;
/* handle uniform packets for scsi type devices (scsi,atapi) */ if( (i_ret = SendCommand(i_fd, &cgc)) )
if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
{ {
return i_ret; return i_ret;
} }
...@@ -517,9 +395,9 @@ static int dvd_read_copyright( int i_fd, dvd_struct *p_dvd ) ...@@ -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; int i_ret, size;
u_char *buf; u_char *buf;
...@@ -533,17 +411,17 @@ static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd ) ...@@ -533,17 +411,17 @@ static int dvd_read_disckey( int i_fd, dvd_struct *p_dvd )
return -ENOMEM; return -ENOMEM;
} }
#endif #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[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = p_dvd->type; cgc.cmd[7] = p_dvd->type;
cgc.cmd[8] = size >> 8; cgc.cmd[8] = size >> 8;
cgc.cmd[9] = size & 0xff; cgc.cmd[9] = size & 0xff;
cgc.cmd[10] = p_dvd->disckey.agid << 6; cgc.cmd[10] = p_dvd->disckey.agid << 6;
/* handle uniform packets for scsi type devices (scsi,atapi) */ if( !(i_ret = SendCommand(i_fd, &cgc)) )
if( !(i_ret = communicate_with_dvd(i_fd, &cgc)) )
{ {
memcpy( p_dvd->disckey.value, &buf[4], sizeof(p_dvd->disckey.value) ); 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 ) ...@@ -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; int i_ret;
u_char buf[4 + 188]; u_char buf[4 + 188];
struct cdrom_generic_command cgc; 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[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = p_dvd->type; cgc.cmd[7] = p_dvd->type;
cgc.cmd[9] = cgc.buflen = 0xff; cgc.cmd[9] = cgc.buflen = 0xff;
/* handle uniform packets for scsi type devices (scsi,atapi) */ if( (i_ret = SendCommand(i_fd, &cgc)) )
if( (i_ret = communicate_with_dvd(i_fd, &cgc)) )
{ {
return i_ret; return i_ret;
} }
...@@ -575,7 +456,7 @@ static int dvd_read_bca( int i_fd, dvd_struct *p_dvd ) ...@@ -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]; p_dvd->bca.len = buf[0] << 8 | buf[1];
if( p_dvd->bca.len < 12 || p_dvd->bca.len > 188 ) 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; return -1;
} }
...@@ -585,15 +466,15 @@ static int dvd_read_bca( int i_fd, dvd_struct *p_dvd ) ...@@ -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; int i_ret = 0, size;
u_char *buf; u_char *buf;
struct cdrom_generic_command cgc; struct cdrom_generic_command cgc;
size = sizeof(p_dvd->manufact.value) + 4; size = sizeof( p_dvd->manufact.value ) + 4;
#if 0 #if 0
if( (buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL ) 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 ) ...@@ -603,14 +484,14 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd )
#endif #endif
buf = (u_char *) malloc(size); 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[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = p_dvd->type; cgc.cmd[7] = p_dvd->type;
cgc.cmd[8] = size >> 8; cgc.cmd[8] = size >> 8;
cgc.cmd[9] = size & 0xff; cgc.cmd[9] = size & 0xff;
/* handle uniform packets for scsi type devices (scsi,atapi) */ if( (i_ret = SendCommand(i_fd, &cgc)) )
if ((i_ret = communicate_with_dvd(i_fd, &cgc)))
{ {
return i_ret; return i_ret;
} }
...@@ -618,8 +499,8 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd ) ...@@ -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]; p_dvd->manufact.len = buf[0] << 8 | buf[1];
if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 ) if( p_dvd->manufact.len < 0 || p_dvd->manufact.len > 2048 )
{ {
intf_ErrMsg( "css error: invalid manufacturer info length " intf_ErrMsg( "css error: invalid manufacturer info length (%d)",
"(%d)\n", p_dvd->bca.len ); p_dvd->bca.len );
i_ret = -1; i_ret = -1;
} }
else else
...@@ -632,11 +513,104 @@ static int dvd_read_manufact( int i_fd, dvd_struct *p_dvd ) ...@@ -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, static void InitGenericCommand( struct cdrom_generic_command *p_cgc,
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; raw_device_command rdc;
memset( &rdc, 0, sizeof( rdc ) ); memset( &rdc, 0, sizeof( rdc ) );
...@@ -654,22 +628,14 @@ static int communicate_with_dvd( int i_fd, ...@@ -654,22 +628,14 @@ static int communicate_with_dvd( int i_fd,
} }
rdc.command_length = 12; rdc.command_length = 12;
rdc.command[0] = p_cgc->cmd[0];
rdc.command[1] = p_cgc->cmd[1]; /* FIXME: check if this _really_ should go up to [12] */
rdc.command[2] = p_cgc->cmd[2]; for( i = 0 ; i < 13 ; i++ )
rdc.command[3] = p_cgc->cmd[3]; {
rdc.command[4] = p_cgc->cmd[4]; rdc.command[i] = p_cgc->cmd[i];
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];
return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) ); return ioctl( i_fd, B_RAW_DEVICE_COMMAND, &rdc, sizeof(rdc) );
} }
#endif #endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* -dvd_udf to find files * -dvd_udf to find files
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2001 VideoLAN * 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: Stphane Borel <stef@via.ecp.fr> * Author: Stphane Borel <stef@via.ecp.fr>
* *
...@@ -711,7 +711,7 @@ static void DVDInit( input_thread_t * p_input ) ...@@ -711,7 +711,7 @@ static void DVDInit( input_thread_t * p_input )
/* FIXME: We consider here that one title is one title set /* FIXME: We consider here that one title is one title set
* it is not true !!! */ * 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 ); p_method->ifo.vmg.mat.i_tts_nb );
#define area p_input->stream.pp_areas #define area p_input->stream.pp_areas
......
...@@ -634,8 +634,7 @@ create_intf_about (void) ...@@ -634,8 +634,7 @@ create_intf_about (void)
GtkWidget *vbox3; GtkWidget *vbox3;
GtkWidget *label14; GtkWidget *label14;
GtkWidget *label18; GtkWidget *label18;
GtkWidget *hbox1; GtkWidget *frame1;
GtkWidget *label15;
GtkWidget *label16; GtkWidget *label16;
GtkWidget *label17; GtkWidget *label17;
GtkWidget *dialog_action_area; GtkWidget *dialog_action_area;
...@@ -673,40 +672,32 @@ create_intf_about (void) ...@@ -673,40 +672,32 @@ create_intf_about (void)
(GtkDestroyNotify) gtk_widget_unref); (GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (label18); gtk_widget_show (label18);
gtk_box_pack_start (GTK_BOX (vbox3), label18, FALSE, FALSE, 0); 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); frame1 = gtk_frame_new (_("Authors"));
gtk_widget_ref (hbox1); gtk_widget_ref (frame1);
gtk_object_set_data_full (GTK_OBJECT (intf_about), "hbox1", hbox1, gtk_object_set_data_full (GTK_OBJECT (intf_about), "frame1", frame1,
(GtkDestroyNotify) gtk_widget_unref); (GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (hbox1); gtk_widget_show (frame1);
gtk_box_pack_start (GTK_BOX (vbox3), hbox1, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox3), frame1, 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);
label16 = gtk_label_new (_("Rgis 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>\nGal Hendryckx <jimmy@via.ecp.fr>\nSamuel Hocevar <sam@zoy.org>\nBrieuc Jeunhomme <bbp@via.ecp.fr>\nMichel Kaempf <maxx@via.ecp.fr>\nStphane Borel <stef@via.ecp.fr>\nRenaud Dartus <reno@via.ecp.fr>\nHenri Fallon <henri@via.ecp.fr>")); label16 = gtk_label_new (_("Rgis 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>\nGal Hendryckx <jimmy@via.ecp.fr>\nSamuel Hocevar <sam@zoy.org>\nBrieuc Jeunhomme <bbp@via.ecp.fr>\nMichel Kaempf <maxx@via.ecp.fr>\nStphane Borel <stef@via.ecp.fr>\nRenaud Dartus <reno@via.ecp.fr>\nHenri Fallon <henri@via.ecp.fr>"));
gtk_widget_ref (label16); gtk_widget_ref (label16);
gtk_object_set_data_full (GTK_OBJECT (intf_about), "label16", label16, gtk_object_set_data_full (GTK_OBJECT (intf_about), "label16", label16,
(GtkDestroyNotify) gtk_widget_unref); (GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (label16); 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_label_set_justify (GTK_LABEL (label16), GTK_JUSTIFY_LEFT);
gtk_misc_set_alignment (GTK_MISC (label16), 0.5, 0); 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.")); 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_widget_ref (label17);
gtk_object_set_data_full (GTK_OBJECT (intf_about), "label17", label17, gtk_object_set_data_full (GTK_OBJECT (intf_about), "label17", label17,
(GtkDestroyNotify) gtk_widget_unref); (GtkDestroyNotify) gtk_widget_unref);
gtk_widget_show (label17); 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_justify (GTK_LABEL (label17), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (label17), TRUE); gtk_label_set_line_wrap (GTK_LABEL (label17), TRUE);
gtk_misc_set_padding (GTK_MISC (label17), 0, 5); gtk_misc_set_padding (GTK_MISC (label17), 0, 5);
......
...@@ -656,12 +656,12 @@ ...@@ -656,12 +656,12 @@
<class>GtkLabel</class> <class>GtkLabel</class>
<name>label18</name> <name>label18</name>
<label>(C) 1996, 1997, 1998, 1999, 2000, 2001 - the VideoLAN Team</label> <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> <wrap>False</wrap>
<xalign>0.5</xalign> <xalign>0.5</xalign>
<yalign>0.5</yalign> <yalign>0.5</yalign>
<xpad>0</xpad> <xpad>0</xpad>
<ypad>0</ypad> <ypad>5</ypad>
<child> <child>
<padding>0</padding> <padding>0</padding>
<expand>False</expand> <expand>False</expand>
...@@ -670,33 +670,17 @@ ...@@ -670,33 +670,17 @@
</widget> </widget>
<widget> <widget>
<class>GtkHBox</class> <class>GtkFrame</class>
<name>hbox1</name> <name>frame1</name>
<homogeneous>False</homogeneous> <label>Authors</label>
<spacing>0</spacing> <label_xalign>0</label_xalign>
<shadow_type>GTK_SHADOW_ETCHED_IN</shadow_type>
<child> <child>
<padding>0</padding> <padding>0</padding>
<expand>False</expand> <expand>False</expand>
<fill>False</fill> <fill>False</fill>
</child> </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> <widget>
<class>GtkLabel</class> <class>GtkLabel</class>
<name>label16</name> <name>label16</name>
...@@ -722,13 +706,8 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label> ...@@ -722,13 +706,8 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label>
<wrap>False</wrap> <wrap>False</wrap>
<xalign>0.5</xalign> <xalign>0.5</xalign>
<yalign>0</yalign> <yalign>0</yalign>
<xpad>10</xpad> <xpad>5</xpad>
<ypad>10</ypad> <ypad>5</ypad>
<child>
<padding>0</padding>
<expand>False</expand>
<fill>False</fill>
</child>
</widget> </widget>
</widget> </widget>
...@@ -745,7 +724,7 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label> ...@@ -745,7 +724,7 @@ Henri Fallon &lt;henri@via.ecp.fr&gt;</label>
<child> <child>
<padding>0</padding> <padding>0</padding>
<expand>False</expand> <expand>False</expand>
<fill>True</fill> <fill>False</fill>
</child> </child>
</widget> </widget>
</widget> </widget>
......
...@@ -348,6 +348,43 @@ void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line, ...@@ -348,6 +348,43 @@ void _intf_DbgMsgImm( char *psz_file, char *psz_function, int i_line,
} }
#endif #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 ?) * intf_FlushMsg (ok ?)
***************************************************************************** *****************************************************************************
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 2000 VideoLAN * Copyright (C) 2000 VideoLAN
* *
* Authors: * Authors: Samuel Hocevar <sam@zoy.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "mtime.h" #include "mtime.h"
#include "intf_msg.h" #include "intf_msg.h"
#include "debug.h" /* ASSERT */
#include "stream_control.h" #include "stream_control.h"
#include "input_ext-dec.h" #include "input_ext-dec.h"
...@@ -44,13 +43,18 @@ ...@@ -44,13 +43,18 @@
#include "spu_decoder.h" #include "spu_decoder.h"
/* /*****************************************************************************
* Local prototypes * Local prototypes
*/ *****************************************************************************/
static int InitThread ( spudec_thread_t *p_spudec ); static int InitThread ( spudec_thread_t * );
static void RunThread ( spudec_thread_t *p_spudec ); static void RunThread ( spudec_thread_t * );
static void ErrorThread ( spudec_thread_t *p_spudec ); static void ErrorThread ( spudec_thread_t * );
static void EndThread ( spudec_thread_t *p_spudec ); 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 * spudec_CreateThread: create a spu decoder thread
...@@ -59,8 +63,6 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config ) ...@@ -59,8 +63,6 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
{ {
spudec_thread_t * p_spudec; spudec_thread_t * p_spudec;
intf_DbgMsg("spudec debug: creating spu decoder thread");
/* Allocate the memory needed to store the thread's structure */ /* Allocate the memory needed to store the thread's structure */
p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) ); p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
...@@ -84,12 +86,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config ) ...@@ -84,12 +86,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder", if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
(vlc_thread_func_t)RunThread, (void *)p_spudec) ) (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 ); free( p_spudec );
return( 0 ); return( 0 );
} }
intf_DbgMsg("spudec debug: spu decoder thread (%p) created", p_spudec);
return( p_spudec->thread_id ); return( p_spudec->thread_id );
} }
...@@ -104,14 +105,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config ) ...@@ -104,14 +105,11 @@ vlc_thread_t spudec_CreateThread( vdec_config_t * p_config )
*****************************************************************************/ *****************************************************************************/
static int InitThread( spudec_thread_t *p_spudec ) 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->p_config->decoder_config.pf_init_bit_stream(
&p_spudec->bit_stream, &p_spudec->bit_stream,
p_spudec->p_config->decoder_config.p_decoder_fifo ); p_spudec->p_config->decoder_config.p_decoder_fifo );
/* Mark thread as running and return */ /* Mark thread as running and return */
intf_DbgMsg( "spudec debug: InitThread(%p) succeeded", p_spudec );
return( 0 ); return( 0 );
} }
...@@ -123,8 +121,7 @@ static int InitThread( spudec_thread_t *p_spudec ) ...@@ -123,8 +121,7 @@ static int InitThread( spudec_thread_t *p_spudec )
*****************************************************************************/ *****************************************************************************/
static void RunThread( spudec_thread_t *p_spudec ) static void RunThread( spudec_thread_t *p_spudec )
{ {
intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)", intf_WarnMsg( 1, "spudec: spu decoder thread %i spawned", getpid() );
p_spudec, getpid());
/* /*
* Initialize thread and free configuration * Initialize thread and free configuration
...@@ -137,165 +134,9 @@ static void RunThread( spudec_thread_t *p_spudec ) ...@@ -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) ) while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
{ {
int i_packet_size; if( !SyncPacket( p_spudec ) )
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
{ {
/* Unexpected PES packet - trash it */ ParsePacket( p_spudec );
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 );
} }
} }
...@@ -308,6 +149,7 @@ static void RunThread( spudec_thread_t *p_spudec ) ...@@ -308,6 +149,7 @@ static void RunThread( spudec_thread_t *p_spudec )
} }
/* End of thread */ /* End of thread */
intf_WarnMsg( 1, "spudec: destroying spu decoder thread %i", getpid() );
EndThread( p_spudec ); EndThread( p_spudec );
} }
...@@ -336,7 +178,8 @@ static void ErrorThread( spudec_thread_t *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 */ /* 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 */ /* We can release the lock before leaving */
...@@ -351,9 +194,272 @@ static void ErrorThread( spudec_thread_t *p_spudec ) ...@@ -351,9 +194,272 @@ static void ErrorThread( spudec_thread_t *p_spudec )
*****************************************************************************/ *****************************************************************************/
static void EndThread( 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->p_config );
free( p_spudec ); 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 );
} }
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* *
* Authors: * Authors: Samuel Hocevar <sam@zoy.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -43,6 +43,13 @@ typedef struct spudec_thread_s ...@@ -43,6 +43,13 @@ typedef struct spudec_thread_s
*/ */
vout_thread_t * p_vout; /* needed to create the spu objects */ 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; } spudec_thread_t;
/***************************************************************************** /*****************************************************************************
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 2000 VideoLAN * Copyright (C) 2000 VideoLAN
* *
* Authors: * Authors: Vincent Seguin <seguin@via.ecp.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
......
/***************************************************************************** /*****************************************************************************
* video_spu.h : DVD subpicture units functions * video_spu.c : DVD subpicture units functions
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * Copyright (C) 1999, 2000 VideoLAN
* *
* Authors: * Authors: Samuel Hocevar <sam@zoy.org>
* Samuel "Sam" Hocevar <sam@via.ecp.fr> * Henri Fallon <henri@via.ecp.fr>
* Henri Fallon <henri@via.ecp.fr>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -40,272 +39,156 @@ ...@@ -40,272 +39,156 @@
#include "intf_msg.h" #include "intf_msg.h"
typedef struct vout_spu_s /* FIXME: fake palette - the real one has to be sought in the .IFO */
{ static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 };
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;
static int NewLine ( vout_spu_t *p_vspu, int *i_id ); static __inline__ u8 GetNibble( u8 *p_source, int *pi_index )
{
/* i = get_nibble(); */ if( *pi_index & 0x1 )
#define GET_NIBBLE( i ) \ {
if( b_aligned ) \ return( p_source[(*pi_index)++ >> 1] & 0xf );
{ \
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; \
} }
else
/* i = j + get_nibble(); */ {
#define ADD_NIBBLE( i, j ) \ return( p_source[(*pi_index)++ >> 1] >> 4 );
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); \
} }
}
/***************************************************************************** /*****************************************************************************
* 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_bytes_per_pixel, int i_bytes_per_line )
{ {
int i_code = 0x00; int i_code = 0x00;
int i_next = 0;
int i_id = 0; int i_id = 0;
int i_color; 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 */ /* FIXME: we need a way to get this information from the stream */
#define TARGET_WIDTH 720 #define TARGET_WIDTH 720
#define TARGET_HEIGHT 576 #define TARGET_HEIGHT 576
int i_x_scale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH; int i_xscale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH;
int i_y_scale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT; int i_yscale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT;
/* FIXME: fake palette - the real one has to be sought in the .IFO */ u8 *p_source = p_spu->p_data;
static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 }; u8 *p_dest;
int pi_index[2];
boolean_t b_aligned = 1; pi_index[0] = ( p_spu->type.spu.i_offset[0] - 2 ) << 1;
byte_t *p_from[2]; pi_index[1] = ( p_spu->type.spu.i_offset[1] - 2 ) << 1;
vout_spu_t vspu;
p_from[1] = p_subpic->p_data + p_subpic->type.spu.i_offset[1]; p_dest = p_buffer->p_data
p_from[0] = p_subpic->p_data + p_subpic->type.spu.i_offset[0]; /* 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; while( pi_index[0] >> 1 < p_spu->type.spu.i_offset[1] )
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( p_from[0] < (byte_t *)p_subpic->p_data i_code = GetNibble( p_source, pi_index + i_id );
+ p_subpic->type.spu.i_offset[1] )
if( i_code >= 0x04 )
{ {
GET_NIBBLE( i_code ); found_code:
if( i_code >= 0x04 ) if( ((i_code >> 2) + i_x + i_y * i_width) > i_height * i_width )
{
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 )
{ {
if( NewLine( &vspu, &i_id ) < 0 ) intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
return; i_code >> 2, i_height * i_width
- ( (i_code >> 2) + i_x + i_y * i_width ) );
if( !b_aligned ) return;
b_aligned = 1;
} }
else else
{ {
/* we have a boo boo ! */ if( (i_color = i_code & 0x3) )
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 )
{ {
intf_DbgMsg ( "video_spu: invalid draw request ! %d %d", u8 *p_target = p_dest
i_code >> 2, vspu.i_height * vspu.i_width + i_bytes_per_pixel * ((i_x * i_xscale) >> 6)
- ( (i_code >> 2) + vspu.i_x + i_bytes_per_line * ((i_y * i_yscale) >> 6);
+ vspu.i_y * vspu.i_width ) );
return; 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) ) pi_index[i_id]++;
{
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;
} }
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 */ return;
b_aligned = 1;
/* finish the line */
NewLine( &vspu, &i_id );
} }
continue;
} }
continue;
ADD_NIBBLE( i_code, (i_code << 4) ); }
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 );
ADD_NIBBLE( i_code, (i_code << 4) ); if( i_code >= 0x10 ) /* 00 11 xx cc */
if( i_code >= 0x040 ) /* 00 00 11 xx xx cc */ {
goto found_code; /* 00 00 01 xx xx cc */ goto found_code; /* 00 01 xx cc */
}
ADD_NIBBLE( i_code, (i_code << 4) );
if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */ i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
goto found_code; /* 00 00 00 01 xx xx xx cc */ if( i_code >= 0x040 ) /* 00 00 11 xx xx cc */
{
/* if the 14 first bits are 0, then it's a newline */ goto found_code; /* 00 00 01 xx xx cc */
if( i_code <= 0x0003 ) }
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 ) pi_index[i_id]++;
return;
if( !b_aligned )
b_aligned = 1;
} }
else
i_id = ~i_id & 0x1;
i_y++;
i_x = 0;
if( i_width <= i_y )
{ {
/* we have a boo boo ! */ return;
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;
} }
} }
} }
} }
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 );
}
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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 * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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 * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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 * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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 * 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 * it under the terms of the GNU General Public License as published by
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
***************************************************************************** *****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN * 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 * 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 * it under the terms of the GNU General Public License as published by
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment