diff --git a/multimedia/xine-lib/Makefile b/multimedia/xine-lib/Makefile index 9903ebfd8db..5125b7f8a20 100644 --- a/multimedia/xine-lib/Makefile +++ b/multimedia/xine-lib/Makefile @@ -1,11 +1,11 @@ -# $OpenBSD: Makefile,v 1.87 2012/04/07 17:24:36 ajacoutot Exp $ +# $OpenBSD: Makefile,v 1.88 2012/04/08 07:37:25 ajacoutot Exp $ SHARED_ONLY= Yes COMMENT= multimedia decoding library DISTNAME= xine-lib-1.1.20.1 -REVISION= 0 +REVISION= 1 CATEGORIES= multimedia MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=xine/} EXTRACT_SUFX= .tar.xz @@ -23,17 +23,21 @@ PERMIT_DISTFILES_CDROM= Yes PERMIT_DISTFILES_FTP= Yes WANTLIB= FLAC GL GLU SDL X11 Xau Xdamage Xdmcp Xext Xfixes Xinerama \ - Xv XvMCW Xxf86vm a52 avcodec avutil c cdio dca drm dvdnav \ - dvdread expat faad fontconfig freetype gsm iso9660 jpeg \ - lcms m mad modplug mpcdec mng mp3lame ogg orc-0.4 postproc \ - pthread-stubs pthread schroedinger-1.0 sndio speex stdc++ \ - theora theoradec theoraenc usbhid vcdinfo vorbis vorbisenc \ - vpx wavpack x264 xcb-shape xcb-shm xcb-xv xcb z + Xv XvMCW Xxf86vm a52 avcodec avutil bluray c cdio dca drm \ + dvdnav dvdread expat faad fontconfig freetype gsm iso9660 \ + jpeg lcms m mad modplug mpcdec mng mp3lame ogg orc-0.4 \ + postproc pthread-stubs pthread schroedinger-1.0 sndio speex \ + stdc++ theora theoradec theoraenc usbhid vcdinfo vorbis \ + vorbisenc vpx wavpack x264 xcb-shape xcb-shm xcb-xv xcb \ + xml2 z XINEAPI_REV= 1.30 SUBST_VARS+= XINEAPI_REV MODULES= devel/gettext +BUILD_DEPENDS= devel/libtool \ + ${MODGNU_AUTOCONF_DEPENDS} \ + ${MODGNU_AUTOMAKE_DEPENDS} LIB_DEPENDS= audio/faad \ audio/flac \ audio/liba52 \ @@ -47,17 +51,20 @@ LIB_DEPENDS= audio/faad \ audio/speex \ audio/wavpack \ devel/sdl \ + multimedia/libbluray \ multimedia/libdvdnav \ multimedia/libtheora \ graphics/ffmpeg>=20111126 \ graphics/libmng \ graphics/vcdimager +AUTOCONF_VERSION= 2.68 +AUTOMAKE_VERSION= 1.11 + USE_GMAKE= Yes USE_LIBTOOL= Yes USE_GROFF= Yes -CONFIGURE_STYLE= autoconf -AUTOCONF_VERSION= 2.68 +CONFIGURE_STYLE= gnu CONFIGURE_ARGS+=--disable-aalib \ --disable-dxr3 \ --disable-fb \ @@ -94,6 +101,10 @@ NO_REGRESS= Yes post-extract: @perl -pi -e 's/\r\n/\n/g' ${WRKSRC}/src/demuxers/asfheader.c +post-patch: + @cd ${WRKSRC} && env AUTOCONF_VERSION=${AUTOCONF_VERSION} AUTOMAKE_VERSION=${AUTOMAKE_VERSION} \ + sh autogen.sh noconfig + post-install: @find ${PREFIX}/lib/xine/plugins -name '*.a' -print | xargs rm diff --git a/multimedia/xine-lib/patches/patch-autogen_sh b/multimedia/xine-lib/patches/patch-autogen_sh new file mode 100644 index 00000000000..d7f3fd2734a --- /dev/null +++ b/multimedia/xine-lib/patches/patch-autogen_sh @@ -0,0 +1,88 @@ +$OpenBSD: patch-autogen_sh,v 1.1 2012/04/08 07:37:25 ajacoutot Exp $ +--- autogen.sh.orig Tue Oct 4 17:42:52 2011 ++++ autogen.sh Sat Apr 7 14:22:42 2012 +@@ -70,18 +70,7 @@ detect_autoconf() { + RETVAL=$? + NUM_RESULT=$# + RESULT_FILE=$3 +- if [ $RETVAL -eq 0 -a $NUM_RESULT -eq 3 -a -f "$RESULT_FILE" ]; then +- AC="`autoconf --version | parse_version_no`" +- if [ `expr $AC` -ge "`echo $AUTOCONF_MIN | parse_version_no`" ]; then +- autoconf_ok=yes +- fi +- else +- echo +- echo "**Error**: You must have \`autoconf' >= $AUTOCONF_MIN installed to" +- echo " compile $PROG. Download the appropriate package" +- echo " for your distribution or source from ftp.gnu.org." +- exit 1 +- fi ++ autoconf_ok=yes + } + + run_autoheader () { +@@ -107,7 +96,9 @@ run_autoconf () { + + echo $_echo_n " + Running autoconf: $_echo_c"; + autoconf; +- sed -i -e '/gnu_ld/,/;;/ s/--rpath \${wl}/--rpath,/' configure ++ sed -e '/gnu_ld/,/;;/ s/--rpath \${wl}/--rpath,/' configure > configure.new ++ mv configure.new configure ++ chmod +x configure + echo "done." + } + +@@ -120,12 +111,7 @@ try_libtool_executable() { + RETVAL=$? + NUM_RESULT=$# + RESULT_FILE=$3 +- if [ $RETVAL -eq 0 -a $NUM_RESULT -eq 3 -a -f "$RESULT_FILE" ]; then +- LT="`$libtool --version | awk '{ print $4 }' | parse_version_no`" +- if [ `expr $LT` -ge "`echo $LIBTOOL_MIN | parse_version_no`" ]; then +- libtool_ok=yes +- fi +- fi ++ libtool_ok=yes + } + + detect_libtool() { +@@ -168,18 +154,7 @@ detect_automake() { + RETVAL=$? + NUM_RESULT=$# + RESULT_FILE=$3 +- if [ $RETVAL -eq 0 -a $NUM_RESULT -eq 3 -a -f "$RESULT_FILE" ]; then +- AM="`automake --version | parse_version_no`" +- if [ `expr $AM` -ge "`echo $AUTOMAKE_MIN | parse_version_no`" ]; then +- automake_ok=yes +- fi +- else +- echo +- echo "**Error**: You must have \`automake' >= $AUTOMAKE_MIN installed to" +- echo " compile $PROG. Download the appropriate package" +- echo " for your distribution or source from ftp.gnu.org." +- exit 1 +- fi ++ automake_ok=yes + } + + run_automake () { +@@ -206,18 +181,7 @@ detect_aclocal() { + RETVAL=$? + NUM_RESULT=$# + RESULT_FILE=$3 +- if [ $RETVAL -eq 0 -a $NUM_RESULT -eq 3 -a -f "$RESULT_FILE" ]; then +- AC="`aclocal --version | parse_version_no`" +- if [ `expr $AC` -ge "`echo $AUTOMAKE_MIN | parse_version_no`" ]; then +- aclocal_ok=yes +- fi +- else +- echo +- echo "**Error**: You must have \`aclocal' >= $AUTOMAKE_MIN installed to" +- echo " compile $PROG. Download the appropriate package" +- echo " for your distribution or source from ftp.gnu.org." +- exit 1 +- fi ++ aclocal_ok=yes + } + + run_aclocal () { diff --git a/multimedia/xine-lib/patches/patch-configure_ac b/multimedia/xine-lib/patches/patch-configure_ac index 1acc410278a..ad82b277ee5 100644 --- a/multimedia/xine-lib/patches/patch-configure_ac +++ b/multimedia/xine-lib/patches/patch-configure_ac @@ -1,6 +1,6 @@ -$OpenBSD: patch-configure_ac,v 1.10 2012/01/05 08:52:26 ajacoutot Exp $ +$OpenBSD: patch-configure_ac,v 1.11 2012/04/08 07:37:25 ajacoutot Exp $ --- configure.ac.orig Sun Jan 1 12:30:52 2012 -+++ configure.ac Sun Jan 1 17:19:01 2012 ++++ configure.ac Sat Apr 7 13:58:35 2012 @@ -558,9 +558,9 @@ t q b :q @@ -26,3 +26,26 @@ $OpenBSD: patch-configure_ac,v 1.10 2012/01/05 08:52:26 ajacoutot Exp $ AC_SUBST(MNG_LIBS) else have_libmng=no +@@ -1672,6 +1673,22 @@ else + no_gdkpixbuf=yes + fi + AM_CONDITIONAL(HAVE_GDK_PIXBUF, test "x$no_gdkpixbuf" != "xyes") ++ ++dnl --------------------------------------------- ++dnl libbluray support ++dnl --------------------------------------------- ++AC_ARG_ENABLE([bluray], ++ AS_HELP_STRING([--disable-bluray], [Do not build BluRay support]), ++ [with_bluray=$enableval], [with_bluray=yes]) ++ ++if test "x$with_bluray" != "xno"; then ++ PKG_CHECK_MODULES([LIBBLURAY], [libbluray >= 0.2.1], ++ [have_libbluray=yes], ++ AC_MSG_RESULT(*** All of the libbluray dependent parts will be disabled ***)) ++ AC_SUBST(LIBBLURAY_CFLAGS) ++ AC_SUBST(LIBBLURAY_LIBS) ++fi ++AM_CONDITIONAL(HAVE_LIBBLURAY, test "x$have_libbluray" = "xyes") + + dnl --------------------------------------------- + dnl libsmbclient support diff --git a/multimedia/xine-lib/patches/patch-src_input_Makefile_am b/multimedia/xine-lib/patches/patch-src_input_Makefile_am new file mode 100644 index 00000000000..08a50dea716 --- /dev/null +++ b/multimedia/xine-lib/patches/patch-src_input_Makefile_am @@ -0,0 +1,34 @@ +$OpenBSD: patch-src_input_Makefile_am,v 1.1 2012/04/08 07:37:25 ajacoutot Exp $ +--- src/input/Makefile.am.orig Sat Apr 7 13:15:19 2012 ++++ src/input/Makefile.am Sat Apr 7 13:16:28 2012 +@@ -56,6 +56,10 @@ if DVB + in_dvb = xineplug_inp_dvb.la + endif + ++if HAVE_LIBBLURAY ++in_bluray = xineplug_inp_bluray.la ++endif ++ + AM_CFLAGS = -D_LARGEFILE64_SOURCE $(GNOME_VFS_CFLAGS) $(ALSA_CFLAGS) $(DVD_CFLAGS) + + xineplug_LTLIBRARIES = \ +@@ -75,6 +79,7 @@ xineplug_LTLIBRARIES = \ + xineplug_inp_net.la \ + $(in_pvr) \ + $(in_dvb) \ ++ $(in_bluray) \ + xineplug_inp_cdda.la + + +@@ -162,6 +167,11 @@ xineplug_inp_pvr_la_SOURCES = input_pvr.c + xineplug_inp_pvr_la_LIBADD = $(XINE_LIB) $(PTHREAD_LIBS) $(LTLIBINTL) + xineplug_inp_pvr_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) + xineplug_inp_pvr_la_LDFLAGS = $(xineplug_ldflags) ++ ++xineplug_inp_bluray_la_SOURCES = input_bluray.c media_helper.c ++xineplug_inp_bluray_la_LIBADD = $(XINE_LIB) $(LIBBLURAY_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) ++xineplug_inp_bluray_la_CFLAGS = $(VISIBILITY_FLAG) $(AM_CFLAGS) $(LIBBLURAY_CFLAGS) ++xineplug_inp_bluray_la_LDFLAGS = $(xineplug_ldflags) + + xineinclude_HEADERS = input_plugin.h + noinst_HEADERS = net_buf_ctrl.h mms.h mmsh.h pnm.h media_helper.h http_helper.h diff --git a/multimedia/xine-lib/patches/patch-src_input_input_bluray_c b/multimedia/xine-lib/patches/patch-src_input_input_bluray_c new file mode 100644 index 00000000000..888be1449ec --- /dev/null +++ b/multimedia/xine-lib/patches/patch-src_input_input_bluray_c @@ -0,0 +1,1751 @@ +$OpenBSD: patch-src_input_input_bluray_c,v 1.1 2012/04/08 07:37:25 ajacoutot Exp $ + +Add BluRay input plugin. + +--- src/input/input_bluray.c.orig Sat Apr 7 13:17:42 2012 ++++ src/input/input_bluray.c Sat Apr 7 13:17:36 2012 +@@ -0,0 +1,1744 @@ ++/* ++ * Copyright (C) 2000-2011 the xine project ++ * Copyright (C) 2009-2011 Petri Hintukainen ++ * ++ * This file is part of xine, a free video player. ++ * ++ * xine 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. ++ * ++ * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA ++ * ++ * Input plugin for BluRay discs / images ++ * ++ * Requires libbluray 0.2.1 or later: ++ * http://www.videolan.org/developers/libbluray.html ++ * git://git.videolan.org/libbluray.git ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* libbluray */ ++#include ++#include ++#include ++#include ++#include ++ ++/* xine */ ++ ++#define LOG_MODULE "input_bluray" ++#define LOG_VERBOSE ++ ++#define LOG ++ ++#define LOGMSG(x...) xine_log (this->stream->xine, XINE_LOG_MSG, "input_bluray: " x); ++ ++#define XINE_ENGINE_INTERNAL ++ ++#include "xine_internal.h" ++#include "xineutils.h" ++#include "input_plugin.h" ++#include "media_helper.h" ++ ++/* */ ++ ++#ifndef MIN ++# define MIN(a,b) ((a)<(b)?(a):(b)) ++#endif ++#ifndef MAX ++# define MAX(a,b) ((a)>(b)?(a):(b)) ++#endif ++ ++#define ALIGNED_UNIT_SIZE 6144 ++#define PKT_SIZE 192 ++#define TICKS_IN_MS 45 ++ ++#define MIN_TITLE_LENGTH 180 ++ ++/* */ ++ ++typedef struct { ++ ++ input_class_t input_class; ++ ++ xine_t *xine; ++ ++ xine_mrl_t **xine_playlist; ++ int xine_playlist_size; ++ ++ /* config */ ++ char *mountpoint; ++ char *device; ++ char *language; ++ char *country; ++ int region; ++ int parental; ++} bluray_input_class_t; ++ ++typedef struct { ++ input_plugin_t input_plugin; ++ ++ bluray_input_class_t *class; ++ ++ xine_stream_t *stream; ++ xine_event_queue_t *event_queue; ++ xine_osd_t *osd[2]; ++ ++ char *mrl; ++ char *disc_root; ++ char *disc_name; ++ ++ BLURAY *bdh; ++ ++ const BLURAY_DISC_INFO *disc_info; ++ const META_DL *meta_dl; /* disc library meta data */ ++ ++ int num_title_idx; /* number of relevant playlists */ ++ int current_title_idx; ++ int num_titles; /* navigation mode, number of titles in disc index */ ++ int current_title; /* navigation mode, title from disc index */ ++ BLURAY_TITLE_INFO *title_info; ++ pthread_mutex_t title_info_mutex; /* lock this when accessing title_info outside of input/demux thread */ ++ unsigned int current_clip; ++ time_t still_end_time; ++ int pg_stream; ++ ++ uint8_t nav_mode : 1; ++ uint8_t error : 1; ++ uint8_t menu_open : 1; ++ uint8_t stream_flushed : 1; ++ uint8_t demux_action_req : 1; ++ uint8_t end_of_title : 1; ++ uint8_t pg_enable : 1; ++ int mouse_inside_button; ++} bluray_input_plugin_t; ++ ++/* ++ * overlay ++ */ ++ ++#define PALETTE_INDEX_BACKGROUND 0xff ++ ++static void send_num_buttons(bluray_input_plugin_t *this, int n) ++{ ++ xine_event_t event; ++ xine_ui_data_t data; ++ ++ event.type = XINE_EVENT_UI_NUM_BUTTONS; ++ event.data = &data; ++ event.data_length = sizeof(data); ++ data.num_buttons = n; ++ ++ xine_event_send(this->stream, &event); ++} ++ ++static void clear_overlay(xine_osd_t *osd) ++{ ++ /* palette entry 0xff is background --> can't use xine_osd_clear(). */ ++ memset(osd->osd.area, PALETTE_INDEX_BACKGROUND, osd->osd.width * osd->osd.height); ++ osd->osd.x1 = osd->osd.width; ++ osd->osd.y1 = osd->osd.height; ++ osd->osd.x2 = 0; ++ osd->osd.y2 = 0; ++} ++ ++static xine_osd_t *get_overlay(bluray_input_plugin_t *this, int plane) ++{ ++ if (!this->osd[plane]) { ++ this->osd[plane] = xine_osd_new(this->stream, 0, 0, 1920, 1080); ++ clear_overlay(this->osd[plane]); ++ } ++ if (!this->pg_enable) { ++ _x_select_spu_channel(this->stream, -1); ++ } ++ return this->osd[plane]; ++} ++ ++static void close_overlay(bluray_input_plugin_t *this, int plane) ++{ ++ if (plane < 0) { ++ close_overlay(this, 0); ++ close_overlay(this, 1); ++ return; ++ } ++ ++ if (plane < 2 && this->osd[plane]) { ++ xine_osd_free(this->osd[plane]); ++ this->osd[plane] = NULL; ++ if (plane == 1) { ++ send_num_buttons(this, 0); ++ this->menu_open = 0; ++ } ++ } ++} ++ ++static void open_overlay(bluray_input_plugin_t *this, const BD_OVERLAY * const ov) ++{ ++ lprintf("open_overlay(%d,%d)\n", ov->w, ov->h); ++ ++ if (this->osd[ov->plane]) { ++ close_overlay(this, ov->plane); ++ } ++ ++ this->osd[ov->plane] = xine_osd_new(this->stream, ov->x, ov->y, ov->w, ov->h); ++ clear_overlay(this->osd[ov->plane]); ++} ++ ++static void draw_bitmap(xine_osd_t *osd, const BD_OVERLAY * const ov) ++{ ++ unsigned i; ++ ++ /* convert and set palette */ ++ if (ov->palette) { ++ uint32_t color[256]; ++ uint8_t trans[256]; ++ for(i = 0; i < 256; i++) { ++ trans[i] = ov->palette[i].T; ++ color[i] = (ov->palette[i].Y << 16) | (ov->palette[i].Cr << 8) | ov->palette[i].Cb; ++ } ++ ++ xine_osd_set_palette(osd, color, trans); ++ } ++ ++ /* uncompress and draw bitmap */ ++ if (ov->img) { ++ const BD_PG_RLE_ELEM *rlep = ov->img; ++ uint8_t *img = malloc(ov->w * ov->h); ++ unsigned pixels = ov->w * ov->h; ++ ++ for (i = 0; i < pixels; i += rlep->len, rlep++) { ++ memset(img + i, rlep->color, rlep->len); ++ } ++ ++ xine_osd_draw_bitmap(osd, img, ov->x, ov->y, ov->w, ov->h, NULL); ++ ++ free(img); ++ } ++} ++ ++static void overlay_proc(void *this_gen, const BD_OVERLAY * const ov) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ xine_osd_t *osd; ++ ++ if (!this) { ++ return; ++ } ++ ++ if (!ov) { ++ /* hide OSD */ ++ close_overlay(this, -1); ++ return; ++ } ++ ++ if (ov->plane > 1) { ++ return; ++ } ++ ++ switch (ov->cmd) { ++ case BD_OVERLAY_INIT: ++ open_overlay(this, ov); ++ return; ++ case BD_OVERLAY_CLOSE: ++ close_overlay(this, ov->plane); ++ return; ++ } ++ ++ osd = get_overlay(this, ov->plane); ++ ++ switch (ov->cmd) { ++ case BD_OVERLAY_DRAW: ++ draw_bitmap(osd, ov); ++ return; ++ ++ case BD_OVERLAY_WIPE: ++ xine_osd_draw_rect(osd, ov->x, ov->y, ov->x + ov->w - 1, ov->y + ov->h - 1, PALETTE_INDEX_BACKGROUND, 1); ++ return; ++ ++ case BD_OVERLAY_CLEAR: ++ xine_osd_hide(osd, 0); ++ clear_overlay(osd); ++ return; ++ ++ case BD_OVERLAY_FLUSH: ++ xine_osd_show(osd, 0); ++ ++ if (ov->plane == 1) { ++ this->menu_open = 1; ++ send_num_buttons(this, 1); ++ } ++ return; ++ ++ default: ++ lprintf("unknown overlay command %d\n", ov->cmd); ++ return; ++ } ++} ++ ++/* ++ * stream info ++ */ ++ ++static void update_stream_info(bluray_input_plugin_t *this) ++{ ++ if (this->title_info) { ++ /* set stream info */ ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_COUNT, this->title_info->angle_count); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_CHAPTERS, this->title_info->chapter_count > 0); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_COUNT, this->title_info->chapter_count); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, bd_get_current_chapter(this->bdh) + 1); ++ } ++} ++ ++static void update_title_name(bluray_input_plugin_t *this) ++{ ++ char title_name[64] = ""; ++ xine_ui_data_t udata; ++ xine_event_t uevent = { ++ .type = XINE_EVENT_UI_SET_TITLE, ++ .stream = this->stream, ++ .data = &udata, ++ .data_length = sizeof(udata) ++ }; ++ ++ /* check disc library metadata */ ++ if (this->meta_dl) { ++ unsigned i; ++ for (i = 0; i < this->meta_dl->toc_count; i++) ++ if (this->meta_dl->toc_entries[i].title_number == (unsigned)this->current_title) ++ if (this->meta_dl->toc_entries[i].title_name) ++ if (strlen(this->meta_dl->toc_entries[i].title_name) > 2) ++ strncpy(title_name, this->meta_dl->toc_entries[i].title_name, sizeof(title_name)); ++ } ++ ++ /* title name */ ++ if (title_name[0]) { ++ } else if (this->current_title == BLURAY_TITLE_TOP_MENU) { ++ strcpy(title_name, "Top Menu"); ++ } else if (this->current_title == BLURAY_TITLE_FIRST_PLAY) { ++ strcpy(title_name, "First Play"); ++ } else if (this->nav_mode) { ++ snprintf(title_name, sizeof(title_name), "Title %d/%d (PL %d/%d)", ++ this->current_title, this->num_titles, ++ this->current_title_idx + 1, this->num_title_idx); ++ } else { ++ snprintf(title_name, sizeof(title_name), "Title %d/%d", ++ this->current_title_idx + 1, this->num_title_idx); ++ } ++ ++ /* disc name */ ++ if (this->disc_name && this->disc_name[0]) { ++ udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s, %s", ++ this->disc_name, title_name); ++ } else { ++ udata.str_len = snprintf(udata.str, sizeof(udata.str), "%s", ++ title_name); ++ } ++ ++ _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, udata.str); ++ ++ xine_event_send(this->stream, &uevent); ++} ++ ++static void update_title_info(bluray_input_plugin_t *this, int playlist_id) ++{ ++ /* update title_info */ ++ ++ pthread_mutex_lock(&this->title_info_mutex); ++ ++ if (this->title_info) ++ bd_free_title_info(this->title_info); ++ ++ if (playlist_id < 0) ++ this->title_info = bd_get_title_info(this->bdh, this->current_title_idx, 0); ++ else ++ this->title_info = bd_get_playlist_info(this->bdh, playlist_id, 0); ++ ++ pthread_mutex_unlock(&this->title_info_mutex); ++ ++ if (!this->title_info) { ++ LOGMSG("bd_get_title_info(%d) failed\n", this->current_title_idx); ++ return; ++ } ++ ++#ifdef LOG ++ int ms = this->title_info->duration / INT64_C(90); ++ lprintf("Opened title %d. Length %"PRId64" bytes / %02d:%02d:%02d.%03d\n", ++ this->current_title_idx, bd_get_title_size(this->bdh), ++ ms / 3600000, (ms % 3600000 / 60000), (ms % 60000) / 1000, ms % 1000); ++#endif ++ ++ /* calculate and set stream rate */ ++ ++ uint64_t rate = bd_get_title_size(this->bdh) * UINT64_C(8) // bits ++ * INT64_C(90000) ++ / (uint64_t)(this->title_info->duration); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, rate); ++ ++ /* set stream info */ ++ ++ if (this->nav_mode) { ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_titles); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title); ++ } else { ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_COUNT, this->num_title_idx); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_TITLE_NUMBER, this->current_title_idx + 1); ++ } ++ ++ update_stream_info(this); ++ ++ /* set title name */ ++ ++ update_title_name(this); ++} ++ ++/* ++ * libbluray event handling ++ */ ++ ++static void stream_flush(bluray_input_plugin_t *this) ++{ ++ if (this->stream_flushed || !this->stream) ++ return; ++ ++ lprintf("Stream flush\n"); ++ ++ this->stream_flushed = 1; ++ ++ xine_event_t event = { ++ .type = XINE_EVENT_END_OF_CLIP, ++ .stream = this->stream, ++ .data = NULL, ++ .data_length = 0, ++ }; ++ xine_event_send (this->stream, &event); ++ ++ this->demux_action_req = 1; ++} ++ ++static void stream_reset(bluray_input_plugin_t *this) ++{ ++ if (!this || !this->stream) ++ return; ++ ++ lprintf("Stream reset\n"); ++ ++ xine_event_t event = { ++ .type = XINE_EVENT_PIDS_CHANGE, ++ .stream = this->stream, ++ .data = NULL, ++ .data_length = 0, ++ }; ++ ++ if (!this->end_of_title) { ++ _x_demux_flush_engine(this->stream); ++ } ++ ++ xine_event_send (this->stream, &event); ++ ++ this->demux_action_req = 1; ++} ++ ++static void wait_secs(bluray_input_plugin_t *this, unsigned seconds) ++{ ++ stream_flush(this); ++ ++ if (this->still_end_time) { ++ if (time(NULL) >= this->still_end_time) { ++ lprintf("pause end\n"); ++ this->still_end_time = 0; ++ bd_read_skip_still(this->bdh); ++ stream_reset(this); ++ return; ++ } ++ } ++ ++ else if (seconds) { ++ if (seconds > 300) { ++ seconds = 300; ++ } ++ ++ lprintf("still image, pause for %d seconds\n", seconds); ++ this->still_end_time = time(NULL) + seconds; ++ } ++ ++ xine_usec_sleep(40*1000); ++} ++ ++static void update_spu_channel(bluray_input_plugin_t *this, int channel) ++{ ++ if (this->stream->video_fifo) { ++ buf_element_t *buf = this->stream->video_fifo->buffer_pool_alloc(this->stream->video_fifo); ++ buf->type = BUF_CONTROL_SPU_CHANNEL; ++ buf->decoder_info[0] = channel; ++ buf->decoder_info[1] = channel; ++ buf->decoder_info[2] = channel; ++ ++ this->stream->video_fifo->put(this->stream->video_fifo, buf); ++ } ++} ++ ++static void update_audio_channel(bluray_input_plugin_t *this, int channel) ++{ ++ if (this->stream->audio_fifo) { ++ buf_element_t *buf = this->stream->audio_fifo->buffer_pool_alloc(this->stream->audio_fifo); ++ buf->type = BUF_CONTROL_AUDIO_CHANNEL; ++ buf->decoder_info[0] = channel; ++ ++ this->stream->audio_fifo->put(this->stream->audio_fifo, buf); ++ } ++} ++ ++static void handle_libbluray_event(bluray_input_plugin_t *this, BD_EVENT ev) ++{ ++ switch ((bd_event_e)ev.event) { ++ ++ case BD_EVENT_NONE: ++ break; ++ ++ case BD_EVENT_ERROR: ++ lprintf("BD_EVENT_ERROR\n"); ++ _x_message (this->stream, XINE_MSG_GENERAL_WARNING, ++ "Error playing BluRay disc", NULL); ++ this->error = 1; ++ return; ++ ++ case BD_EVENT_READ_ERROR: ++ LOGMSG("BD_EVENT_READ_ERROR\n"); ++ return; ++ ++ case BD_EVENT_ENCRYPTED: ++ lprintf("BD_EVENT_ENCRYPTED\n"); ++ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, ++ "Media stream scrambled/encrypted", NULL); ++ this->error = 1; ++ return; ++ ++ /* sound effects */ ++#if BLURAY_VERSION >= 202 ++ case BD_EVENT_SOUND_EFFECT: ++ lprintf("BD_EVENT_SOUND_EFFECT %d\n", ev.param); ++ break; ++#endif ++ ++ /* playback control */ ++ ++ case BD_EVENT_SEEK: ++ lprintf("BD_EVENT_SEEK\n"); ++ this->still_end_time = 0; ++ stream_reset(this); ++ break; ++ ++ case BD_EVENT_STILL_TIME: ++ wait_secs(this, ev.param); ++ break; ++ ++ case BD_EVENT_STILL: ++ lprintf("BD_EVENT_STILL %d\n", ev.param); ++ int paused = _x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE; ++ if (paused != ev.param) { ++ _x_set_fine_speed(this->stream, ev.param ? XINE_SPEED_PAUSE : XINE_SPEED_NORMAL); ++ } ++ break; ++ ++ /* playback position */ ++ ++ case BD_EVENT_ANGLE: ++ lprintf("BD_EVENT_ANGLE_NUMBER %d\n", ev.param); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, ev.param); ++ break; ++ ++ case BD_EVENT_END_OF_TITLE: ++ lprintf("BD_EVENT_END_OF_TITLE\n"); ++ stream_flush(this); ++ this->end_of_title = 1; ++ break; ++ ++ case BD_EVENT_TITLE: ++ if (this->nav_mode) { ++ lprintf("BD_EVENT_TITLE %d\n", ev.param); ++ this->current_title = ev.param; ++ } ++ break; ++ ++ case BD_EVENT_PLAYLIST: ++ lprintf("BD_EVENT_PLAYLIST %d\n", ev.param); ++ this->current_title_idx = bd_get_current_title(this->bdh); ++ this->current_clip = 0; ++ update_title_info(this, ev.param); ++ stream_reset(this); ++ this->end_of_title = 0; ++ break; ++ ++ case BD_EVENT_PLAYITEM: ++ lprintf("BD_EVENT_PLAYITEM %d\n", ev.param); ++ this->current_clip = ev.param; ++ this->still_end_time = 0; ++ break; ++ ++ case BD_EVENT_CHAPTER: ++ lprintf("BD_EVENT_CHAPTER %d\n", ev.param); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, ev.param); ++ break; ++ ++ /* stream selection */ ++ ++ case BD_EVENT_AUDIO_STREAM: ++ lprintf("BD_EVENT_AUDIO_STREAM %d\n", ev.param); ++ if (ev.param < 32) { ++ update_audio_channel(this, ev.param - 1); ++ } else { ++ update_audio_channel(this, 0); ++ } ++ break; ++ ++ case BD_EVENT_PG_TEXTST: ++ lprintf("BD_EVENT_PG_TEXTST %s\n", ev.param ? "ON" : "OFF"); ++ this->pg_enable = !!ev.param; ++ update_spu_channel(this, this->pg_enable ? this->pg_stream : -1); ++ break; ++ ++ case BD_EVENT_PG_TEXTST_STREAM: ++ lprintf("BD_EVENT_PG_TEXTST_STREAM %d\n", ev.param); ++ if (ev.param < 64) { ++ this->pg_stream = ev.param - 1; ++ } else { ++ this->pg_stream = -1; ++ } ++ if (this->pg_enable) { ++ update_spu_channel(this, this->pg_stream); ++ } ++ break; ++ ++ default: ++ lprintf("unhandled libbluray event %d [param %d]\n", ev.event, ev.param); ++ break; ++ } ++} ++ ++static void handle_libbluray_events(bluray_input_plugin_t *this) ++{ ++ BD_EVENT ev; ++ while (bd_get_event(this->bdh, &ev)) { ++ handle_libbluray_event(this, ev); ++ if (this->error || ev.event == BD_EVENT_NONE || ev.event == BD_EVENT_ERROR) ++ break; ++ } ++} ++ ++/* ++ * xine event handling ++ */ ++ ++static int open_title (bluray_input_plugin_t *this, int title_idx) ++{ ++ if (bd_select_title(this->bdh, title_idx) <= 0) { ++ LOGMSG("bd_select_title(%d) failed\n", title_idx); ++ return 0; ++ } ++ ++ this->current_title_idx = title_idx; ++ ++ update_title_info(this, -1); ++ ++ return 1; ++} ++ ++static void send_mouse_enter_leave_event(bluray_input_plugin_t *this, int direction) ++{ ++ if (direction != this->mouse_inside_button) { ++ xine_event_t event; ++ xine_spu_button_t spu_event; ++ ++ spu_event.direction = direction; ++ spu_event.button = 1; ++ ++ event.type = XINE_EVENT_SPU_BUTTON; ++ event.stream = this->stream; ++ event.data = &spu_event; ++ event.data_length = sizeof(spu_event); ++ xine_event_send(this->stream, &event); ++ ++ this->mouse_inside_button = direction; ++ } ++} ++ ++static void handle_events(bluray_input_plugin_t *this) ++{ ++ xine_event_t *event; ++ ++ if (!this->event_queue) ++ return; ++ ++ while (NULL != (event = xine_event_get(this->event_queue))) { ++ ++ if (!this->bdh || !this->title_info) { ++ xine_event_free(event); ++ return; ++ } ++ ++ int64_t pts = xine_get_current_vpts(this->stream) - ++ this->stream->metronom->get_option(this->stream->metronom, METRONOM_VPTS_OFFSET); ++ ++ if (this->menu_open) { ++ switch (event->type) { ++ case XINE_EVENT_INPUT_LEFT: bd_user_input(this->bdh, pts, BD_VK_LEFT); break; ++ case XINE_EVENT_INPUT_RIGHT: bd_user_input(this->bdh, pts, BD_VK_RIGHT); break; ++ } ++ } else { ++ switch (event->type) { ++ ++ case XINE_EVENT_INPUT_LEFT: ++ lprintf("XINE_EVENT_INPUT_LEFT: previous title\n"); ++ if (!this->nav_mode) { ++ open_title(this, MAX(0, this->current_title_idx - 1)); ++ } else { ++ bd_play_title(this->bdh, MAX(1, this->current_title - 1)); ++ } ++ stream_reset(this); ++ break; ++ ++ case XINE_EVENT_INPUT_RIGHT: ++ lprintf("XINE_EVENT_INPUT_RIGHT: next title\n"); ++ if (!this->nav_mode) { ++ open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1)); ++ } else { ++ bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1)); ++ } ++ stream_reset(this); ++ break; ++ } ++ } ++ ++ switch (event->type) { ++ ++ case XINE_EVENT_INPUT_MOUSE_BUTTON: { ++ xine_input_data_t *input = event->data; ++ lprintf("mouse click: button %d at (%d,%d)\n", input->button, input->x, input->y); ++ if (input->button == 1) { ++ bd_mouse_select(this->bdh, pts, input->x, input->y); ++ bd_user_input(this->bdh, pts, BD_VK_MOUSE_ACTIVATE); ++ send_mouse_enter_leave_event(this, 0); ++ } ++ break; ++ } ++ ++ case XINE_EVENT_INPUT_MOUSE_MOVE: { ++ xine_input_data_t *input = event->data; ++ if (bd_mouse_select(this->bdh, pts, input->x, input->y) > 0) { ++ send_mouse_enter_leave_event(this, 1); ++ } else { ++ send_mouse_enter_leave_event(this, 0); ++ } ++ break; ++ } ++ ++ case XINE_EVENT_INPUT_MENU1: ++ if (!this->disc_info->top_menu_supported) { ++ _x_message (this->stream, XINE_MSG_GENERAL_WARNING, ++ "Can't open Top Menu", ++ "Top Menu title not supported", NULL); ++ } ++ bd_menu_call(this->bdh, pts); ++ break; ++ ++ case XINE_EVENT_INPUT_MENU2: bd_user_input(this->bdh, pts, BD_VK_POPUP); break; ++ case XINE_EVENT_INPUT_UP: bd_user_input(this->bdh, pts, BD_VK_UP); break; ++ case XINE_EVENT_INPUT_DOWN: bd_user_input(this->bdh, pts, BD_VK_DOWN); break; ++ case XINE_EVENT_INPUT_SELECT: bd_user_input(this->bdh, pts, BD_VK_ENTER); break; ++ case XINE_EVENT_INPUT_NUMBER_0: bd_user_input(this->bdh, pts, BD_VK_0); break; ++ case XINE_EVENT_INPUT_NUMBER_1: bd_user_input(this->bdh, pts, BD_VK_1); break; ++ case XINE_EVENT_INPUT_NUMBER_2: bd_user_input(this->bdh, pts, BD_VK_2); break; ++ case XINE_EVENT_INPUT_NUMBER_3: bd_user_input(this->bdh, pts, BD_VK_3); break; ++ case XINE_EVENT_INPUT_NUMBER_4: bd_user_input(this->bdh, pts, BD_VK_4); break; ++ case XINE_EVENT_INPUT_NUMBER_5: bd_user_input(this->bdh, pts, BD_VK_5); break; ++ case XINE_EVENT_INPUT_NUMBER_6: bd_user_input(this->bdh, pts, BD_VK_6); break; ++ case XINE_EVENT_INPUT_NUMBER_7: bd_user_input(this->bdh, pts, BD_VK_7); break; ++ case XINE_EVENT_INPUT_NUMBER_8: bd_user_input(this->bdh, pts, BD_VK_8); break; ++ case XINE_EVENT_INPUT_NUMBER_9: bd_user_input(this->bdh, pts, BD_VK_9); break; ++ ++ case XINE_EVENT_INPUT_NEXT: { ++ cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config, ++ "media.bluray.skip_behaviour"); ++ switch (entry->num_value) { ++ case 0: /* skip by chapter */ ++ bd_seek_chapter(this->bdh, bd_get_current_chapter(this->bdh) + 1); ++ update_stream_info(this); ++ break; ++ case 1: /* skip by title */ ++ if (!this->nav_mode) { ++ open_title(this, MIN(this->num_title_idx - 1, this->current_title_idx + 1)); ++ } else { ++ bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1)); ++ } ++ break; ++ } ++ stream_reset(this); ++ break; ++ } ++ ++ case XINE_EVENT_INPUT_PREVIOUS: { ++ cfg_entry_t* entry = this->class->xine->config->lookup_entry(this->class->xine->config, ++ "media.bluray.skip_behaviour"); ++ switch (entry->num_value) { ++ case 0: /* skip by chapter */ ++ bd_seek_chapter(this->bdh, MAX(0, ((int)bd_get_current_chapter(this->bdh)) - 1)); ++ update_stream_info(this); ++ break; ++ case 1: /* skip by title */ ++ if (!this->nav_mode) { ++ open_title(this, MAX(0, this->current_title_idx - 1)); ++ } else { ++ bd_play_title(this->bdh, MAX(1, this->current_title - 1)); ++ } ++ break; ++ } ++ stream_reset(this); ++ break; ++ } ++ ++ case XINE_EVENT_INPUT_ANGLE_NEXT: { ++ unsigned curr_angle = bd_get_current_angle(this->bdh); ++ unsigned angle = MIN(8, curr_angle + 1); ++ lprintf("XINE_EVENT_INPUT_ANGLE_NEXT: set angle %d --> %d\n", curr_angle, angle); ++ bd_seamless_angle_change(this->bdh, angle); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); ++ break; ++ } ++ ++ case XINE_EVENT_INPUT_ANGLE_PREVIOUS: { ++ unsigned curr_angle = bd_get_current_angle(this->bdh); ++ unsigned angle = curr_angle ? curr_angle - 1 : 0; ++ lprintf("XINE_EVENT_INPUT_ANGLE_PREVIOUS: set angle %d --> %d\n", curr_angle, angle); ++ bd_seamless_angle_change(this->bdh, angle); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_ANGLE_NUMBER, bd_get_current_angle(this->bdh)); ++ break; ++ } ++ } ++ ++ xine_event_free(event); ++ } ++} ++ ++/* ++ * xine plugin interface ++ */ ++ ++static uint32_t bluray_plugin_get_capabilities (input_plugin_t *this_gen) ++{ ++ return INPUT_CAP_SEEKABLE | ++ INPUT_CAP_BLOCK | ++ INPUT_CAP_AUDIOLANG | ++ INPUT_CAP_SPULANG | ++ INPUT_CAP_CHAPTERS; ++} ++ ++#define CHECK_READ_INTERRUPT \ ++ do { \ ++ if (this->demux_action_req) { \ ++ this->demux_action_req = 0; \ ++ errno = EAGAIN; \ ++ return -1; \ ++ } \ ++ if (_x_action_pending(this->stream)) { \ ++ errno = EINTR; \ ++ return -1; \ ++ } \ ++ } while (0) ++ ++static off_t bluray_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ off_t result; ++ ++ if (!this || !this->bdh || len < 0 || this->error) ++ return -1; ++ ++ handle_events(this); ++ CHECK_READ_INTERRUPT; ++ ++ if (this->nav_mode) { ++ do { ++ BD_EVENT ev; ++ result = bd_read_ext (this->bdh, (unsigned char *)buf, len, &ev); ++ handle_libbluray_event(this, ev); ++ CHECK_READ_INTERRUPT; ++ ++ if (result == 0) { ++ handle_events(this); ++ CHECK_READ_INTERRUPT; ++#if 0 ++ if (ev.event == BD_EVENT_NONE) { ++ if (_x_action_pending(this->stream)) { ++ break; ++ } ++ } ++#endif ++ } ++ } while (!this->error && result == 0); ++ ++ } else { ++ result = bd_read (this->bdh, (unsigned char *)buf, len); ++ handle_libbluray_events(this); ++ } ++ ++ if (result < 0) { ++ LOGMSG("bd_read() failed: %s (%d of %d)\n", strerror(errno), (int)result, (int)len); ++ } ++ ++ if (result > 0) { ++ this->stream_flushed = 0; ++ } ++ ++ return result; ++} ++ ++static buf_element_t *bluray_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) ++{ ++ buf_element_t *buf = fifo->buffer_pool_alloc (fifo); ++ ++ if (todo > (off_t)buf->max_size) ++ todo = buf->max_size; ++ ++ if (todo > ALIGNED_UNIT_SIZE) ++ todo = ALIGNED_UNIT_SIZE; ++ ++ if (todo > 0) { ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ buf->size = bluray_plugin_read(this_gen, (char*)buf->mem, todo); ++ buf->type = BUF_DEMUX_BLOCK; ++ ++ if (buf->size > 0) { ++ buf->extra_info->total_time = this->title_info->duration / 90000; ++ return buf; ++ } ++ } ++ ++ buf->free_buffer (buf); ++ return NULL; ++} ++ ++static off_t bluray_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ if (!this || !this->bdh) ++ return -1; ++ if (this->still_end_time) ++ return offset; ++ ++ /* convert relative seeks to absolute */ ++ ++ if (origin == SEEK_CUR) { ++ offset = bd_tell(this->bdh) + offset; ++ } ++ else if (origin == SEEK_END) { ++ if (offset < (off_t)bd_get_title_size(this->bdh)) ++ offset = bd_get_title_size(this->bdh) - offset; ++ else ++ offset = 0; ++ } ++ ++ lprintf("bluray_plugin_seek() seeking to %lld\n", (long long)offset); ++ ++ return bd_seek (this->bdh, offset); ++} ++ ++static off_t bluray_plugin_seek_time (input_plugin_t *this_gen, int time_offset, int origin) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ if (!this || !this->bdh) ++ return -1; ++ ++ if (this->still_end_time) ++ return bd_tell(this->bdh); ++ ++ /* convert relative seeks to absolute */ ++ ++ if (origin == SEEK_CUR) { ++ time_offset += this_gen->get_current_time(this_gen); ++ } ++ else if (origin == SEEK_END) { ++ ++ pthread_mutex_lock(&this->title_info_mutex); ++ ++ if (!this->title_info) { ++ pthread_mutex_unlock(&this->title_info_mutex); ++ return -1; ++ } ++ ++ int duration = this->title_info->duration / 90; ++ if (time_offset < duration) ++ time_offset = duration - time_offset; ++ else ++ time_offset = 0; ++ ++ pthread_mutex_unlock(&this->title_info_mutex); ++ } ++ ++ lprintf("bluray_plugin_seek_time() seeking to %d.%03ds\n", time_offset / 1000, time_offset % 1000); ++ ++ return bd_seek_time(this->bdh, time_offset * INT64_C(90)); ++} ++ ++static off_t bluray_plugin_get_current_pos (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ return this->bdh ? bd_tell(this->bdh) : 0; ++} ++ ++static int bluray_plugin_get_current_time (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ return this->bdh ? (int)(bd_tell_time(this->bdh) / UINT64_C(90)) : -1; ++} ++ ++static off_t bluray_plugin_get_length (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ return this->bdh ? (off_t)bd_get_title_size(this->bdh) : (off_t)-1; ++} ++ ++static uint32_t bluray_plugin_get_blocksize (input_plugin_t *this_gen) ++{ ++ return ALIGNED_UNIT_SIZE; ++} ++ ++static const char* bluray_plugin_get_mrl (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ return this->mrl; ++} ++ ++static int get_audio_lang (bluray_input_plugin_t *this, int *data) ++{ ++ /* ++ * audio track language: ++ * - channel number can be mpeg-ts PID (0x1100 ... 0x11ff) ++ */ ++ ++ unsigned int current_clip = this->current_clip; /* can change any time */ ++ ++ if (this->title_info && current_clip < this->title_info->clip_count) { ++ int channel = *data; ++ BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip]; ++ ++ if (channel >= 0 && channel < clip->audio_stream_count) { ++ memcpy(data, clip->audio_streams[channel].lang, 4); ++ return INPUT_OPTIONAL_SUCCESS; ++ } ++ ++ /* search by pid */ ++ int i; ++ for (i = 0; i < clip->audio_stream_count; i++) { ++ if (channel == clip->audio_streams[i].pid) { ++ memcpy(data, clip->audio_streams[i].lang, 4); ++ return INPUT_OPTIONAL_SUCCESS; ++ } ++ } ++ } ++ ++ return INPUT_OPTIONAL_UNSUPPORTED; ++} ++ ++static int get_spu_lang (bluray_input_plugin_t *this, int *data) ++{ ++ /* ++ * SPU track language: ++ * - channel number can be mpeg-ts PID (0x1200 ... 0x12ff) ++ */ ++ ++ unsigned int current_clip = this->current_clip; /* can change any time */ ++ ++ if (this->title_info && current_clip < this->title_info->clip_count) { ++ int channel = *data; ++ BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip]; ++ ++ if (channel >= 0 && channel < clip->pg_stream_count) { ++ memcpy(data, clip->pg_streams[channel].lang, 4); ++ return INPUT_OPTIONAL_SUCCESS; ++ } ++ ++ /* search by pid */ ++ int i; ++ for (i = 0; i < clip->pg_stream_count; i++) { ++ if (channel == clip->pg_streams[i].pid) { ++ memcpy(data, clip->pg_streams[i].lang, 4); ++ return INPUT_OPTIONAL_SUCCESS; ++ } ++ } ++ } ++ ++ return INPUT_OPTIONAL_UNSUPPORTED; ++} ++ ++static int get_optional_data_impl (bluray_input_plugin_t *this, void *data, int data_type) ++{ ++ switch (data_type) { ++ ++ case INPUT_OPTIONAL_DATA_DEMUXER: ++ if (data) ++ *(const char **)data = "mpeg-ts"; ++ return INPUT_OPTIONAL_SUCCESS; ++ ++ case INPUT_OPTIONAL_DATA_AUDIOLANG: ++ return get_audio_lang(this, data); ++ ++ case INPUT_OPTIONAL_DATA_SPULANG: ++ return get_spu_lang(this, data); ++ ++ default: ++ return INPUT_OPTIONAL_UNSUPPORTED; ++ } ++ ++ return INPUT_OPTIONAL_UNSUPPORTED; ++} ++ ++static int bluray_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ int r = INPUT_OPTIONAL_UNSUPPORTED; ++ ++ if (this && this->stream && data) { ++ pthread_mutex_lock(&this->title_info_mutex); ++ r = get_optional_data_impl(this, data, data_type); ++ pthread_mutex_unlock(&this->title_info_mutex); ++ } ++ ++ return r; ++} ++ ++static void bluray_plugin_dispose (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ ++ if (this->bdh) ++ bd_register_overlay_proc(this->bdh, NULL, NULL); ++ ++ close_overlay(this, -1); ++ ++ if (this->event_queue) ++ xine_event_dispose_queue(this->event_queue); ++ ++ pthread_mutex_lock(&this->title_info_mutex); ++ if (this->title_info) ++ bd_free_title_info(this->title_info); ++ this->title_info = NULL; ++ pthread_mutex_unlock(&this->title_info_mutex); ++ ++ pthread_mutex_destroy(&this->title_info_mutex); ++ ++ if (this->bdh) ++ bd_close(this->bdh); ++ ++ free (this->mrl); ++ free (this->disc_root); ++ free (this->disc_name); ++ ++ free (this); ++} ++ ++static int parse_mrl(const char *mrl_in, char **path, int *title, int *chapter) ++{ ++ int skip = 0; ++ ++ if (!strncasecmp(mrl_in, "bluray:", 7)) ++ skip = 7; ++ else if (!strncasecmp(mrl_in, "bd:", 3)) ++ skip = 3; ++ else ++ return -1; ++ ++ char *mrl = strdup(mrl_in + skip); ++ ++ /* title[.chapter] given ? parse and drop it */ ++ if (mrl[strlen(mrl)-1] != '/') { ++ char *end = strrchr(mrl, '/'); ++ if (end && end[1]) { ++ if (sscanf(end, "/%d.%d", title, chapter) < 1) ++ *title = -1; ++ else ++ *end = 0; ++ } ++ } ++ lprintf(" -> title %d, chapter %d, mrl \'%s\'\n", *title, *chapter, mrl); ++ ++ if ((mrl[0] == 0) || !strcmp(mrl, "/") || !strcmp(mrl, "//") || !strcmp(mrl, "///")) { ++ ++ /* default device */ ++ *path = NULL; ++ ++ } else if (*mrl == '/') { ++ ++ /* strip extra slashes */ ++ char *start = mrl; ++ while (start[0] == '/' && start[1] == '/') ++ start++; ++ ++ *path = strdup(start); ++ ++ _x_mrl_unescape(*path); ++ ++ lprintf("non-defaut mount point \'%s\'\n", *path); ++ ++ } else { ++ lprintf("invalid mrl \'%s\'\n", mrl_in); ++ free(mrl); ++ return 0; ++ } ++ ++ free(mrl); ++ ++ return 1; ++} ++ ++static int get_disc_info(bluray_input_plugin_t *this) ++{ ++ const BLURAY_DISC_INFO *disc_info; ++ ++ disc_info = bd_get_disc_info(this->bdh); ++ ++ if (!disc_info) { ++ LOGMSG("bd_get_disc_info() failed\n"); ++ return -1; ++ } ++ ++ if (!disc_info->bluray_detected) { ++ LOGMSG("bd_get_disc_info(): BluRay not detected\n"); ++ this->nav_mode = 0; ++ return 0; ++ } ++ ++ if (disc_info->aacs_detected && !disc_info->aacs_handled) { ++ if (!disc_info->libaacs_detected) ++ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, ++ "Media stream scrambled/encrypted with AACS", ++ "libaacs not installed", NULL); ++ else ++ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, ++ "Media stream scrambled/encrypted with AACS", NULL); ++ return -1; ++ } ++ ++ if (disc_info->bdplus_detected && !disc_info->bdplus_handled) { ++ if (!disc_info->libbdplus_detected) ++ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, ++ "Media scrambled/encrypted with BD+", ++ "libbdplus not installed.", NULL); ++ else ++ _x_message (this->stream, XINE_MSG_ENCRYPTED_SOURCE, ++ "Media stream scrambled/encrypted with BD+", NULL); ++ return -1; ++ } ++ ++ if (this->nav_mode && !disc_info->first_play_supported) { ++ _x_message (this->stream, XINE_MSG_GENERAL_WARNING, ++ "Can't play disc using menus", ++ "First Play title not supported", NULL); ++ this->nav_mode = 0; ++ } ++ ++ if (this->nav_mode && disc_info->num_unsupported_titles > 0) { ++ _x_message (this->stream, XINE_MSG_GENERAL_WARNING, ++ "Unsupported titles found", ++ "Some titles can't be played in navigation mode", NULL); ++ } ++ ++ this->num_titles = disc_info->num_hdmv_titles + disc_info->num_bdj_titles; ++ this->disc_info = disc_info; ++ ++ return 1; ++} ++ ++static char *get_disc_name(const char *path) ++{ ++ const char *name_start; ++ char *file_name = NULL; ++ int len; ++ ++ name_start = path + strlen(path) - 1; ++ /* skip trailing '/' */ ++ while (name_start > path && name_start[0] == '/') ++ name_start--; ++ /* find prev '/' */ ++ while (name_start > path && name_start[-1] != '/') ++ name_start--; ++ ++ file_name = strdup(name_start); ++ len = strlen(file_name); ++ ++ /* trim trailing '/' */ ++ while (len > 0 && file_name[len - 1] == '/') ++ file_name[--len] = 0; ++ ++ /* trim trailing ".iso" */ ++ if (len > 3 && !strcasecmp(file_name + len - 4, ".iso")) ++ file_name[len - 4] = 0; ++ ++ /* '_' --> ' ' */ ++ for (len = 0; file_name[len]; ++len) ++ if (file_name[len] == '_') ++ file_name[len] = ' '; ++ ++ lprintf("disc name: %s\n", file_name); ++ return file_name; ++} ++ ++static int is_iso_image(const char *mrl) ++{ ++ if (mrl) { ++ const char *pos = strrchr(mrl, '.'); ++ return pos && !strcasecmp(pos + 1, "iso"); ++ } ++ return 0; ++} ++ ++static int bluray_plugin_open (input_plugin_t *this_gen) ++{ ++ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; ++ int title = -1; ++ int chapter = 0; ++ ++ lprintf("bluray_plugin_open '%s'\n",this->mrl); ++ ++ /* validate and parse mrl */ ++ if (!parse_mrl(this->mrl, &this->disc_root, &title, &chapter)) ++ return -1; ++ ++ if (!strncasecmp(this->mrl, "bd:", 3)) ++ this->nav_mode = 1; ++ ++ if (!this->disc_root) ++ this->disc_root = strdup(this->class->mountpoint); ++ ++ /* mount .iso image */ ++ if (is_iso_image(this->disc_root)) { ++ _x_message (this->stream, XINE_MSG_GENERAL_WARNING, ++ "Can't play BluRay .iso image", ++ "", NULL); ++ return -1; ++ } ++ ++ /* open libbluray */ ++ ++ if (! (this->bdh = bd_open (this->disc_root, NULL))) { ++ LOGMSG("bd_open(\'%s\') failed: %s\n", this->disc_root, strerror(errno)); ++ return -1; ++ } ++ lprintf("bd_open(\'%s\') OK\n", this->disc_root); ++ ++ if (get_disc_info(this) < 0) { ++ return -1; ++ } ++ ++ /* load title list */ ++ ++ this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH); ++ LOGMSG("%d titles\n", this->num_title_idx); ++ ++ if (this->num_title_idx < 1) ++ return -1; ++ ++ /* select title */ ++ ++ /* if title was not in mrl, guess the main title */ ++ if (title < 0) { ++ uint64_t duration = 0; ++ int i, playlist = 99999; ++ for (i = 0; i < this->num_title_idx; i++) { ++ BLURAY_TITLE_INFO *info = bd_get_title_info(this->bdh, i, 0); ++ if (info->duration > duration) { ++ title = i; ++ duration = info->duration; ++ playlist = info->playlist; ++ } ++ bd_free_title_info(info); ++ } ++ lprintf("main title: %d (%05d.mpls)\n", title, playlist); ++ } ++ ++ /* update player settings */ ++ ++ bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_REGION_CODE, this->class->region); ++ bd_set_player_setting (this->bdh, BLURAY_PLAYER_SETTING_PARENTAL, this->class->parental); ++ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_AUDIO_LANG, this->class->language); ++ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_PG_LANG, this->class->language); ++ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_MENU_LANG, this->class->language); ++ bd_set_player_setting_str(this->bdh, BLURAY_PLAYER_SETTING_COUNTRY_CODE, this->class->country); ++ ++ /* init event queue */ ++ bd_get_event(this->bdh, NULL); ++ ++ /* get disc name */ ++ ++ this->meta_dl = bd_get_meta(this->bdh); ++ ++ if (this->meta_dl && this->meta_dl->di_name && strlen(this->meta_dl->di_name) > 1) { ++ this->disc_name = strdup(this->meta_dl->di_name); ++ } ++ else if (strcmp(this->disc_root, this->class->mountpoint)) { ++ this->disc_name = get_disc_name(this->disc_root); ++ } ++ ++ /* register overlay (graphics) handler */ ++ ++ bd_register_overlay_proc(this->bdh, this, overlay_proc); ++ ++ /* open */ ++ this->current_title = -1; ++ this->current_title_idx = -1; ++ ++ if (this->nav_mode) { ++ if (bd_play(this->bdh) <= 0) { ++ LOGMSG("bd_play() failed\n"); ++ return -1; ++ } ++ ++ } else { ++ if (open_title(this, title) <= 0 && ++ open_title(this, 0) <= 0) ++ return -1; ++ } ++ ++ /* jump to chapter */ ++ ++ if (chapter > 0) { ++ chapter = MAX(0, MIN((int)this->title_info->chapter_count, chapter) - 1); ++ bd_seek_chapter(this->bdh, chapter); ++ _x_stream_info_set(this->stream, XINE_STREAM_INFO_DVD_CHAPTER_NUMBER, chapter + 1); ++ } ++ ++ return 1; ++} ++ ++static input_plugin_t *bluray_class_get_instance (input_class_t *cls_gen, xine_stream_t *stream, ++ const char *mrl) ++{ ++ bluray_input_plugin_t *this; ++ ++ lprintf("bluray_class_get_instance\n"); ++ ++ if (strncasecmp(mrl, "bluray:", 7) && strncasecmp(mrl, "bd:", 3)) ++ return NULL; ++ ++ this = (bluray_input_plugin_t *) calloc(1, sizeof (bluray_input_plugin_t)); ++ ++ this->stream = stream; ++ this->class = (bluray_input_class_t*)cls_gen; ++ this->mrl = strdup(mrl); ++ ++ this->input_plugin.open = bluray_plugin_open; ++ this->input_plugin.get_capabilities = bluray_plugin_get_capabilities; ++ this->input_plugin.read = bluray_plugin_read; ++ this->input_plugin.read_block = bluray_plugin_read_block; ++ this->input_plugin.seek = bluray_plugin_seek; ++ this->input_plugin.seek_time = bluray_plugin_seek_time; ++ this->input_plugin.get_current_pos = bluray_plugin_get_current_pos; ++ this->input_plugin.get_current_time = bluray_plugin_get_current_time; ++ this->input_plugin.get_length = bluray_plugin_get_length; ++ this->input_plugin.get_blocksize = bluray_plugin_get_blocksize; ++ this->input_plugin.get_mrl = bluray_plugin_get_mrl; ++ this->input_plugin.get_optional_data = bluray_plugin_get_optional_data; ++ this->input_plugin.dispose = bluray_plugin_dispose; ++ this->input_plugin.input_class = cls_gen; ++ ++ this->event_queue = xine_event_new_queue (this->stream); ++ ++ pthread_mutex_init(&this->title_info_mutex, NULL); ++ ++ this->pg_stream = -1; ++ ++ return &this->input_plugin; ++} ++ ++/* ++ * plugin class ++ */ ++ ++static void mountpoint_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->mountpoint = cfg->str_value; ++} ++ ++static void device_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->device = cfg->str_value; ++} ++ ++static void language_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->language = cfg->str_value; ++} ++ ++static void country_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->country = cfg->str_value; ++} ++ ++static void region_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->region = cfg->num_value; ++} ++ ++static void parental_change_cb(void *data, xine_cfg_entry_t *cfg) ++{ ++ bluray_input_class_t *class = (bluray_input_class_t *) data; ++ ++ class->parental = cfg->num_value; ++} ++ ++static void free_xine_playlist(bluray_input_class_t *this) ++{ ++ if (this->xine_playlist) { ++ int i; ++ for (i = 0; i < this->xine_playlist_size; i++) { ++ MRL_ZERO(this->xine_playlist[i]); ++ free(this->xine_playlist[i]); ++ } ++ free(this->xine_playlist); ++ this->xine_playlist = NULL; ++ } ++ ++ this->xine_playlist_size = 0; ++} ++ ++static const char *bluray_class_get_description (input_class_t *this_gen) ++{ ++ return _("BluRay input plugin"); ++} ++ ++static const char *bluray_class_get_identifier (input_class_t *this_gen) ++{ ++ return "bluray"; ++} ++ ++static char **bluray_class_get_autoplay_list (input_class_t *this_gen, int *num_files) ++{ ++ static char *autoplay_list[] = { "bluray:/", NULL }; ++ ++ *num_files = 1; ++ ++ return autoplay_list; ++} ++ ++static xine_mrl_t **bluray_class_get_dir(input_class_t *this_gen, const char *filename, int *nFiles) ++{ ++ bluray_input_class_t *this = (bluray_input_class_t*) this_gen; ++ char *path = NULL; ++ int title = -1, chapter = -1, i, num_pl; ++ BLURAY *bdh; ++ ++ lprintf("bluray_class_get_dir(%s)\n", filename); ++ ++ free_xine_playlist(this); ++ ++ if (filename) ++ parse_mrl(filename, &path, &title, &chapter); ++ ++ bdh = bd_open(path ? path : this->mountpoint, NULL); ++ ++ if (bdh) { ++ num_pl = bd_get_titles(bdh, TITLES_RELEVANT, MIN_TITLE_LENGTH); ++ ++ if (num_pl > 0) { ++ ++ this->xine_playlist_size = num_pl; ++ this->xine_playlist = calloc(this->xine_playlist_size + 1, sizeof(xine_mrl_t*)); ++ ++ for (i = 0; i < num_pl; i++) { ++ this->xine_playlist[i] = calloc(1, sizeof(xine_mrl_t)); ++ ++ this->xine_playlist[i]->origin = _x_asprintf("bluray:/%s", path ? path : ""); ++ this->xine_playlist[i]->mrl = _x_asprintf("bluray:/%s/%d", path ? path : "", i); ++ this->xine_playlist[i]->type = mrl_dvd; ++ } ++ } ++ ++ bd_close(bdh); ++ } ++ ++ free(path); ++ ++ if (nFiles) ++ *nFiles = this->xine_playlist_size; ++ ++ return this->xine_playlist; ++} ++ ++static int bluray_class_eject_media (input_class_t *this_gen) ++{ ++ bluray_input_class_t *this = (bluray_input_class_t*) this_gen; ++ ++ return media_eject_media (this->xine, this->device); ++} ++ ++static void bluray_class_dispose (input_class_t *this_gen) ++{ ++ bluray_input_class_t *this = (bluray_input_class_t *) this_gen; ++ config_values_t *config = this->xine->config; ++ ++ free_xine_playlist(this); ++ ++ config->unregister_callback(config, "media.bluray.mountpoint"); ++ config->unregister_callback(config, "media.bluray.device"); ++ config->unregister_callback(config, "media.bluray.region"); ++ config->unregister_callback(config, "media.bluray.language"); ++ config->unregister_callback(config, "media.bluray.country"); ++ config->unregister_callback(config, "media.bluray.parental"); ++ ++ free (this); ++} ++ ++static void *bluray_init_plugin (xine_t *xine, void *data) ++{ ++ static const char * const skip_modes[] = {"skip chapter", "skip title", NULL}; ++ ++ config_values_t *config = xine->config; ++ bluray_input_class_t *this = (bluray_input_class_t *) calloc(1, sizeof (bluray_input_class_t)); ++ ++ this->xine = xine; ++ ++ this->input_class.get_instance = bluray_class_get_instance; ++ this->input_class.get_identifier = bluray_class_get_identifier; ++ this->input_class.get_description = bluray_class_get_description; ++ this->input_class.get_dir = bluray_class_get_dir; ++ this->input_class.get_autoplay_list = bluray_class_get_autoplay_list; ++ this->input_class.dispose = bluray_class_dispose; ++ this->input_class.eject_media = bluray_class_eject_media; ++ ++ this->mountpoint = ++ config->register_filename(config, "media.bluray.mountpoint", ++ "/mnt/bluray", XINE_CONFIG_STRING_IS_DIRECTORY_NAME, ++ _("BluRay mount point"), ++ _("Default mount location for BluRay discs."), ++ 0, mountpoint_change_cb, (void *) this); ++ this->device = ++ config->register_filename(config, "media.bluray.device", ++ "/dev/dvd", XINE_CONFIG_STRING_IS_DIRECTORY_NAME, ++ _("device used for BluRay playback"), ++ _("The path to the device " ++ "which you intend to use for playing BluRy discs."), ++ 0, device_change_cb, (void *) this); ++ ++ /* Player settings */ ++ this->language = ++ config->register_string(config, "media.bluray.language", ++ "eng", ++ _("default language for BluRay playback"), ++ _("xine tries to use this language as a default for BluRay playback. " ++ "As far as the BluRay supports it, menus and audio tracks will be presented " ++ "in this language.\nThe value must be a three character" ++ "ISO639-2 language code."), ++ 0, language_change_cb, this); ++ this->country = ++ config->register_string(config, "media.bluray.country", ++ "en", ++ _("BluRay player country code"), ++ _("The value must be a two character ISO3166-1 country code."), ++ 0, country_change_cb, this); ++ this->region = ++ config->register_num(config, "media.bluray.region", ++ 7, ++ _("BluRay player region code (1=A, 2=B, 4=C)"), ++ _("This only needs to be changed if your BluRay jumps to a screen " ++ "complaining about a wrong region code. It has nothing to do with " ++ "the region code set in BluRay drives, this is purely software."), ++ 0, region_change_cb, this); ++ this->parental = ++ config->register_num(config, "media.bluray.parental", ++ 99, ++ _("parental control age limit (1-99)"), ++ _("Prevents playback of BluRay titles where parental " ++ "control age limit is higher than this limit"), ++ 0, parental_change_cb, this); ++ ++ /* */ ++ config->register_enum(config, "media.bluray.skip_behaviour", 0, ++ skip_modes, ++ _("unit for the skip action"), ++ _("You can configure the behaviour when issuing a skip command (using the skip " ++ "buttons for example)."), ++ 20, NULL, NULL); ++ ++ return this; ++} ++ ++static const char *bd_class_get_description (input_class_t *this_gen) ++{ ++ return _("BluRay input plugin (using menus)"); ++} ++ ++static const char *bd_class_get_identifier (input_class_t *this_gen) ++{ ++ return "bd"; ++} ++ ++static char **bd_class_get_autoplay_list (input_class_t *this_gen, int *num_files) ++{ ++ static char *autoplay_list[] = { "bd:/", NULL }; ++ ++ *num_files = 1; ++ ++ return autoplay_list; ++} ++ ++static void *bd_init_plugin (xine_t *xine, void *data) ++{ ++ bluray_input_class_t *this = bluray_init_plugin(xine, data); ++ ++ if (this) { ++ this->input_class.get_identifier = bd_class_get_identifier; ++ this->input_class.get_description = bd_class_get_description; ++ this->input_class.get_dir = NULL; ++ this->input_class.get_autoplay_list = bd_class_get_autoplay_list; ++ } ++ ++ return this; ++} ++ ++/* ++ * exported plugin catalog entry ++ */ ++ ++const plugin_info_t xine_plugin_info[] EXPORTED = { ++ /* type, API, "name", version, special_info, init_function */ ++ { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BLURAY", XINE_VERSION_CODE, NULL, bluray_init_plugin }, ++ { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, INPUT_PLUGIN_IFACE_VERSION, "BD", XINE_VERSION_CODE, NULL, bd_init_plugin }, ++ { PLUGIN_NONE, 0, "", 0, NULL, NULL } ++}; diff --git a/multimedia/xine-lib/pkg/PLIST b/multimedia/xine-lib/pkg/PLIST index d05fb0a842f..3fa52905020 100644 --- a/multimedia/xine-lib/pkg/PLIST +++ b/multimedia/xine-lib/pkg/PLIST @@ -1,4 +1,4 @@ -@comment $OpenBSD: PLIST,v 1.15 2012/01/05 08:52:26 ajacoutot Exp $ +@comment $OpenBSD: PLIST,v 1.16 2012/04/08 07:37:25 ajacoutot Exp $ @conflict xine-lib-arts-* @conflict xine-lib-esd-* @conflict xine-lib-jack-* @@ -64,7 +64,6 @@ lib/xine/plugins/${XINEAPI_REV}/post/xineplug_post_planar.so lib/xine/plugins/${XINEAPI_REV}/post/xineplug_post_switch.so lib/xine/plugins/${XINEAPI_REV}/post/xineplug_post_tvtime.so lib/xine/plugins/${XINEAPI_REV}/post/xineplug_post_visualizations.so -@comment lib/xine/plugins/${XINEAPI_REV}/vidix/ lib/xine/plugins/${XINEAPI_REV}/xineplug_ao_out_file.so lib/xine/plugins/${XINEAPI_REV}/xineplug_ao_out_none.so lib/xine/plugins/${XINEAPI_REV}/xineplug_ao_out_sndio.so @@ -116,6 +115,7 @@ lib/xine/plugins/${XINEAPI_REV}/xineplug_dmx_sputext.so lib/xine/plugins/${XINEAPI_REV}/xineplug_dmx_yuv4mpeg2.so lib/xine/plugins/${XINEAPI_REV}/xineplug_dmx_yuv_frames.so lib/xine/plugins/${XINEAPI_REV}/xineplug_flac.so +lib/xine/plugins/${XINEAPI_REV}/xineplug_inp_bluray.so lib/xine/plugins/${XINEAPI_REV}/xineplug_inp_cdda.so lib/xine/plugins/${XINEAPI_REV}/xineplug_inp_dvb.so lib/xine/plugins/${XINEAPI_REV}/xineplug_inp_dvd.so