Thomas Guillem
2015-01-27 14:59:25 UTC
libdvdcss | branch: master | Thomas Guillem <***@gllm.fr> | Tue Jan 27 15:54:44 2015 +0100| [f72b87294908e6fd28c79558bb7519e0bef1a3c9] | committer: Jean-Baptiste Kempf
Add dvdcss_open_stream() API function
This allows opening a DVD device using external read/seek callbacks.
NEWS | 2 +
src/device.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/dvdcss/dvdcss.h | 15 +++++++
src/libdvdcss.c | 30 ++++++++++++++
src/libdvdcss.h | 3 ++
5 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 17dd7e7..01743c7 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ Changes since 1.3.0:
* Drop support for Windows 9x and Windows NT.
Windows 2000 is now required.
* Replace BeOS support by Haiku support.
+ * Add dvdcss_open_stream() to public API. This allows installing custom
+ callback functions for accessing DVD, e.g. over the network.
* dvdcss_error() now returns "const char *" instad of "char *".
* Drop support for MSVC versions before 2010.
* Raw device access now errors out if the device cannot be opened.
diff --git a/src/device.c b/src/device.c
index 50fc754..2b82ae1 100644
--- a/src/device.c
+++ b/src/device.c
@@ -79,6 +79,10 @@ static int libc_seek ( dvdcss_t, int );
static int libc_read ( dvdcss_t, void *, int );
static int libc_readv ( dvdcss_t, const struct iovec *, int );
+static int stream_seek ( dvdcss_t, int );
+static int stream_read ( dvdcss_t, void *, int );
+static int stream_readv ( dvdcss_t, const struct iovec *, int );
+
#ifdef _WIN32
static int win2k_open ( dvdcss_t, const char * );
static int win2k_seek ( dvdcss_t, int );
@@ -91,6 +95,9 @@ static int os2_open ( dvdcss_t, const char * );
int dvdcss_use_ioctls( dvdcss_t dvdcss )
{
+ if( dvdcss->p_stream )
+ return 0;
+
#if defined( _WIN32 )
if( dvdcss->b_file )
{
@@ -182,8 +189,8 @@ void dvdcss_check_device ( dvdcss_t dvdcss )
int i, i_fd;
#endif
- /* If the device name is non-null, return */
- if( dvdcss->psz_device[0] )
+ /* If the device name is non-NULL or stream is set, return. */
+ if( dvdcss->psz_device[0] || dvdcss->p_stream )
{
return;
}
@@ -343,6 +350,16 @@ int dvdcss_open_device ( dvdcss_t dvdcss )
}
print_debug( dvdcss, "opening target `%s'", psz_device );
+ /* if callback functions are initialized */
+ if( dvdcss->p_stream )
+ {
+ print_debug( dvdcss, "using stream API for access" );
+ dvdcss->pf_seek = stream_seek;
+ dvdcss->pf_read = stream_read;
+ dvdcss->pf_readv = stream_readv;
+ return 0;
+ }
+
#if defined( _WIN32 )
dvdcss->b_file = 1;
/* If device is "X:" or "X:\", we are not actually opening a file. */
@@ -527,6 +544,31 @@ static int libc_seek( dvdcss_t dvdcss, int i_blocks )
return dvdcss->i_pos;
}
+static int stream_seek( dvdcss_t dvdcss, int i_blocks )
+{
+ off_t i_seek = i_blocks * DVDCSS_BLOCK_SIZE;
+
+ if( !dvdcss->p_stream_cb->pf_seek )
+ return -1;
+
+ if( dvdcss->i_pos == i_blocks )
+ {
+ /* We are already in position */
+ return i_blocks;
+ }
+
+ if( dvdcss->p_stream_cb->pf_seek( dvdcss->p_stream, i_seek ) != 0 )
+ {
+ print_error( dvdcss, "seek error" );
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ dvdcss->i_pos = i_blocks;
+
+ return dvdcss->i_pos;
+}
+
#if defined( _WIN32 )
static int win2k_seek( dvdcss_t dvdcss, int i_blocks )
{
@@ -596,6 +638,46 @@ static int libc_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
return i_ret_blocks;
}
+static int stream_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+{
+ off_t i_size, i_ret, i_ret_blocks;
+
+ i_size = i_blocks * DVDCSS_BLOCK_SIZE;
+
+ if( !dvdcss->p_stream_cb->pf_read )
+ return -1;
+
+ i_ret = dvdcss->p_stream_cb->pf_read( dvdcss->p_stream, p_buffer, i_size );
+
+ if( i_ret < 0 )
+ {
+ print_error( dvdcss, "read error" );
+ dvdcss->i_pos = -1;
+ return i_ret;
+ }
+
+ i_ret_blocks = i_ret / DVDCSS_BLOCK_SIZE;
+
+ /* Handle partial reads */
+ if( i_ret != i_size )
+ {
+ int i_seek;
+
+ dvdcss->i_pos = -1;
+ i_seek = stream_seek( dvdcss, i_ret_blocks );
+ if( i_seek < 0 )
+ {
+ return i_seek;
+ }
+
+ /* We have to return now so that i_pos isn't clobbered */
+ return i_ret_blocks;
+ }
+
+ dvdcss->i_pos += i_ret_blocks;
+ return i_ret_blocks;
+}
+
#if defined( _WIN32 )
static int win2k_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
{
@@ -688,6 +770,30 @@ static int libc_readv ( dvdcss_t dvdcss, const struct iovec *p_iovec,
#endif
}
+/*****************************************************************************
+ * stream_readv: vectored read
+ *****************************************************************************/
+static int stream_readv ( dvdcss_t dvdcss, const struct iovec *p_iovec,
+ int i_blocks )
+{
+ int i_read;
+
+ if( !dvdcss->p_stream_cb->pf_readv )
+ return -1;
+
+ i_read = dvdcss->p_stream_cb->pf_readv( dvdcss->p_stream, p_iovec,
+ i_blocks );
+
+ if( i_read < 0 )
+ {
+ dvdcss->i_pos = -1;
+ return i_read;
+ }
+
+ dvdcss->i_pos += i_read / DVDCSS_BLOCK_SIZE;
+ return i_read / DVDCSS_BLOCK_SIZE;
+}
+
#if defined( _WIN32 )
/*****************************************************************************
* win2k_readv: vectored read using ReadFile for Win2K
diff --git a/src/dvdcss/dvdcss.h b/src/dvdcss/dvdcss.h
index ea62b8b..a630107 100644
--- a/src/dvdcss/dvdcss.h
+++ b/src/dvdcss/dvdcss.h
@@ -31,6 +31,8 @@
#define DVDCSS_DVDCSS_H 1
#endif
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -38,6 +40,17 @@ extern "C" {
/** Library instance handle, to be used for each library call. */
typedef struct dvdcss_s* dvdcss_t;
+/** Set of callbacks to access DVDs in custom ways. */
+typedef struct dvdcss_stream_cb
+{
+ /** custom seek callback */
+ int ( *pf_seek ) ( void *p_stream, uint64_t i_pos);
+ /** custom read callback */
+ int ( *pf_read ) ( void *p_stream, void *buffer, int i_read);
+ /** custom vectored read callback */
+ int ( *pf_readv ) ( void *p_stream, const void *p_iovec, int i_blocks);
+} dvdcss_stream_cb;
+
/** The block size of a DVD. */
#define DVDCSS_BLOCK_SIZE 2048
@@ -73,6 +86,8 @@ typedef struct dvdcss_s* dvdcss_t;
* Exported prototypes.
*/
LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target );
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open_stream( void *p_stream,
+ dvdcss_stream_cb *p_stream_cb );
LIBDVDCSS_EXPORT int dvdcss_close ( dvdcss_t );
LIBDVDCSS_EXPORT int dvdcss_seek ( dvdcss_t,
int i_blocks,
diff --git a/src/libdvdcss.c b/src/libdvdcss.c
index 73a91e8..1b4c680 100644
--- a/src/libdvdcss.c
+++ b/src/libdvdcss.c
@@ -143,6 +143,8 @@
#define MANUFACTURING_DATE_LENGTH 16
+static dvdcss_t dvdcss_open_common ( const char *psz_target, void *p_stream,
+ dvdcss_stream_cb *p_stream_cb );
static void set_verbosity( dvdcss_t dvdcss )
{
const char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
@@ -456,6 +458,27 @@ static void init_cache( dvdcss_t dvdcss )
*/
LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
{
+ return dvdcss_open_common( psz_target, NULL, NULL );
+}
+
+/**
+ * \brief Open a DVD device using dvdcss_stream_cb.
+ *
+ * \param p_stream a private handle used by p_stream_cb
+ * \param p_stream_cb a struct containing seek and read functions
+ * \return a handle to a dvdcss instance or NULL on error.
+ *
+ * \see dvdcss_open()
+ */
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open_stream ( void *p_stream,
+ dvdcss_stream_cb *p_stream_cb )
+{
+ return dvdcss_open_common( NULL, p_stream, p_stream_cb );
+}
+
+static dvdcss_t dvdcss_open_common ( const char *psz_target, void *p_stream,
+ dvdcss_stream_cb *p_stream_cb )
+{
int i_ret;
/* Allocate the library structure. */
@@ -465,6 +488,10 @@ LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
return NULL;
}
+ if( psz_target == NULL &&
+ ( p_stream == NULL || p_stream_cb == NULL ) )
+ return NULL;
+
/* Initialize structure with default values. */
dvdcss->i_pos = 0;
dvdcss->p_titles = NULL;
@@ -473,6 +500,9 @@ LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
dvdcss->i_method = DVDCSS_METHOD_KEY;
dvdcss->psz_cachefile[0] = '\0';
+ dvdcss->p_stream = p_stream;
+ dvdcss->p_stream_cb = p_stream_cb;
+
/* Set library verbosity from DVDCSS_VERBOSE environment variable. */
set_verbosity( dvdcss );
diff --git a/src/libdvdcss.h b/src/libdvdcss.h
index 881bb45..93668e0 100644
--- a/src/libdvdcss.h
+++ b/src/libdvdcss.h
@@ -74,6 +74,9 @@ struct dvdcss_s
char * p_readv_buffer;
int i_readv_buf_size;
#endif /* _WIN32 */
+
+ void *p_stream;
+ dvdcss_stream_cb *p_stream_cb;
};
/*****************************************************************************
Add dvdcss_open_stream() API function
This allows opening a DVD device using external read/seek callbacks.
http://git.videolan.org/gitweb.cgi/libdvdcss.git/?a=commit;h=f72b87294908e6fd28c79558bb7519e0bef1a3c9
---NEWS | 2 +
src/device.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++-
src/dvdcss/dvdcss.h | 15 +++++++
src/libdvdcss.c | 30 ++++++++++++++
src/libdvdcss.h | 3 ++
5 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 17dd7e7..01743c7 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ Changes since 1.3.0:
* Drop support for Windows 9x and Windows NT.
Windows 2000 is now required.
* Replace BeOS support by Haiku support.
+ * Add dvdcss_open_stream() to public API. This allows installing custom
+ callback functions for accessing DVD, e.g. over the network.
* dvdcss_error() now returns "const char *" instad of "char *".
* Drop support for MSVC versions before 2010.
* Raw device access now errors out if the device cannot be opened.
diff --git a/src/device.c b/src/device.c
index 50fc754..2b82ae1 100644
--- a/src/device.c
+++ b/src/device.c
@@ -79,6 +79,10 @@ static int libc_seek ( dvdcss_t, int );
static int libc_read ( dvdcss_t, void *, int );
static int libc_readv ( dvdcss_t, const struct iovec *, int );
+static int stream_seek ( dvdcss_t, int );
+static int stream_read ( dvdcss_t, void *, int );
+static int stream_readv ( dvdcss_t, const struct iovec *, int );
+
#ifdef _WIN32
static int win2k_open ( dvdcss_t, const char * );
static int win2k_seek ( dvdcss_t, int );
@@ -91,6 +95,9 @@ static int os2_open ( dvdcss_t, const char * );
int dvdcss_use_ioctls( dvdcss_t dvdcss )
{
+ if( dvdcss->p_stream )
+ return 0;
+
#if defined( _WIN32 )
if( dvdcss->b_file )
{
@@ -182,8 +189,8 @@ void dvdcss_check_device ( dvdcss_t dvdcss )
int i, i_fd;
#endif
- /* If the device name is non-null, return */
- if( dvdcss->psz_device[0] )
+ /* If the device name is non-NULL or stream is set, return. */
+ if( dvdcss->psz_device[0] || dvdcss->p_stream )
{
return;
}
@@ -343,6 +350,16 @@ int dvdcss_open_device ( dvdcss_t dvdcss )
}
print_debug( dvdcss, "opening target `%s'", psz_device );
+ /* if callback functions are initialized */
+ if( dvdcss->p_stream )
+ {
+ print_debug( dvdcss, "using stream API for access" );
+ dvdcss->pf_seek = stream_seek;
+ dvdcss->pf_read = stream_read;
+ dvdcss->pf_readv = stream_readv;
+ return 0;
+ }
+
#if defined( _WIN32 )
dvdcss->b_file = 1;
/* If device is "X:" or "X:\", we are not actually opening a file. */
@@ -527,6 +544,31 @@ static int libc_seek( dvdcss_t dvdcss, int i_blocks )
return dvdcss->i_pos;
}
+static int stream_seek( dvdcss_t dvdcss, int i_blocks )
+{
+ off_t i_seek = i_blocks * DVDCSS_BLOCK_SIZE;
+
+ if( !dvdcss->p_stream_cb->pf_seek )
+ return -1;
+
+ if( dvdcss->i_pos == i_blocks )
+ {
+ /* We are already in position */
+ return i_blocks;
+ }
+
+ if( dvdcss->p_stream_cb->pf_seek( dvdcss->p_stream, i_seek ) != 0 )
+ {
+ print_error( dvdcss, "seek error" );
+ dvdcss->i_pos = -1;
+ return -1;
+ }
+
+ dvdcss->i_pos = i_blocks;
+
+ return dvdcss->i_pos;
+}
+
#if defined( _WIN32 )
static int win2k_seek( dvdcss_t dvdcss, int i_blocks )
{
@@ -596,6 +638,46 @@ static int libc_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
return i_ret_blocks;
}
+static int stream_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+{
+ off_t i_size, i_ret, i_ret_blocks;
+
+ i_size = i_blocks * DVDCSS_BLOCK_SIZE;
+
+ if( !dvdcss->p_stream_cb->pf_read )
+ return -1;
+
+ i_ret = dvdcss->p_stream_cb->pf_read( dvdcss->p_stream, p_buffer, i_size );
+
+ if( i_ret < 0 )
+ {
+ print_error( dvdcss, "read error" );
+ dvdcss->i_pos = -1;
+ return i_ret;
+ }
+
+ i_ret_blocks = i_ret / DVDCSS_BLOCK_SIZE;
+
+ /* Handle partial reads */
+ if( i_ret != i_size )
+ {
+ int i_seek;
+
+ dvdcss->i_pos = -1;
+ i_seek = stream_seek( dvdcss, i_ret_blocks );
+ if( i_seek < 0 )
+ {
+ return i_seek;
+ }
+
+ /* We have to return now so that i_pos isn't clobbered */
+ return i_ret_blocks;
+ }
+
+ dvdcss->i_pos += i_ret_blocks;
+ return i_ret_blocks;
+}
+
#if defined( _WIN32 )
static int win2k_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
{
@@ -688,6 +770,30 @@ static int libc_readv ( dvdcss_t dvdcss, const struct iovec *p_iovec,
#endif
}
+/*****************************************************************************
+ * stream_readv: vectored read
+ *****************************************************************************/
+static int stream_readv ( dvdcss_t dvdcss, const struct iovec *p_iovec,
+ int i_blocks )
+{
+ int i_read;
+
+ if( !dvdcss->p_stream_cb->pf_readv )
+ return -1;
+
+ i_read = dvdcss->p_stream_cb->pf_readv( dvdcss->p_stream, p_iovec,
+ i_blocks );
+
+ if( i_read < 0 )
+ {
+ dvdcss->i_pos = -1;
+ return i_read;
+ }
+
+ dvdcss->i_pos += i_read / DVDCSS_BLOCK_SIZE;
+ return i_read / DVDCSS_BLOCK_SIZE;
+}
+
#if defined( _WIN32 )
/*****************************************************************************
* win2k_readv: vectored read using ReadFile for Win2K
diff --git a/src/dvdcss/dvdcss.h b/src/dvdcss/dvdcss.h
index ea62b8b..a630107 100644
--- a/src/dvdcss/dvdcss.h
+++ b/src/dvdcss/dvdcss.h
@@ -31,6 +31,8 @@
#define DVDCSS_DVDCSS_H 1
#endif
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -38,6 +40,17 @@ extern "C" {
/** Library instance handle, to be used for each library call. */
typedef struct dvdcss_s* dvdcss_t;
+/** Set of callbacks to access DVDs in custom ways. */
+typedef struct dvdcss_stream_cb
+{
+ /** custom seek callback */
+ int ( *pf_seek ) ( void *p_stream, uint64_t i_pos);
+ /** custom read callback */
+ int ( *pf_read ) ( void *p_stream, void *buffer, int i_read);
+ /** custom vectored read callback */
+ int ( *pf_readv ) ( void *p_stream, const void *p_iovec, int i_blocks);
+} dvdcss_stream_cb;
+
/** The block size of a DVD. */
#define DVDCSS_BLOCK_SIZE 2048
@@ -73,6 +86,8 @@ typedef struct dvdcss_s* dvdcss_t;
* Exported prototypes.
*/
LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target );
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open_stream( void *p_stream,
+ dvdcss_stream_cb *p_stream_cb );
LIBDVDCSS_EXPORT int dvdcss_close ( dvdcss_t );
LIBDVDCSS_EXPORT int dvdcss_seek ( dvdcss_t,
int i_blocks,
diff --git a/src/libdvdcss.c b/src/libdvdcss.c
index 73a91e8..1b4c680 100644
--- a/src/libdvdcss.c
+++ b/src/libdvdcss.c
@@ -143,6 +143,8 @@
#define MANUFACTURING_DATE_LENGTH 16
+static dvdcss_t dvdcss_open_common ( const char *psz_target, void *p_stream,
+ dvdcss_stream_cb *p_stream_cb );
static void set_verbosity( dvdcss_t dvdcss )
{
const char *psz_verbose = getenv( "DVDCSS_VERBOSE" );
@@ -456,6 +458,27 @@ static void init_cache( dvdcss_t dvdcss )
*/
LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
{
+ return dvdcss_open_common( psz_target, NULL, NULL );
+}
+
+/**
+ * \brief Open a DVD device using dvdcss_stream_cb.
+ *
+ * \param p_stream a private handle used by p_stream_cb
+ * \param p_stream_cb a struct containing seek and read functions
+ * \return a handle to a dvdcss instance or NULL on error.
+ *
+ * \see dvdcss_open()
+ */
+LIBDVDCSS_EXPORT dvdcss_t dvdcss_open_stream ( void *p_stream,
+ dvdcss_stream_cb *p_stream_cb )
+{
+ return dvdcss_open_common( NULL, p_stream, p_stream_cb );
+}
+
+static dvdcss_t dvdcss_open_common ( const char *psz_target, void *p_stream,
+ dvdcss_stream_cb *p_stream_cb )
+{
int i_ret;
/* Allocate the library structure. */
@@ -465,6 +488,10 @@ LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
return NULL;
}
+ if( psz_target == NULL &&
+ ( p_stream == NULL || p_stream_cb == NULL ) )
+ return NULL;
+
/* Initialize structure with default values. */
dvdcss->i_pos = 0;
dvdcss->p_titles = NULL;
@@ -473,6 +500,9 @@ LIBDVDCSS_EXPORT dvdcss_t dvdcss_open ( const char *psz_target )
dvdcss->i_method = DVDCSS_METHOD_KEY;
dvdcss->psz_cachefile[0] = '\0';
+ dvdcss->p_stream = p_stream;
+ dvdcss->p_stream_cb = p_stream_cb;
+
/* Set library verbosity from DVDCSS_VERBOSE environment variable. */
set_verbosity( dvdcss );
diff --git a/src/libdvdcss.h b/src/libdvdcss.h
index 881bb45..93668e0 100644
--- a/src/libdvdcss.h
+++ b/src/libdvdcss.h
@@ -74,6 +74,9 @@ struct dvdcss_s
char * p_readv_buffer;
int i_readv_buf_size;
#endif /* _WIN32 */
+
+ void *p_stream;
+ dvdcss_stream_cb *p_stream_cb;
};
/*****************************************************************************