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

Rémi Denis-Courmont remi at remlab.net
Mon Dec 21 22:57:31 CET 2015


On Monday 21 December 2015 22:49:29 Petri Hintukainen wrote:
> Enable playback of BluRay disc images over smb/ssh/...
> ---
>  modules/access/bluray.c | 149
> +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 128
> insertions(+), 21 deletions(-)
> 
> diff --git a/modules/access/bluray.c b/modules/access/bluray.c
> index 60b7b6c..aa8b45b 100644
> --- a/modules/access/bluray.c
> +++ b/modules/access/bluray.c
> @@ -96,6 +96,15 @@ vlc_module_begin ()
>      add_shortcut("bluray", "file")
> 
>      set_callbacks(blurayOpen, blurayClose)
> +
> +    /* demux module */
> +    add_submodule()
> +        set_description( "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).
> */ @@ -171,6 +180,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;
>  };
> @@ -460,19 +472,93 @@ static void attachThumbnail(demux_t *p_demux)
>  }
> 
>  /**************************************************************************
> *** + * stream input
> +
> ***************************************************************************
> **/ +
> +static int probeStream(demux_t *p_demux)
> +{
> +    /* input must be seekable */
> +    bool b_canseek = false;
> +    stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_canseek );
> +    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) {

Should be always true?

> +            if (stream_Seek( p_demux->s, (int64_t)lba * 2048 ) ==
> VLC_SUCCESS) {

That´s going to be quite slow. If you need to read from more than one offset, 
you are typically better off opening the byte stream as many times.

Even for local files, using pread() is often much slower than read() because 
it does not play nicely with the OS-level cache.

(Ditto for AVI, if somebody cares.)

> +                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;
> +    int64_t i_init_pos = 0;
> 
>      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")) {

Strictly speaking, this is case-insensitive. But that´s a bit ugly hack 
anyway.

> +            /* 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;
> +        }
>      }
> 
>      /* */
> @@ -493,29 +579,44 @@ 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)
> +    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) {
> +        i_init_pos = stream_Tell(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);
> +        /* 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);
> +        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;
> +        goto error;
>      }
> 
> -    vlc_mutex_init(&p_sys->pl_info_lock);
> -    vlc_mutex_init(&p_sys->bdj_overlay_lock);
> -
>      /* 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",
> @@ -633,8 +734,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");
> @@ -650,6 +749,12 @@ error:
>      if (error_msg)
>          dialog_Fatal(p_demux, _("Blu-ray error"), "%s", error_msg);
>      blurayClose(object);
> +
> +    if (p_demux->s != NULL && i_init_pos >= 0) {
> +        /* restore stream position */
> +        VLC_UNUSED_RESULT( stream_Seek(p_demux->s, i_init_pos) );

This needs an error message. Probing any further demuxer will not work 
properly.

> +    }
> +
>      return VLC_EGENERIC;
>  #undef BLURAY_ERROR
>  }
> @@ -672,8 +777,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);
> 
> @@ -695,6 +801,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);
> @@ -1705,7 +1812,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) {

-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list