[libdvdcss-devel] Add dvdcss_open_stream() API function
[email protected] (Thomas Guillem) Tue, 27 Jan 2015 15:59:25 +0100 (CET)
| Newsgroups | gmane.comp.video.videolan.libdvdcss,gmane.comp.video.videolan.libdvdcss.devel |
|---|---|
| Message-ID | <[email protected]> |
libdvdcss | branch: master | Thomas Guillem <[email protected]> | 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. Signed-off-by: Diego Biurrun <[email protected]> Signed-off-by: Jean-Baptiste Kempf <[email protected]> > 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; }; /***************************************************************************** _______________________________________________ libdvdcss-devel mailing list [email protected] https://mailman.videolan.org/listinfo/libdvdcss-devel