[vlc-devel] [PATCH] bluray: add support for stream input

Petri Hintukainen phintuka at gmail.com
Tue Dec 15 09:27:16 CET 2015


Enable playback of BluRay disc images over smb/ssh/...
---
 modules/access/bluray.c | 149 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 125 insertions(+), 24 deletions(-)

diff --git a/modules/access/bluray.c b/modules/access/bluray.c
index 45ebdd6..95aaf25 100644
--- a/modules/access/bluray.c
+++ b/modules/access/bluray.c
@@ -97,8 +97,18 @@ vlc_module_begin ()
     add_shortcut("bluray", "file")
 
     set_callbacks(blurayOpen, blurayClose)
+
+    /* demux module */
+    add_submodule()
+        set_description( N_("BluRay demuxer") )
+        set_category( CAT_INPUT )
+        set_subcategory( SUBCAT_INPUT_DEMUX )
+        set_capability( "demux", 5 )
+        set_callbacks( blurayOpen, blurayClose )
+
 vlc_module_end ()
 
+
 /* libbluray's overlay.h defines 2 types of overlay (bd_overlay_plane_e). */
 #define MAX_OVERLAY 2
 
@@ -172,6 +182,9 @@ struct  demux_sys_t
     bool                b_flushed;
     bool                b_pl_playing;       /* true when playing playlist */
 
+    /* stream input */
+    vlc_mutex_t         read_block_lock;
+
     /* Used to store bluray disc path */
     char                *psz_bd_path;
 };
@@ -469,19 +482,94 @@ static void attachThumbnail(demux_t *p_demux)
 }
 
 /*****************************************************************************
+ * stream input
+ *****************************************************************************/
+
+static int probeStream(demux_t *p_demux)
+{
+    /* input must be seekable */
+    bool b_canseek = false, b_canfastseek = false;
+    stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
+    stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &b_canfastseek );
+    if (!b_canseek) {
+        return VLC_EGENERIC;
+    }
+
+    /* first sector(s) should be filled with zeros */
+    size_t i_peek;
+    const uint8_t *p_peek;
+    i_peek = stream_Peek( p_demux->s, &p_peek, 2048 );
+    if( i_peek < 512 ) {
+        return VLC_EGENERIC;
+    }
+    while (i_peek > 0) {
+        if (p_peek[ --i_peek ]) {
+            return VLC_EGENERIC;
+        }
+    }
+
+    return VLC_SUCCESS;
+}
+
+static int blurayReadBlock(void *object, void *buf, int lba, int num_blocks)
+{
+    int result = -1;
+
+    if (object) {
+        demux_t *p_demux = (demux_t*)object;
+        demux_sys_t *p_sys = p_demux->p_sys;
+
+        vlc_mutex_lock(&p_sys->read_block_lock);
+        if (p_demux->s) {
+            if (stream_Seek( p_demux->s, (int64_t)lba * 2048 ) == VLC_SUCCESS) {
+                size_t  req = (size_t)2048 * num_blocks;
+                ssize_t got;
+
+                got = stream_Read( p_demux->s, buf, req);
+                if (got < 0 || (size_t)got != req) {
+                    msg_Err(p_demux, "read from lba %d failed: got %zd/%zu", lba, got, req);
+                }
+                if (got > 0) {
+                    result = got / 2048;
+                }
+            } else {
+                msg_Err(p_demux, "seek to lba %d failed", lba);
+            }
+        }
+        vlc_mutex_unlock(&p_sys->read_block_lock);
+    }
+
+    return result;
+}
+
+/*****************************************************************************
  * blurayOpen: module init function
  *****************************************************************************/
+
 static int blurayOpen(vlc_object_t *object)
 {
     demux_t *p_demux = (demux_t*)object;
     demux_sys_t *p_sys;
+    bool forced;
 
     const char *error_msg = NULL;
 #define BLURAY_ERROR(s) do { error_msg = s; goto error; } while(0)
 
-    if (strcmp(p_demux->psz_access, "bluray")) {
-        // TODO BDMV support, once we figure out what to do in libbluray
-        return VLC_EGENERIC;
+    forced = !strcmp(p_demux->psz_access, "bluray");
+
+    if (p_demux->s) {
+        if (p_demux->psz_access == NULL || !strcmp(p_demux->psz_access, "file")) {
+            /* use access_demux for local files */
+            return VLC_EGENERIC;
+        }
+
+        if (probeStream(p_demux) != VLC_SUCCESS) {
+            return VLC_EGENERIC;
+        }
+    } else {
+        if (!forced || !p_demux->psz_file) {
+            return VLC_EGENERIC;
+        }
     }
 
     /* */
@@ -502,32 +590,45 @@ static int blurayOpen(vlc_object_t *object)
     TAB_INIT(p_sys->i_title, p_sys->pp_title);
     TAB_INIT(p_sys->i_attachments, p_sys->attachments);
 
-    /* store current bd path */
-    if (p_demux->psz_file)
-        p_sys->psz_bd_path = strdup(p_demux->psz_file);
-
-    /* If we're passed a block device, try to convert it to the mount point. */
-    FindMountPoint(&p_sys->psz_bd_path);
-
     last_log_handle = p_demux;
     bd_set_debug_handler(blurayLogHandler);
 
-    p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
-    if (!p_sys->bluray) {
-        free(p_sys->psz_bd_path);
-        free(p_sys);
-        return VLC_EGENERIC;
-    }
-
     vlc_mutex_init(&p_sys->pl_info_lock);
     vlc_mutex_init(&p_sys->bdj_overlay_lock);
+    vlc_mutex_init(&p_sys->read_block_lock); /* used during bd_open_stream() */
+
+    var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
+
+    /* Open BluRay */
+    if (p_demux->s) {
+        p_sys->bluray = bd_init();
+        if (!bd_open_stream(p_sys->bluray, p_demux, blurayReadBlock)) {
+            bd_close(p_sys->bluray);
+            p_sys->bluray = NULL;
+        }
+    } else {
+        /* store current bd path */
+        p_sys->psz_bd_path = strdup(p_demux->psz_file);
+
+        /* If we're passed a block device, try to convert it to the mount point. */
+        FindMountPoint(&p_sys->psz_bd_path);
+
+        p_sys->bluray = bd_open(p_sys->psz_bd_path, NULL);
+    }
+    if (!p_sys->bluray) {
+        goto error;
+    }
 
     /* Warning the user about AACS/BD+ */
     const BLURAY_DISC_INFO *disc_info = bd_get_disc_info(p_sys->bluray);
 
     /* Is it a bluray? */
-    if (!disc_info->bluray_detected)
-        BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
+    if (!disc_info->bluray_detected) {
+        if (forced) {
+            BLURAY_ERROR(_("Path doesn't appear to be a Blu-ray"));
+        }
+        goto error;
+    }
 
     msg_Info(p_demux, "First play: %i, Top menu: %i\n"
                       "HDMV Titles: %i, BD-J Titles: %i, Other: %i",
@@ -645,8 +746,6 @@ static int blurayOpen(vlc_object_t *object)
     if (unlikely(p_sys->p_out == NULL))
         goto error;
 
-    var_AddCallback( p_demux->p_input, "intf-event", onIntfEvent, p_demux );
-
     blurayResetParser(p_demux);
     if (!p_sys->p_parser) {
         msg_Err(p_demux, "Failed to create TS demuxer");
@@ -684,8 +783,9 @@ static void blurayClose(vlc_object_t *object)
      * This will close all the overlays before we release p_vout
      * bd_close(NULL) can crash
      */
-    assert(p_sys->bluray);
-    bd_close(p_sys->bluray);
+    if (p_sys->bluray) {
+        bd_close(p_sys->bluray);
+    }
 
     blurayReleaseVout(p_demux);
 
@@ -707,6 +807,7 @@ static void blurayClose(vlc_object_t *object)
 
     vlc_mutex_destroy(&p_sys->pl_info_lock);
     vlc_mutex_destroy(&p_sys->bdj_overlay_lock);
+    vlc_mutex_destroy(&p_sys->read_block_lock);
 
     free(p_sys->psz_bd_path);
     free(p_sys);
@@ -1717,7 +1818,7 @@ static int blurayControl(demux_t *p_demux, int query, va_list args)
                       p_sys->attachments[p_sys->i_cover_idx]->psz_name );
             vlc_meta_Set( p_meta, vlc_meta_ArtworkURL, psz_url );
         }
-        else if (meta->thumb_count > 0 && meta->thumbnails) {
+        else if (meta->thumb_count > 0 && meta->thumbnails && p_sys->psz_bd_path) {
             char *psz_thumbpath;
             if (asprintf(&psz_thumbpath, "%s" DIR_SEP "BDMV" DIR_SEP "META" DIR_SEP "DL" DIR_SEP "%s",
                           p_sys->psz_bd_path, meta->thumbnails[0].path) > 0) {
-- 
2.5.0



More information about the vlc-devel mailing list