From 41fbcee1f557c3ddbfefc79b2b1b4719c6442265 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 12 Aug 2012 18:40:21 +0200 Subject: Remove dvdnav support (DVD menus) When the internal mplayer MPEG demuxer was removed (commit 1fde09db), the default demuxer when using dvdnav was set to libavformat. Now it turns out that this doesn't work with libavformat. It will terminate playback right after the audio runs out (instead of looping it like the video, or whatever it's supposed to do). I'm not sure what exactly the problem is, but since 1. even mplayer-svn can't handle DVD menus directly (missing highlights), 2. DVD menus are essentially worthless, and 3. I don't directly watch DVDs, don't bother with it and remove it. For basic playback, there's still libdvdread support. Also, use pkg-config for libdvdread, and drop support for in-tree libdvdread. Remove support for in-tree libdvdcss as well. --- DOCS/man/en/mplayer.rst | 35 +- Makefile | 33 -- command.c | 79 +--- configure | 133 +----- etc/input.conf | 14 - input/input.c | 4 - input/input.h | 11 - libmpdemux/demuxer.c | 2 +- mp_core.h | 6 - mplayer.c | 241 +---------- parser-mpcmd.c | 8 +- stream/stream.c | 8 - stream/stream.h | 1 - stream/stream_dvdnav.c | 1027 ----------------------------------------------- stream/stream_dvdnav.h | 49 --- sub/sub.c | 62 --- sub/sub.h | 6 - 17 files changed, 15 insertions(+), 1704 deletions(-) delete mode 100644 stream/stream_dvdnav.c delete mode 100644 stream/stream_dvdnav.h diff --git a/DOCS/man/en/mplayer.rst b/DOCS/man/en/mplayer.rst index 3c1ffe43f1..89c125a1e0 100644 --- a/DOCS/man/en/mplayer.rst +++ b/DOCS/man/en/mplayer.rst @@ -9,7 +9,7 @@ Synopsis | **mplayer** [options] files | **mplayer** [options] {group of files and options} | **mplayer** [br]://[title][/device] [options] -| **mplayer** [dvd|dvdnav]://[title|[start\_title]-end\_title][/device] [options] +| **mplayer** dvd://[title|[start\_title]-end\_title][/device] [options] | **mplayer** \vcd://track[/device] | **mplayer** \tv://[channel][/input_id] [options] | **mplayer** radio://[channel|frequency][/capture] [options] @@ -239,30 +239,6 @@ n u Change channel list. -(The following keys are only valid if you compiled with dvdnav support: They -are used to navigate the menus.) - -keypad 8 - Select button up. - -keypad 2 - Select button down. - -keypad 4 - Select button left. - -keypad 6 - Select button right. - -keypad 5 - Return to main menu. - -keypad 7 - Return to nearest menu (the order of preference is: chapter->title->root). - -keypad ENTER - Confirm choice. - mouse control ------------- @@ -410,12 +386,6 @@ option. To end the profile, start another one or use the profile name | vf=pp=hb/vb/dr/al/fd | alang=en | -| [protocol.dvdnav] -| profile-desc="profile for dvdnav:// streams" -| profile=protocol.dvd -| mouse-movements=yes -| nocache=yes -| | [extension.flv] | profile-desc="profile for .flv files" | flip=yes @@ -680,9 +650,6 @@ Play DVD video from a directory with VOB files: Copy a DVD title to hard disk, saving to file title1.vob : ``mplayer dvd://1 --dumpstream --dumpfile=title1.vob`` -Play a DVD with dvdnav from path /dev/sr1: - ``mplayer dvdnav:////dev/sr1`` - Stream from HTTP: ``mplayer http://mplayer.hq/example.avi`` diff --git a/Makefile b/Makefile index a679e8e7ca..567f22114d 100644 --- a/Makefile +++ b/Makefile @@ -31,29 +31,8 @@ SRCS_COMMON-$(CDDA) += stream/stream_cdda.c \ SRCS_COMMON-$(CDDB) += stream/stream_cddb.c SRCS_COMMON-$(DVBIN) += stream/dvb_tune.c \ stream/stream_dvb.c -SRCS_COMMON-$(DVDNAV) += stream/stream_dvdnav.c -SRCS_COMMON-$(DVDNAV_INTERNAL) += libdvdnav/dvdnav.c \ - libdvdnav/highlight.c \ - libdvdnav/navigation.c \ - libdvdnav/read_cache.c \ - libdvdnav/remap.c \ - libdvdnav/searching.c \ - libdvdnav/settings.c \ - libdvdnav/vm/decoder.c \ - libdvdnav/vm/vm.c \ - libdvdnav/vm/vmcmd.c \ - SRCS_COMMON-$(DVDREAD) += stream/stream_dvd.c \ stream/stream_dvd_common.c -SRCS_COMMON-$(DVDREAD_INTERNAL) += libdvdread4/bitreader.c \ - libdvdread4/dvd_input.c \ - libdvdread4/dvd_reader.c \ - libdvdread4/dvd_udf.c \ - libdvdread4/ifo_print.c \ - libdvdread4/ifo_read.c \ - libdvdread4/md5.c \ - libdvdread4/nav_print.c \ - libdvdread4/nav_read.c \ SRCS_COMMON-$(FAAD) += libmpcodecs/ad_faad.c @@ -78,11 +57,6 @@ SRCS_COMMON-$(LIBDCA) += libmpcodecs/ad_libdca.c SRCS_COMMON-$(LIBDV) += libmpcodecs/ad_libdv.c \ libmpcodecs/vd_libdv.c \ libmpdemux/demux_rawdv.c -SRCS_COMMON-$(LIBDVDCSS_INTERNAL) += libdvdcss/css.c \ - libdvdcss/device.c \ - libdvdcss/error.c \ - libdvdcss/ioctl.c \ - libdvdcss/libdvdcss.c \ SRCS_COMMON-$(LIBMAD) += libmpcodecs/ad_libmad.c @@ -518,13 +492,6 @@ libmpcodecs/vf_fspp.o libmpcodecs/vf_mcdeint.o libmpcodecs/vf_spp.o: CFLAGS := - osdep/mplayer-rc.o: osdep/mplayer.exe.manifest -libdvdcss/%: CFLAGS := -Ilibdvdcss -D_GNU_SOURCE -DVERSION=\"1.2.10\" $(CFLAGS_LIBDVDCSS) $(CFLAGS) -libdvdnav/%: CFLAGS := -Ilibdvdnav -D_GNU_SOURCE -DHAVE_CONFIG_H -DVERSION=\"MPlayer-custom\" $(CFLAGS) -libdvdread4/%: CFLAGS := -Ilibdvdread4 -D_GNU_SOURCE $(CFLAGS_LIBDVDCSS_DVDREAD) $(CFLAGS) - -stream/stream_dvdnav%: CFLAGS := $(CFLAGS_LIBDVDNAV) $(CFLAGS) - - ###### installation / clean / generic rules ####### diff --git a/command.c b/command.c index 5c77480bfe..48606be43c 100644 --- a/command.c +++ b/command.c @@ -65,7 +65,6 @@ #ifdef CONFIG_DVDREAD #include "stream/stream_dvd.h" #endif -#include "stream/stream_dvdnav.h" #include "m_struct.h" #include "screenshot.h" @@ -1690,10 +1689,9 @@ static int mp_property_sub(m_option_t *prop, int action, void *arg, } } #ifdef CONFIG_DVDREAD - if (vo_spudec - && (mpctx->stream->type == STREAMTYPE_DVD - || mpctx->stream->type == STREAMTYPE_DVDNAV) - && opts->sub_id < 0 && reset_spu) { + if (vo_spudec && (mpctx->stream->type == STREAMTYPE_DVD) + && opts->sub_id < 0 && reset_spu) + { d_sub->id = -2; d_sub->sh = NULL; } @@ -2513,36 +2511,6 @@ static bool set_property_command(MPContext *mpctx, mp_cmd_t *cmd) return 1; } -#ifdef CONFIG_DVDNAV -static const struct { - const char *name; - const enum mp_command_type cmd; -} mp_dvdnav_bindings[] = { - { "up", MP_CMD_DVDNAV_UP }, - { "down", MP_CMD_DVDNAV_DOWN }, - { "left", MP_CMD_DVDNAV_LEFT }, - { "right", MP_CMD_DVDNAV_RIGHT }, - { "menu", MP_CMD_DVDNAV_MENU }, - { "select", MP_CMD_DVDNAV_SELECT }, - { "prev", MP_CMD_DVDNAV_PREVMENU }, - { "mouse", MP_CMD_DVDNAV_MOUSECLICK }, - - /* - * keep old dvdnav sub-command options for a while in order not to - * break slave-mode API too suddenly. - */ - { "1", MP_CMD_DVDNAV_UP }, - { "2", MP_CMD_DVDNAV_DOWN }, - { "3", MP_CMD_DVDNAV_LEFT }, - { "4", MP_CMD_DVDNAV_RIGHT }, - { "5", MP_CMD_DVDNAV_MENU }, - { "6", MP_CMD_DVDNAV_SELECT }, - { "7", MP_CMD_DVDNAV_PREVMENU }, - { "8", MP_CMD_DVDNAV_MOUSECLICK }, - { NULL, 0 } -}; -#endif - static const char *property_error_string(int error_value) { switch (error_value) { @@ -3392,50 +3360,9 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) pointer_x = cmd->args[0].v.i; pointer_y = cmd->args[1].v.i; rescale_input_coordinates(mpctx, pointer_x, pointer_y, &dx, &dy); -#ifdef CONFIG_DVDNAV - if (mpctx->stream->type == STREAMTYPE_DVDNAV - && dx > 0.0 && dy > 0.0) { - int button = -1; - pointer_x = (int) (dx * (double) sh_video->disp_w); - pointer_y = (int) (dy * (double) sh_video->disp_h); - mp_dvdnav_update_mouse_pos(mpctx->stream, - pointer_x, pointer_y, &button); - if (opts->osd_level > 1 && button > 0) - set_osd_msg(mpctx, OSD_MSG_TEXT, 1, osd_duration, - "Selected button number %d", button); - } -#endif break; } -#ifdef CONFIG_DVDNAV - case MP_CMD_DVDNAV: { - int button = -1; - int i; - enum mp_command_type command = 0; - if (mpctx->stream->type != STREAMTYPE_DVDNAV) - break; - - for (i = 0; mp_dvdnav_bindings[i].name; i++) - if (cmd->args[0].v.s && - !strcasecmp(cmd->args[0].v.s, - mp_dvdnav_bindings[i].name)) - command = mp_dvdnav_bindings[i].cmd; - - mp_dvdnav_handle_input(mpctx->stream, command, &button); - if (opts->osd_level > 1 && button > 0) - set_osd_msg(mpctx, OSD_MSG_TEXT, 1, osd_duration, - "Selected button number %d", button); - break; - } - - case MP_CMD_SWITCH_TITLE: - if (mpctx->stream->type == STREAMTYPE_DVDNAV) - mp_dvdnav_switch_title(mpctx->stream, cmd->args[0].v.i); - break; - -#endif - case MP_CMD_VO_CMDLINE: if (mpctx->video_out) { char *s = cmd->args[0].v.s; diff --git a/configure b/configure index ce7c4488e7..9946ca8234 100755 --- a/configure +++ b/configure @@ -325,10 +325,7 @@ Optional features: --enable-lcms2 enable LCMS2 support [autodetect] --disable-vcd disable VCD support [autodetect] --disable-bluray disable Blu-ray support [autodetect] - --disable-dvdnav disable libdvdnav [autodetect] --disable-dvdread disable libdvdread [autodetect] - --disable-dvdread-internal disable internal libdvdread [autodetect] - --disable-libdvdcss-internal disable internal libdvdcss [autodetect] --disable-cddb disable cddb [autodetect] --disable-sortsub disable subtitle sorting [enabled] --disable-enca disable ENCA charset oracle library [autodetect] @@ -425,7 +422,6 @@ Use these options if autodetection fails: --extra-libs=FLAGS extra linker flags --extra-libs-mplayer=FLAGS extra linker flags for MPlayer - --with-dvdnav-config=PATH path to dvdnav-config --with-dvdread-config=PATH path to dvdread-config This configure script is NOT autoconf-based, even though its output is similar. @@ -482,12 +478,8 @@ _ladspa=auto _libbs2b=auto _vcd=auto _bluray=auto -_dvdnav=auto -_dvdnavconfig=dvdnav-config _dvdreadconfig=dvdread-config _dvdread=auto -_dvdread_internal=auto -_libdvdcss_internal=auto _live=no _nemesi=auto _lcms2=auto @@ -579,10 +571,6 @@ for ac_option do --with-install=*) _install=$(echo $ac_option | cut -d '=' -f 2 ) ;; - - --with-dvdnav-config=*) - _dvdnavconfig=$(echo $ac_option | cut -d '=' -f 2) - ;; --with-dvdread-config=*) _dvdreadconfig=$(echo $ac_option | cut -d '=' -f 2) ;; @@ -718,12 +706,6 @@ for ac_option do --disable-bluray) _bluray=no ;; --enable-dvdread) _dvdread=yes ;; --disable-dvdread) _dvdread=no ;; - --enable-dvdread-internal) _dvdread_internal=yes ;; - --disable-dvdread-internal) _dvdread_internal=no ;; - --enable-libdvdcss-internal) _libdvdcss_internal=yes ;; - --disable-libdvdcss-internal) _libdvdcss_internal=no ;; - --enable-dvdnav) _dvdnav=yes ;; - --disable-dvdnav) _dvdnav=no ;; --enable-live) _live=yes ;; --disable-live) _live=no ;; --enable-nemesi) _nemesi=yes ;; @@ -2852,44 +2834,15 @@ else fi echores "$_bluray" + echocheck "dvdread" -if test "$_dvdread_internal" = auto && test ! -f "libdvdread4/dvd_reader.c" ; then - _dvdread_internal=no -fi -if test "$_dvdread_internal" = auto ; then - _dvdread_internal=no - _dvdread=no - if (linux || freebsd || netbsd || openbsd || dragonfly) && - (test "$_dvd" = yes || test "$_cdrom" = yes || test "$_cdio" = yes || - test "$_dvdio" = yes || test "$_bsdi_dvd" = yes) || - darwin || win32; then - _dvdread_internal=yes - _dvdread=yes - extra_cflags="-Ilibdvdread4 $extra_cflags" - fi -elif test "$_dvdread" = auto ; then +if test "$_dvdread" = auto ; then _dvdread=no - if test "$_dl" = yes; then - _dvdreadcflags=$($_dvdreadconfig --cflags 2> /dev/null) - _dvdreadlibs=$($_dvdreadconfig --libs 2> /dev/null) - if header_check dvdread/dvd_reader.h $_dvdreadcflags $_dvdreadlibs $_ld_dl ; then - _dvdread=yes - extra_cflags="$extra_cflags $_dvdreadcflags" - extra_ldflags="$extra_ldflags $_dvdreadlibs" - res_comment="external" - fi - fi + pkg_config_add 'dvdread >= 4.2.0' && _dvdread=yes fi - -if test "$_dvdread_internal" = yes; then +if test "$_dvdread" = yes ; then def_dvdread='#define CONFIG_DVDREAD 1' - inputmodules="dvdread(internal) $inputmodules" - res_comment="internal" -elif test "$_dvdread" = yes; then - def_dvdread='#define CONFIG_DVDREAD 1' - extra_ldflags="$extra_ldflags -ldvdread" - inputmodules="dvdread(external) $inputmodules" - res_comment="external" + inputmodules="dvdread $inputmodules" else def_dvdread='#undef CONFIG_DVDREAD' noinputmodules="dvdread $noinputmodules" @@ -2897,32 +2850,6 @@ fi echores "$_dvdread" -echocheck "internal libdvdcss" -if test "$_libdvdcss_internal" = auto ; then - _libdvdcss_internal=no - test "$_dvdread_internal" = yes && test -d libdvdcss && _libdvdcss_internal=yes -fi -if test "$_libdvdcss_internal" = yes ; then - if linux || netbsd || openbsd ; then - def_dvd_linux='#define HAVE_LINUX_DVD_STRUCT 1' - openbsd && def_dvd_openbsd='#define HAVE_OPENBSD_DVD_STRUCT 1' - elif freebsd || dragonfly ; then - def_dvd_bsd='#define HAVE_BSD_DVD_STRUCT 1' - elif darwin ; then - def_dvd_darwin='#define DARWIN_DVD_IOCTL' - extra_ldflags="$extra_ldflags -framework IOKit -framework Carbon" - elif cygwin ; then - cflags_libdvdcss="-DSYS_CYGWIN -DWIN32" - fi - cflags_libdvdcss_dvdread="-Ilibdvdcss" - def_dvdcss="#define HAVE_DVDCSS_DVDCSS_H 1" - inputmodules="libdvdcss(internal) $inputmodules" -else - noinputmodules="libdvdcss(internal) $noinputmodules" -fi -echores "$_libdvdcss_internal" - - echocheck "libcdio" if test "$_libcdio" = auto ; then _libcdio=no @@ -3575,49 +3502,7 @@ CFLAGS="$CFLAGS -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE CXXFLAGS=" $CFLAGS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS" -# This must be the last test to be performed. Any other tests following it -# could fail due to linker errors. libdvdnavmini is intentionally not linked -# against libdvdread (to permit MPlayer to use its own copy of the library). -# So any compilation using the flags added here but not linking against -# libdvdread can fail. -echocheck "DVD support (libdvdnav)" -if test "$_dvdread_internal" = yes && test ! -f "libdvdnav/dvdnav.c" ; then - _dvdnav=no -fi -dvdnav_internal=no -if test "$_dvdnav" = auto ; then - if test "$_dvdread_internal" = yes ; then - _dvdnav=yes - dvdnav_internal=yes - res_comment="internal" - else - $_dvdnavconfig --version --minilibs >> $TMPLOG 2>&1 || _dvdnav=no - fi -fi -if test "$_dvdnav" = auto ; then - _dvdnav=no - _dvdnavdir=$($_dvdnavconfig --cflags) - _dvdnavlibs=$($_dvdnavconfig --libs) - statement_check_broken stdint.h dvdnav/dvdnav.h 'dvdnav_t *dvd = 0' $_dvdnavdir $_dvdnavlibs $_ld_dl $_ld_pthread && _dvdnav=yes -fi -if test "$_dvdnav" = yes ; then - def_dvdnav='#define CONFIG_DVDNAV 1' - if test "$dvdnav_internal" = yes ; then - cflags_libdvdnav="-Ilibdvdnav" - inputmodules="dvdnav(internal) $inputmodules" - else - extra_cflags="$extra_cflags $($_dvdnavconfig --cflags)" - extra_ldflags="$extra_ldflags $($_dvdnavconfig --minilibs)" - inputmodules="dvdnav $inputmodules" - fi -else - def_dvdnav='#undef CONFIG_DVDNAV' - noinputmodules="dvdnav $noinputmodules" -fi -echores "$_dvdnav" - # DO NOT ADD ANY TESTS THAT USE LINKER FLAGS HERE (like cc_check). -# Read dvdnav comment above. mak_enable () { list=$(echo $1 | tr '[a-z]' '[A-Z]') @@ -3667,7 +3552,6 @@ DEPFLAGS = $DEPFLAGS CFLAGS_LIBDVDCSS = $cflags_libdvdcss CFLAGS_LIBDVDCSS_DVDREAD = $cflags_libdvdcss_dvdread -CFLAGS_LIBDVDNAV = $cflags_libdvdnav EXTRALIBS = $extra_ldflags $_ld_static $_ld_lm $extra_libs EXTRALIBS_MPLAYER = $libs_mplayer @@ -3705,10 +3589,7 @@ DIRECT3D = $_direct3d DIRECTFB = $_directfb DIRECTX = $_directx DVBIN = $_dvbin -DVDNAV = $_dvdnav -DVDNAV_INTERNAL = $dvdnav_internal DVDREAD = $_dvdread -DVDREAD_INTERNAL = $_dvdread_internal DXR3 = $_dxr3 FAAD = $_faad FTP = $_ftp @@ -3731,7 +3612,6 @@ LIBBLURAY = $_bluray LIBBS2B = $_libbs2b LIBDCA = $_libdca LIBDV = $_libdv -LIBDVDCSS_INTERNAL = $_libdvdcss_internal LIBMAD = $_mad LIBNEMESI = $_nemesi LCMS2 = $_lcms2 @@ -3835,8 +3715,6 @@ $def_translation /* libdvdread */ #define STDC_HEADERS 1 #define HAVE_MEMCPY 1 -/* libdvdnav */ -#define READ_CACHE_TRACE 0 /* libdvdread */ #define HAVE_DLFCN_H 1 $def_dvdcss @@ -3916,7 +3794,6 @@ $def_dvd_darwin $def_dvd_linux $def_dvd_openbsd $def_dvdio -$def_dvdnav $def_dvdread $def_vcd diff --git a/etc/input.conf b/etc/input.conf index 91eb098134..a7732acf01 100644 --- a/etc/input.conf +++ b/etc/input.conf @@ -134,20 +134,6 @@ k tv_step_channel -1 n tv_step_norm u tv_step_chanlist -# -# DVDNAV -# Requires dvdnav:// -# - -KP8 {dvdnav} dvdnav up -KP2 {dvdnav} dvdnav down -KP4 {dvdnav} dvdnav left -KP6 {dvdnav} dvdnav right -KP5 {dvdnav} dvdnav menu -KP_ENTER {dvdnav} dvdnav select -MOUSE_BTN0 {dvdnav} dvdnav mouse -KP7 {dvdnav} dvdnav prev - # # Apple Remote section # diff --git a/input/input.c b/input/input.c index 690321f7fe..98b135c349 100644 --- a/input/input.c +++ b/input/input.c @@ -197,10 +197,6 @@ static const mp_cmd_t mp_cmds[] = { { MP_CMD_RUN, "run", { ARG_STRING } }, { MP_CMD_VF_CHANGE_RECTANGLE, "change_rectangle", { ARG_INT, ARG_INT } }, -#ifdef CONFIG_DVDNAV - { MP_CMD_DVDNAV, "dvdnav", { ARG_STRING } }, -#endif - { MP_CMD_GET_VO_FULLSCREEN, "get_vo_fullscreen", }, { MP_CMD_GET_SUB_VISIBILITY, "get_sub_visibility", }, { MP_CMD_KEYDOWN_EVENTS, "key_down_event", { ARG_INT } }, diff --git a/input/input.h b/input/input.h index 0fccbb5233..04cefab46e 100644 --- a/input/input.h +++ b/input/input.h @@ -44,7 +44,6 @@ enum mp_command_type { MP_CMD_TV_STEP_CHANNEL_LIST, MP_CMD_VO_FULLSCREEN, MP_CMD_SUB_POS, - MP_CMD_DVDNAV, MP_CMD_SCREENSHOT, MP_CMD_PANSCAN, MP_CMD_MUTE, @@ -130,16 +129,6 @@ enum mp_command_type { MP_CMD_SWITCH_TITLE, MP_CMD_STOP, - /// DVDNAV commands - MP_CMD_DVDNAV_UP = 1000, - MP_CMD_DVDNAV_DOWN, - MP_CMD_DVDNAV_LEFT, - MP_CMD_DVDNAV_RIGHT, - MP_CMD_DVDNAV_MENU, - MP_CMD_DVDNAV_SELECT, - MP_CMD_DVDNAV_PREVMENU, - MP_CMD_DVDNAV_MOUSECLICK, - /// DVB commands MP_CMD_DVB_SET_CHANNEL = 5101, diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index 078699fad7..51d7a45cb4 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -1145,7 +1145,7 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, * (nothing actually implements DEMUXER_CTRL_RESYNC now). */ struct stream *stream = demuxer->stream; - if (stream->type == STREAMTYPE_DVD || stream->type == STREAMTYPE_DVDNAV) { + if (stream->type == STREAMTYPE_DVD) { double pts; if (flags & SEEK_ABSOLUTE) diff --git a/mp_core.h b/mp_core.h index 466bbfdf04..6d19426295 100644 --- a/mp_core.h +++ b/mp_core.h @@ -214,12 +214,6 @@ typedef struct MPContext { struct screenshot_ctx *screenshot_ctx; -#ifdef CONFIG_DVDNAV - struct mp_image *nav_smpi; ///< last decoded dvdnav video image - unsigned char *nav_buffer; ///< last read dvdnav video frame - unsigned char *nav_start; ///< pointer to last read video buffer - int nav_in_size; ///< last read size -#endif } MPContext; diff --git a/mplayer.c b/mplayer.c index e280a1e20c..a15d9ea385 100644 --- a/mplayer.c +++ b/mplayer.c @@ -146,7 +146,6 @@ static int max_framesize = 0; #ifdef CONFIG_DVDREAD #include "stream/stream_dvd.h" #endif -#include "stream/stream_dvdnav.h" #include "libmpcodecs/dec_audio.h" #include "libmpcodecs/dec_video.h" @@ -526,19 +525,6 @@ static void print_file_properties(struct MPContext *mpctx, const char *filename) /// step size of mixer changes int volstep = 3; -#ifdef CONFIG_DVDNAV -static void mp_dvdnav_context_free(MPContext *ctx) -{ - if (ctx->nav_smpi) - free_mp_image(ctx->nav_smpi); - ctx->nav_smpi = NULL; - free(ctx->nav_buffer); - ctx->nav_buffer = NULL; - ctx->nav_start = NULL; - ctx->nav_in_size = 0; -} -#endif - static void uninit_subs(struct demuxer *demuxer) { for (int i = 0; i < MAX_S_STREAMS; i++) { @@ -615,9 +601,6 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) mpctx->initialized_flags &= ~INITIALIZED_VO; vo_destroy(mpctx->video_out); mpctx->video_out = NULL; -#ifdef CONFIG_DVDNAV - mp_dvdnav_context_free(mpctx); -#endif } // Must be after libvo uninit, as few vo drivers (svgalib) have tty code. @@ -953,13 +936,6 @@ void init_vo_spudec(struct MPContext *mpctx) } #endif -#ifdef CONFIG_DVDNAV - if (vo_spudec == NULL && mpctx->stream->type == STREAMTYPE_DVDNAV) { - unsigned int *palette = mp_dvdnav_get_spu_clut(mpctx->stream); - vo_spudec = spudec_new_scaled(palette, width, height, NULL, 0); - } -#endif - if (vo_spudec == NULL) { sh_sub_t *sh = mpctx->d_sub->sh; vo_spudec = spudec_new_scaled(NULL, width, height, sh->extradata, @@ -1854,149 +1830,6 @@ static int select_subtitle(MPContext *mpctx) return found; } -#ifdef CONFIG_DVDNAV -#ifndef FF_B_TYPE -#define FF_B_TYPE 3 -#endif -/// store decoded video image -static mp_image_t *mp_dvdnav_copy_mpi(mp_image_t *to_mpi, - mp_image_t *from_mpi) -{ - mp_image_t *mpi; - - /// Do not store B-frames - if (from_mpi->pict_type == FF_B_TYPE) - return to_mpi; - - if (to_mpi && - to_mpi->w == from_mpi->w && - to_mpi->h == from_mpi->h && - to_mpi->imgfmt == from_mpi->imgfmt) - mpi = to_mpi; - else { - if (to_mpi) - free_mp_image(to_mpi); - if (from_mpi->w == 0 || from_mpi->h == 0) - return NULL; - mpi = alloc_mpi(from_mpi->w, from_mpi->h, from_mpi->imgfmt); - } - - copy_mpi(mpi, from_mpi); - return mpi; -} - -static void mp_dvdnav_reset_stream(MPContext *ctx) -{ - struct MPOpts *opts = &ctx->opts; - if (ctx->sh_video) { - /// clear video pts - ctx->d_video->pts = 0.0f; - ctx->sh_video->pts = 0.0f; - ctx->sh_video->i_pts = 0.0f; - ctx->sh_video->last_pts = 0.0f; - ctx->sh_video->num_buffered_pts = 0; - ctx->sh_video->num_frames = 0; - ctx->sh_video->num_frames_decoded = 0; - ctx->sh_video->timer = 0.0f; - ctx->sh_video->stream_delay = 0.0f; - ctx->sh_video->timer = 0; - ctx->demuxer->stream_pts = MP_NOPTS_VALUE; - } - - if (ctx->sh_audio) { - /// free audio packets and reset - ds_free_packs(ctx->d_audio); - audio_delay -= ctx->sh_audio->stream_delay; - ctx->delay = -audio_delay; - ao_reset(ctx->ao); - resync_audio_stream(ctx->sh_audio); - } - - audio_delay = 0.0f; - ctx->sub_counts[SUB_SOURCE_DEMUX] = mp_dvdnav_number_of_subs(ctx->stream); - if (opts->sub_lang && opts->sub_id == dvdsub_lang_id) { - dvdsub_lang_id = mp_dvdnav_sid_from_lang(ctx->stream, opts->sub_lang); - if (dvdsub_lang_id != opts->sub_id) { - opts->sub_id = dvdsub_lang_id; - select_subtitle(ctx); - } - } - - /// clear all EOF related flags - ctx->d_video->eof = ctx->d_audio->eof = ctx->stream->eof = 0; -} - -/// Restore last decoded DVDNAV (still frame) -static mp_image_t *mp_dvdnav_restore_smpi(struct MPContext *mpctx, - int *in_size, - unsigned char **start, - mp_image_t *decoded_frame) -{ - if (mpctx->stream->type != STREAMTYPE_DVDNAV) - return decoded_frame; - - /// a change occurred in dvdnav stream - if (mp_dvdnav_cell_has_changed(mpctx->stream, 0)) { - mp_dvdnav_read_wait(mpctx->stream, 1, 1); - mp_dvdnav_context_free(mpctx); - mp_dvdnav_reset_stream(mpctx); - mp_dvdnav_read_wait(mpctx->stream, 0, 1); - mp_dvdnav_cell_has_changed(mpctx->stream, 1); - } - - if (*in_size < 0) { - float len; - - /// Display still frame, if any - if (mpctx->nav_smpi && !mpctx->nav_buffer) - decoded_frame = mpctx->nav_smpi; - - /// increment video frame : continue playing after still frame - len = get_time_length(mpctx); - if (mpctx->sh_video->pts >= len && - mpctx->sh_video->pts > 0.0 && len > 0.0) { - mp_dvdnav_skip_still(mpctx->stream); - mp_dvdnav_skip_wait(mpctx->stream); - } - mpctx->sh_video->pts += 1 / mpctx->sh_video->fps; - - if (mpctx->nav_buffer) { - *start = mpctx->nav_start; - *in_size = mpctx->nav_in_size; - if (mpctx->nav_start) - memcpy(*start, mpctx->nav_buffer, mpctx->nav_in_size); - } - } - - return decoded_frame; -} - -/// Save last decoded DVDNAV (still frame) -static void mp_dvdnav_save_smpi(struct MPContext *mpctx, int in_size, - unsigned char *start, - mp_image_t *decoded_frame) -{ - if (mpctx->stream->type != STREAMTYPE_DVDNAV) - return; - - free(mpctx->nav_buffer); - mpctx->nav_buffer = NULL; - mpctx->nav_start = NULL; - mpctx->nav_in_size = -1; - - if (in_size > 0) - mpctx->nav_buffer = malloc(in_size); - if (mpctx->nav_buffer) { - mpctx->nav_start = start; - mpctx->nav_in_size = in_size; - memcpy(mpctx->nav_buffer, start, in_size); - } - - if (decoded_frame && mpctx->nav_smpi != decoded_frame) - mpctx->nav_smpi = mp_dvdnav_copy_mpi(mpctx->nav_smpi, decoded_frame); -} -#endif /* CONFIG_DVDNAV */ - /* Modify video timing to match the audio timeline. There are two main * reasons this is needed. First, video and audio can start from different * positions at beginning of file or after a seek (MPlayer starts both @@ -2365,20 +2198,8 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx) while (!in_size) in_size = video_read_frame(sh_video, &sh_video->next_frame_time, &packet, force_fps); - if (in_size < 0) { -#ifdef CONFIG_DVDNAV - if (mpctx->stream->type == STREAMTYPE_DVDNAV) { - if (mp_dvdnav_is_eof(mpctx->stream)) - return -1; - if (mpctx->d_video) - mpctx->d_video->eof = 0; - if (mpctx->d_audio) - mpctx->d_audio->eof = 0; - mpctx->stream->eof = 0; - } else -#endif + if (in_size < 0) return -1; - } if (in_size > max_framesize) max_framesize = in_size; sh_video->timer += frame_time; @@ -2389,16 +2210,8 @@ static double update_video_nocorrect_pts(struct MPContext *mpctx) int framedrop_type = check_framedrop(mpctx, frame_time); void *decoded_frame; -#ifdef CONFIG_DVDNAV - decoded_frame = mp_dvdnav_restore_smpi(mpctx, &in_size, &packet, NULL); - if (in_size >= 0 && !decoded_frame) -#endif decoded_frame = decode_video(sh_video, sh_video->ds->current, packet, in_size, framedrop_type, sh_video->pts); -#ifdef CONFIG_DVDNAV - // Save last still frame for future display - mp_dvdnav_save_smpi(mpctx, in_size, packet, decoded_frame); -#endif if (decoded_frame) { filter_video(sh_video, decoded_frame, sh_video->pts); } @@ -3195,30 +3008,6 @@ static void run_playloop(struct MPContext *mpctx) break; } // video -#ifdef CONFIG_DVDNAV - if (mpctx->stream->type == STREAMTYPE_DVDNAV) { - nav_highlight_t hl; - mp_dvdnav_get_highlight(mpctx->stream, &hl); - if (!vo_spudec || !spudec_apply_palette_crop(vo_spudec, hl.palette, hl.sx, hl.sy, hl.ex, hl.ey)) { - osd_set_nav_box(hl.sx, hl.sy, hl.ex, hl.ey); - vo_osd_changed(OSDTYPE_DVDNAV); - } else { - osd_set_nav_box(0, 0, 0, 0); - vo_osd_changed(OSDTYPE_DVDNAV); - vo_osd_changed(OSDTYPE_SPU); - } - - if (mp_dvdnav_stream_has_changed(mpctx->stream)) { - double ar = -1.0; - if (mpctx->sh_video && - stream_control(mpctx->demuxer->stream, - STREAM_CTRL_GET_ASPECT_RATIO, &ar) - != STREAM_UNSUPPORTED) - mpctx->sh_video->stream_aspect = ar; - } - } -#endif - if (mpctx->sh_audio && (mpctx->restart_playback ? !video_left : mpctx->ao->untimed && (mpctx->delay <= 0 || !video_left))) { @@ -3635,21 +3424,6 @@ static void play_current_file(struct MPContext *mpctx) } #endif -#ifdef CONFIG_DVDNAV - if (mpctx->stream->type == STREAMTYPE_DVDNAV) { - if (opts->audio_lang && opts->audio_id == -1) - opts->audio_id = mp_dvdnav_aid_from_lang(mpctx->stream, - opts->audio_lang); - dvdsub_lang_id = -3; - if (opts->sub_lang && opts->sub_id == -1) - dvdsub_lang_id = opts->sub_id = mp_dvdnav_sid_from_lang( - mpctx->stream, opts->sub_lang); - // setup global sub numbering - mpctx->sub_counts[SUB_SOURCE_DEMUX] = mp_dvdnav_number_of_subs( - mpctx->stream); - } -#endif - // CACHE2: initial prefill: 20% later: 5% (should be set by -cacheopts) goto_enable_cache: if (stream_cache_size > 0) { @@ -3763,8 +3537,7 @@ goto_enable_cache: demux_info_print(mpctx->demuxer); //================= Read SUBTITLES (DVD & TEXT) ========================= - if (vo_spudec == NULL && (mpctx->stream->type == STREAMTYPE_DVD - || mpctx->stream->type == STREAMTYPE_DVDNAV)) + if (vo_spudec == NULL && (mpctx->stream->type == STREAMTYPE_DVD)) init_vo_spudec(mpctx); open_subtitles_from_options(mpctx); @@ -3844,8 +3617,6 @@ goto_enable_cache: //TODO: add desired (stream-based) sections here if (mpctx->stream->type == STREAMTYPE_TV) mp_input_set_section(mpctx->input, "tv"); - if (mpctx->stream->type == STREAMTYPE_DVDNAV) - mp_input_set_section(mpctx->input, "dvdnav"); //==================== START PLAYING ======================= @@ -3896,14 +3667,6 @@ goto_enable_cache: end_at.type = END_AT_NONE; } -#ifdef CONFIG_DVDNAV - mp_dvdnav_context_free(mpctx); - if (mpctx->stream->type == STREAMTYPE_DVDNAV) { - mp_dvdnav_read_wait(mpctx->stream, 0, 1); - mp_dvdnav_cell_has_changed(mpctx->stream, 1); - } -#endif - mpctx->seek = (struct seek_params){ 0 }; get_relative_time(mpctx); // reset current delta // Make sure VO knows current pause state diff --git a/parser-mpcmd.c b/parser-mpcmd.c index 5a91c093f9..41cad67467 100644 --- a/parser-mpcmd.c +++ b/parser-mpcmd.c @@ -265,10 +265,9 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, // filename bstr file = p.arg; char *file0 = bstrdup0(NULL, p.arg); - int is_dvdnav = bstr_startswith0(file, "dvdnav://"); // expand DVD filename entries like dvd://1-3 into component titles - if (bstr_startswith0(file, "dvd://") || is_dvdnav) { - int offset = is_dvdnav ? 9 : 6; + if (bstr_startswith0(file, "dvd://")) { + int offset = 6; char *splitpos = strstr(file0 + offset, "-"); if (splitpos != NULL) { int start_title = strtol(file0 + offset, NULL, 10); @@ -284,8 +283,7 @@ bool m_config_parse_mp_command_line(m_config_t *config, struct playlist *files, && (start_title < end_title)) { for (int j = start_title; j <= end_title; j++) { char entbuf[15]; - snprintf(entbuf, sizeof(entbuf), - is_dvdnav ? "dvdnav://%d" : "dvd://%d", j); + snprintf(entbuf, sizeof(entbuf), "dvd://%d", j); playlist_add_file(files, entbuf); } } else diff --git a/stream/stream.c b/stream/stream.c index d4f0c8ae97..d04b7fb8d8 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -71,7 +71,6 @@ extern const stream_info_t stream_info_radio; extern const stream_info_t stream_info_pvr; extern const stream_info_t stream_info_ftp; extern const stream_info_t stream_info_vstream; -extern const stream_info_t stream_info_dvdnav; extern const stream_info_t stream_info_smb; extern const stream_info_t stream_info_sdp; extern const stream_info_t stream_info_rtsp_sip; @@ -130,9 +129,6 @@ static const stream_info_t* const auto_open_streams[] = { &stream_info_ifo, &stream_info_dvd, #endif -#ifdef CONFIG_DVDNAV - &stream_info_dvdnav, -#endif #ifdef CONFIG_LIBBLURAY &stream_info_bluray, #endif @@ -313,10 +309,6 @@ int stream_read_internal(stream_t *s, void *buf, int len) // do not retry if this looks like proper eof if (s->eof || (s->end_pos && s->pos == s->end_pos)) goto eof_out; - // dvdnav has some horrible hacks to "suspend" reads, - // we need to skip this code or seeks will hang. - if (s->type == STREAMTYPE_DVDNAV) - goto eof_out; // just in case this is an error e.g. due to network // timeout reset and retry diff --git a/stream/stream.h b/stream/stream.h index df1f15c0b0..7df09490d1 100644 --- a/stream/stream.h +++ b/stream/stream.h @@ -42,7 +42,6 @@ #define STREAMTYPE_MEMORY 4 // read data from memory area #define STREAMTYPE_PLAYLIST 6 // FIXME!!! same as STREAMTYPE_FILE now #define STREAMTYPE_DS 8 // read from a demuxer stream -#define STREAMTYPE_DVDNAV 9 // we cannot safely "seek" in this... #define STREAMTYPE_CDDA 10 // raw audio CD reader #define STREAMTYPE_SMB 11 // smb:// url, using libsmbclient (samba) #define STREAMTYPE_VCDBINCUE 12 // vcd directly from bin/cue files diff --git a/stream/stream_dvdnav.c b/stream/stream_dvdnav.c deleted file mode 100644 index d0e29446d3..0000000000 --- a/stream/stream_dvdnav.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include "options.h" -#include "mp_msg.h" -#include "osdep/timer.h" -#include "input/input.h" -#include "stream.h" -#include "libmpdemux/demuxer.h" -#include -#include "stream_dvdnav.h" -#include "libvo/video_out.h" -#include "libavutil/common.h" -#include "sub/spudec.h" -#include "m_option.h" -#include "m_struct.h" -#include "stream_dvd_common.h" - -/* state flags */ -typedef enum { - NAV_FLAG_EOF = 1 << 0, /* end of stream has been reached */ - NAV_FLAG_WAIT = 1 << 1, /* wait event */ - NAV_FLAG_WAIT_SKIP = 1 << 2, /* wait skip disable */ - NAV_FLAG_CELL_CHANGE = 1 << 3, /* cell change event */ - NAV_FLAG_WAIT_READ_AUTO = 1 << 4, /* wait read auto mode */ - NAV_FLAG_WAIT_READ = 1 << 5, /* suspend read from stream */ - NAV_FLAG_VTS_DOMAIN = 1 << 6, /* vts domain */ - NAV_FLAG_SPU_SET = 1 << 7, /* spu_clut is valid */ - NAV_FLAG_STREAM_CHANGE = 1 << 8, /* title, chapter, audio or SPU */ - NAV_FLAG_AUDIO_CHANGE = 1 << 9, /* audio stream change event */ - NAV_FLAG_SPU_CHANGE = 1 << 10, /* spu stream change event */ -} dvdnav_state_t; - -typedef struct { - dvdnav_t * dvdnav; /* handle to libdvdnav stuff */ - char * filename; /* path */ - unsigned int duration; /* in milliseconds */ - int mousex, mousey; - int title; - unsigned int spu_clut[16]; - dvdnav_highlight_event_t hlev; - int still_length; /* still frame duration */ - unsigned int state; -} dvdnav_priv_t; - -static struct stream_priv_s { - int track; - char* device; -} stream_priv_dflts = { - 0, - NULL -}; - -#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f) -/// URL definition -static const m_option_t stream_opts_fields[] = { - {"filename", ST_OFF(device), CONF_TYPE_STRING, 0, 0, 0, NULL }, - {"hostname", ST_OFF(track), CONF_TYPE_INT, M_OPT_RANGE, 1, 99, NULL}, - { NULL, NULL, 0, 0, 0, 0, NULL } -}; -static const struct m_struct_st stream_opts = { - "dvd", - sizeof(struct stream_priv_s), - &stream_priv_dflts, - stream_opts_fields -}; - -static int seek(stream_t *s, off_t newpos); -static void show_audio_subs_languages(dvdnav_t *nav); - -static dvdnav_priv_t * new_dvdnav_stream(char * filename) { - const char * title_str; - dvdnav_priv_t *priv; - - if (!filename) - return NULL; - - if (!(priv=calloc(1,sizeof(dvdnav_priv_t)))) - return NULL; - - if (!(priv->filename=strdup(filename))) { - free(priv); - return NULL; - } - - dvd_set_speed(priv->filename, dvd_speed); - - if(dvdnav_open(&(priv->dvdnav),priv->filename)!=DVDNAV_STATUS_OK) - { - free(priv->filename); - free(priv); - return NULL; - } - - if (!priv->dvdnav) { - free(priv); - return NULL; - } - - if(1) //from vlc: if not used dvdnav from cvs will fail - { - int len, event; - char buf[2048]; - - dvdnav_get_next_block(priv->dvdnav,buf,&event,&len); - dvdnav_sector_search(priv->dvdnav, 0, SEEK_SET); - } - - /* turn off dvdnav caching */ - dvdnav_set_readahead_flag(priv->dvdnav, 0); - if(dvdnav_set_PGC_positioning_flag(priv->dvdnav, 1) != DVDNAV_STATUS_OK) - mp_msg(MSGT_OPEN,MSGL_ERR,"stream_dvdnav, failed to set PGC positioning\n"); - /* report the title?! */ - if (dvdnav_get_title_string(priv->dvdnav,&title_str)==DVDNAV_STATUS_OK) { - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_VOLUME_ID=%s\n", title_str); - } - - //dvdnav_event_clear(priv); - - return priv; -} - -static void dvdnav_get_highlight (dvdnav_priv_t *priv, int display_mode) { - pci_t *pnavpci = NULL; - dvdnav_highlight_event_t *hlev = &(priv->hlev); - int btnum; - - if (!priv || !priv->dvdnav) - return; - - pnavpci = dvdnav_get_current_nav_pci (priv->dvdnav); - if (!pnavpci) - return; - - dvdnav_get_current_highlight (priv->dvdnav, &(hlev->buttonN)); - hlev->display = display_mode; /* show */ - - if (hlev->buttonN > 0 && pnavpci->hli.hl_gi.btn_ns > 0 && hlev->display) { - for (btnum = 0; btnum < pnavpci->hli.hl_gi.btn_ns; btnum++) { - btni_t *btni = &(pnavpci->hli.btnit[btnum]); - - if (hlev->buttonN == btnum + 1) { - hlev->sx = FFMIN (btni->x_start, btni->x_end); - hlev->ex = FFMAX (btni->x_start, btni->x_end); - hlev->sy = FFMIN (btni->y_start, btni->y_end); - hlev->ey = FFMAX (btni->y_start, btni->y_end); - - hlev->palette = (btni->btn_coln == 0) ? 0 : - pnavpci->hli.btn_colit.btn_coli[btni->btn_coln - 1][0]; - break; - } - } - } else { /* hide button or no button */ - hlev->sx = hlev->ex = 0; - hlev->sy = hlev->ey = 0; - hlev->palette = hlev->buttonN = 0; - } -} - -static inline int dvdnav_get_duration (int length) { - return (length == 255) ? 0 : length * 1000; -} - -static int dvdnav_stream_read(dvdnav_priv_t * priv, unsigned char *buf, int *len) { - int event = DVDNAV_NOP; - - *len=-1; - if (dvdnav_get_next_block(priv->dvdnav,buf,&event,len)!=DVDNAV_STATUS_OK) { - mp_msg(MSGT_OPEN,MSGL_V, "Error getting next block from DVD %d (%s)\n",event, dvdnav_err_to_string(priv->dvdnav) ); - *len=-1; - } - else if (event!=DVDNAV_BLOCK_OK) { - // need to handle certain events internally (like skipping stills) - switch (event) { - case DVDNAV_NAV_PACKET: - return event; - case DVDNAV_STILL_FRAME: { - dvdnav_still_event_t *still_event = (dvdnav_still_event_t *) buf; - priv->still_length = still_event->length; - /* set still frame duration */ - priv->duration = dvdnav_get_duration (priv->still_length); - if (priv->still_length <= 1) { - pci_t *pnavpci = dvdnav_get_current_nav_pci (priv->dvdnav); - priv->duration = mp_dvdtimetomsec (&pnavpci->pci_gi.e_eltm); - } - break; - } - case DVDNAV_HIGHLIGHT: { - dvdnav_get_highlight (priv, 1); - break; - } - case DVDNAV_CELL_CHANGE: { - dvdnav_cell_change_event_t *ev = (dvdnav_cell_change_event_t*)buf; - uint32_t nextstill; - - priv->state &= ~NAV_FLAG_WAIT_SKIP; - priv->state |= NAV_FLAG_STREAM_CHANGE; - if(ev->pgc_length) - priv->duration = ev->pgc_length/90; - - if (dvdnav_is_domain_vts(priv->dvdnav)) { - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "DVDNAV_TITLE_IS_MOVIE\n"); - priv->state &= ~NAV_FLAG_VTS_DOMAIN; - } else { - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "DVDNAV_TITLE_IS_MENU\n"); - priv->state |= NAV_FLAG_VTS_DOMAIN; - } - - nextstill = dvdnav_get_next_still_flag (priv->dvdnav); - if (nextstill) { - priv->duration = dvdnav_get_duration (nextstill); - priv->still_length = nextstill; - if (priv->still_length <= 1) { - pci_t *pnavpci = dvdnav_get_current_nav_pci (priv->dvdnav); - priv->duration = mp_dvdtimetomsec (&pnavpci->pci_gi.e_eltm); - } - } - - break; - } - case DVDNAV_SPU_CLUT_CHANGE: { - memcpy(priv->spu_clut, buf, 16*sizeof(unsigned int)); - priv->state |= NAV_FLAG_SPU_SET; - break; - } - case DVDNAV_WAIT: { - if ((priv->state & NAV_FLAG_WAIT_SKIP) && - !(priv->state & NAV_FLAG_WAIT)) - dvdnav_wait_skip (priv->dvdnav); - else - priv->state |= NAV_FLAG_WAIT; - break; - } - case DVDNAV_VTS_CHANGE: { - priv->state &= ~NAV_FLAG_WAIT_SKIP; - priv->state |= NAV_FLAG_STREAM_CHANGE; - break; - } - case DVDNAV_SPU_STREAM_CHANGE: { - priv->state |= NAV_FLAG_STREAM_CHANGE; - break; - } - } - - *len=0; - } - return event; -} - -static void update_title_len(stream_t *stream) { - dvdnav_priv_t *priv = stream->priv; - dvdnav_status_t status; - uint32_t pos = 0, len = 0; - - status = dvdnav_get_position(priv->dvdnav, &pos, &len); - if(status == DVDNAV_STATUS_OK && len) { - stream->end_pos = (off_t) len * 2048; - stream->seek = seek; - } else { - stream->seek = NULL; - stream->end_pos = 0; - } -} - - -static int seek(stream_t *s, off_t newpos) { - uint32_t sector = 0; - dvdnav_priv_t *priv = s->priv; - - if(s->end_pos && newpos > s->end_pos) - newpos = s->end_pos; - sector = newpos / 2048ULL; - if(dvdnav_sector_search(priv->dvdnav, (uint64_t) sector, SEEK_SET) != DVDNAV_STATUS_OK) - goto fail; - - s->pos = newpos; - - return 1; - -fail: - mp_msg(MSGT_STREAM,MSGL_INFO,"dvdnav_stream, seeking to %"PRIu64" failed: %s\n", newpos, dvdnav_err_to_string(priv->dvdnav)); - - return 1; -} - -static void stream_dvdnav_close(stream_t *s) { - dvdnav_priv_t *priv = s->priv; - dvdnav_close(priv->dvdnav); - priv->dvdnav = NULL; - dvd_set_speed(priv->filename, -1); - free(priv); -} - - -static int fill_buffer(stream_t *s, char *but, int len) -{ - int event; - - dvdnav_priv_t* priv=s->priv; - if (priv->state & NAV_FLAG_WAIT_READ) /* read is suspended */ - return -1; - len=0; - if(!s->end_pos) - update_title_len(s); - while(!len) /* grab all event until DVDNAV_BLOCK_OK (len=2048), DVDNAV_STOP or DVDNAV_STILL_FRAME */ - { - event=dvdnav_stream_read(priv, s->buffer, &len); - if(event==-1 || len==-1) - { - mp_msg(MSGT_CPLAYER,MSGL_ERR, "DVDNAV stream read error!\n"); - return 0; - } - if (event != DVDNAV_BLOCK_OK) - dvdnav_get_highlight (priv, 1); - switch (event) { - case DVDNAV_STOP: { - priv->state |= NAV_FLAG_EOF; - return len; - } - case DVDNAV_BLOCK_OK: - case DVDNAV_NAV_PACKET: - case DVDNAV_STILL_FRAME: - return len; - case DVDNAV_WAIT: { - if (priv->state & NAV_FLAG_WAIT) - return len; - break; - } - case DVDNAV_VTS_CHANGE: { - int tit = 0, part = 0; - dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)s->buffer; - mp_msg(MSGT_CPLAYER,MSGL_INFO, "DVDNAV, switched to title: %d\r\n", vts_event->new_vtsN); - priv->state |= NAV_FLAG_CELL_CHANGE; - priv->state |= NAV_FLAG_AUDIO_CHANGE; - priv->state |= NAV_FLAG_SPU_CHANGE; - priv->state &= ~NAV_FLAG_WAIT_SKIP; - priv->state &= ~NAV_FLAG_WAIT; - s->end_pos = 0; - update_title_len(s); - show_audio_subs_languages(priv->dvdnav); - if (priv->state & NAV_FLAG_WAIT_READ_AUTO) - priv->state |= NAV_FLAG_WAIT_READ; - if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) == DVDNAV_STATUS_OK) { - mp_msg(MSGT_CPLAYER,MSGL_V, "\r\nDVDNAV, NEW TITLE %d\r\n", tit); - dvdnav_get_highlight (priv, 0); - if(priv->title > 0 && tit != priv->title) { - priv->state |= NAV_FLAG_EOF; - return 0; - } - } - break; - } - case DVDNAV_CELL_CHANGE: { - priv->state |= NAV_FLAG_CELL_CHANGE; - priv->state |= NAV_FLAG_AUDIO_CHANGE; - priv->state |= NAV_FLAG_SPU_CHANGE; - priv->state &= ~NAV_FLAG_WAIT_SKIP; - priv->state &= ~NAV_FLAG_WAIT; - if (priv->state & NAV_FLAG_WAIT_READ_AUTO) - priv->state |= NAV_FLAG_WAIT_READ; - if(priv->title > 0 && s->opts->chapterrange[1] > 0) { - int tit=0, part=0; - if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) == DVDNAV_STATUS_OK && part > s->opts->chapterrange[1]) { - priv->state |= NAV_FLAG_EOF; - return 0; - } - } - dvdnav_get_highlight (priv, 1); - } - break; - case DVDNAV_AUDIO_STREAM_CHANGE: - priv->state |= NAV_FLAG_AUDIO_CHANGE; - break; - case DVDNAV_SPU_STREAM_CHANGE: - priv->state |= NAV_FLAG_SPU_CHANGE; - break; - } - } - mp_msg(MSGT_STREAM,MSGL_DBG2,"DVDNAV fill_buffer len: %d\n",len); - return len; -} - -static int mp_dvdnav_lang_from_sid(stream_t *stream, int sid); -static int mp_dvdnav_lang_from_aid(stream_t *stream, int sid); - -static int control(stream_t *stream, int cmd, void* arg) { - dvdnav_priv_t* priv=stream->priv; - int tit, part; - - switch(cmd) - { - case STREAM_CTRL_SEEK_TO_CHAPTER: - { - int chap = *(unsigned int *)arg+1; - - if(chap < 1 || dvdnav_current_title_info(priv->dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - if(dvdnav_part_play(priv->dvdnav, tit, chap) != DVDNAV_STATUS_OK) - break; - return 1; - } - case STREAM_CTRL_GET_NUM_CHAPTERS: - { - if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - if(dvdnav_get_number_of_parts(priv->dvdnav, tit, &part) != DVDNAV_STATUS_OK) - break; - if(!part) - break; - *(unsigned int *)arg = part; - return 1; - } - case STREAM_CTRL_GET_CURRENT_CHAPTER: - { - if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) != DVDNAV_STATUS_OK) - break; - *(unsigned int *)arg = part - 1; - return 1; - } - case STREAM_CTRL_GET_TIME_LENGTH: - { - if(priv->duration || priv->still_length) - { - *(double *)arg = (double)priv->duration / 1000.0; - return 1; - } - break; - } - case STREAM_CTRL_GET_ASPECT_RATIO: - { - uint8_t ar = dvdnav_get_video_aspect(priv->dvdnav); - *(double *)arg = !ar ? 4.0/3.0 : 16.0/9.0; - return 1; - } - case STREAM_CTRL_GET_CURRENT_TIME: - { - double tm; - tm = dvdnav_get_current_time(priv->dvdnav)/90000.0f; - if(tm != -1) - { - *(double *)arg = tm; - return 1; - } - break; - } - case STREAM_CTRL_SEEK_TO_TIME: - { - uint64_t tm = (uint64_t) (*((double*)arg) * 90000); - if(dvdnav_time_search(priv->dvdnav, tm) == DVDNAV_STATUS_OK) - return 1; - break; - } - case STREAM_CTRL_GET_NUM_ANGLES: - { - uint32_t curr, angles; - if(dvdnav_get_angle_info(priv->dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - *(int *)arg = angles; - return 1; - } - case STREAM_CTRL_GET_ANGLE: - { - uint32_t curr, angles; - if(dvdnav_get_angle_info(priv->dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - *(int *)arg = curr; - return 1; - } - case STREAM_CTRL_SET_ANGLE: - { - uint32_t curr, angles; - int new_angle = *(int *)arg; - if(dvdnav_get_angle_info(priv->dvdnav, &curr, &angles) != DVDNAV_STATUS_OK) - break; - if(new_angle>angles || new_angle<1) - break; - if(dvdnav_angle_change(priv->dvdnav, new_angle) != DVDNAV_STATUS_OK) - return 1; - } - case STREAM_CTRL_GET_LANG: - { - struct stream_lang_req *req = arg; - int lang = 0; - switch(req->type) { - case stream_ctrl_audio: - lang = mp_dvdnav_lang_from_aid(stream, req->id); - break; - case stream_ctrl_sub: - lang = mp_dvdnav_lang_from_sid(stream, req->id); - break; - } - if (!lang) - break; - req->name = talloc_strdup(NULL, (char[]) {lang >> 8, lang, 0}); - return STREAM_OK; - } - } - - return STREAM_UNSUPPORTED; -} - -static void identify_chapters(dvdnav_t *nav, uint32_t title) -{ - uint64_t *parts=NULL, duration=0; - uint32_t n, i, t; - n = dvdnav_describe_title_chapters(nav, title, &parts, &duration); - if(parts) { - t = duration / 90; - mp_msg(MSGT_IDENTIFY, MSGL_V, "ID_DVD_TITLE_%d_LENGTH=%d.%03d\n", title, t / 1000, t % 1000); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_TITLE_%d_CHAPTERS=%d\n", title, n); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "TITLE %u, CHAPTERS: ", title); - - for(i=0; itrack <= 0) { - dvdnav_get_number_of_titles(priv->dvdnav, &titles); - for(i=1; i<=titles; i++) - identify_chapters(priv->dvdnav, i); - } - else - identify_chapters(priv->dvdnav, p->track); -} - -static void show_audio_subs_languages(dvdnav_t *nav) -{ - uint8_t lg; - uint16_t i, lang, format, id, channels; - int base[7] = {128, 0, 0, 0, 160, 136, 0}; - for(i=0; i<8; i++) - { - char tmp[] = "unknown"; - lg = dvdnav_get_audio_logical_stream(nav, i); - if(lg == 0xff) continue; - channels = dvdnav_audio_stream_channels(nav, lg); - if(channels == 0xFFFF) - channels = 2; //unknown - else - channels--; - lang = dvdnav_audio_stream_to_lang(nav, lg); - if(lang != 0xFFFF) - { - tmp[0] = lang >> 8; - tmp[1] = lang & 0xFF; - tmp[2] = 0; - } - format = dvdnav_audio_stream_format(nav, lg); - if(format == 0xFFFF || format > 6) - format = 1; //unknown - id = i + base[format]; - mp_tmsg(MSGT_OPEN,MSGL_STATUS,"audio stream: %d format: %s (%s) language: %s aid: %d.\n", i, - dvd_audio_stream_types[format], dvd_audio_stream_channels[channels], tmp, id); - if (lang != 0xFFFF && lang && tmp[0]) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", id, tmp); - } - - for(i=0; i<32; i++) - { - char tmp[] = "unknown"; - lg = dvdnav_get_spu_logical_stream(nav, i); - if(lg == 0xff) continue; - lang = dvdnav_spu_stream_to_lang(nav, i); - if(lang != 0xFFFF) - { - tmp[0] = lang >> 8; - tmp[1] = lang & 0xFF; - tmp[2] = 0; - } - mp_msg(MSGT_OPEN,MSGL_STATUS,"subtitle ( sid ): %d language: %s\n", lg, tmp); - if (lang != 0xFFFF && lang && tmp[0]) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", lg, tmp); - } -} - -static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { - struct stream_priv_s* p = (struct stream_priv_s*)opts; - char *filename; - dvdnav_priv_t *priv; - - if(p->device) filename = p->device; - else if(dvd_device) filename= dvd_device; - else filename = DEFAULT_DVD_DEVICE; - if(!(priv=new_dvdnav_stream(filename))) { - mp_tmsg(MSGT_OPEN,MSGL_ERR,"Couldn't open DVD device: %s (%s)\n",filename, strerror(errno)); - return STREAM_UNSUPPORTED; - } - - if(p->track > 0) { - priv->title = p->track; - if(dvdnav_title_play(priv->dvdnav, p->track) != DVDNAV_STATUS_OK) { - mp_msg(MSGT_OPEN,MSGL_FATAL,"dvdnav_stream, couldn't select title %d, error '%s'\n", p->track, dvdnav_err_to_string(priv->dvdnav)); - return STREAM_UNSUPPORTED; - } - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_DVD_CURRENT_TITLE=%d\n", p->track); - } else if (p->track == 0) { - if(dvdnav_menu_call(priv->dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK) - dvdnav_menu_call(priv->dvdnav, DVD_MENU_Title); - } - if(mp_msg_test(MSGT_IDENTIFY, MSGL_INFO)) - identify(priv, p); - if(p->track > 0) - show_audio_subs_languages(priv->dvdnav); - if(dvd_angle > 1) - dvdnav_angle_change(priv->dvdnav, dvd_angle); - - stream->sector_size = 2048; - stream->flags = STREAM_READ | MP_STREAM_SEEK; - stream->fill_buffer = fill_buffer; - stream->seek = seek; - stream->control = control; - stream->close = stream_dvdnav_close; - stream->type = STREAMTYPE_DVDNAV; - stream->priv=(void*)priv; - *file_format = DEMUXER_TYPE_MPEG_PS; - - update_title_len(stream); - if(!stream->pos && p->track > 0) - mp_msg(MSGT_OPEN,MSGL_ERR, "INIT ERROR: couldn't get init pos %s\r\n", dvdnav_err_to_string(priv->dvdnav)); - - mp_msg(MSGT_OPEN,MSGL_INFO, "Remember to disable MPlayer's cache when playing dvdnav:// streams (adding -nocache to your command line)\r\n"); - - return STREAM_OK; -} - - -void mp_dvdnav_handle_input(stream_t *stream, int cmd, int *button) { - dvdnav_priv_t * priv = stream->priv; - dvdnav_t *nav = priv->dvdnav; - dvdnav_status_t status=DVDNAV_STATUS_ERR; - pci_t *pci = dvdnav_get_current_nav_pci(nav); - - if(cmd != MP_CMD_DVDNAV_SELECT && !pci) - return; - - switch(cmd) { - case MP_CMD_DVDNAV_UP: - status = dvdnav_upper_button_select(nav, pci); - break; - case MP_CMD_DVDNAV_DOWN: - status = dvdnav_lower_button_select(nav, pci); - break; - case MP_CMD_DVDNAV_LEFT: - status = dvdnav_left_button_select(nav, pci); - break; - case MP_CMD_DVDNAV_RIGHT: - status = dvdnav_right_button_select(nav, pci); - break; - case MP_CMD_DVDNAV_MENU: - status = dvdnav_menu_call(nav,DVD_MENU_Root); - break; - case MP_CMD_DVDNAV_PREVMENU: { - int title=0, part=0; - - dvdnav_current_title_info(nav, &title, &part); - if(title) { - if((status=dvdnav_menu_call(nav, DVD_MENU_Part)) == DVDNAV_STATUS_OK) - break; - } - if((status=dvdnav_menu_call(nav, DVD_MENU_Title)) == DVDNAV_STATUS_OK) - break; - status=dvdnav_menu_call(nav, DVD_MENU_Root); - } - break; - case MP_CMD_DVDNAV_SELECT: - status = dvdnav_button_activate(nav, pci); - break; - case MP_CMD_DVDNAV_MOUSECLICK: - /* - this is a workaround: in theory the simple dvdnav_lower_button_select()+dvdnav_button_activate() - should be enough (and generally it is), but there are cases when the calls to dvdnav_lower_button_select() - and friends fail! Hence we have to call dvdnav_mouse_activate(priv->mousex, priv->mousey) with - the coodinates saved by mp_dvdnav_update_mouse_pos(). - This last call always works well - */ - status = dvdnav_mouse_activate(nav, pci, priv->mousex, priv->mousey); - break; - default: - mp_msg(MSGT_CPLAYER, MSGL_V, "Unknown DVDNAV cmd %d\n", cmd); - break; - } - - if(status == DVDNAV_STATUS_OK) - dvdnav_get_current_highlight(nav, button); -} - -void mp_dvdnav_update_mouse_pos(stream_t *stream, int32_t x, int32_t y, int* button) { - dvdnav_priv_t * priv = stream->priv; - dvdnav_t *nav = priv->dvdnav; - dvdnav_status_t status; - pci_t *pci = dvdnav_get_current_nav_pci(nav); - - if(!pci) return; - - status = dvdnav_mouse_select(nav, pci, x, y); - if(status == DVDNAV_STATUS_OK) dvdnav_get_current_highlight(nav, button); - else *button = -1; - priv->mousex = x; - priv->mousey = y; -} - -static int mp_dvdnav_get_aid_from_format (stream_t *stream, int index, uint8_t lg) { - dvdnav_priv_t * priv = stream->priv; - uint8_t format; - - format = dvdnav_audio_stream_format(priv->dvdnav, lg); - switch(format) { - case DVDNAV_FORMAT_AC3: - return index + 128; - case DVDNAV_FORMAT_DTS: - return index + 136; - case DVDNAV_FORMAT_LPCM: - return index + 160; - case DVDNAV_FORMAT_MPEGAUDIO: - return index; - default: - return -1; - } - - return -1; -} - -/** - * \brief mp_dvdnav_aid_from_lang() returns the audio id corresponding to the language code 'lang' - * \param stream: - stream pointer - * \param lang: 2-characters language code[s], eventually separated by spaces of commas - * \return -1 on error, current subtitle id if successful - */ -int mp_dvdnav_aid_from_lang(stream_t *stream, char **language) { - dvdnav_priv_t * priv = stream->priv; - int k; - uint8_t lg; - uint16_t lang, lcode; - - for (int i = 0; language[i]; i++) { - lcode = (language[i][0] << 8) | (language[i][1]); - for(k=0; k<32; k++) { - lg = dvdnav_get_audio_logical_stream(priv->dvdnav, k); - if(lg == 0xff) continue; - lang = dvdnav_audio_stream_to_lang(priv->dvdnav, lg); - if(lang != 0xFFFF && lang == lcode) - return mp_dvdnav_get_aid_from_format (stream, k, lg); - } - } - return -1; -} - -/** - * \brief mp_dvdnav_lang_from_aid() returns the language corresponding to audio id 'aid' - * \param stream: - stream pointer - * \param sid: physical subtitle id - * \return 0 on error, otherwise language id - */ -static int mp_dvdnav_lang_from_aid(stream_t *stream, int aid) { - uint8_t lg; - uint16_t lang; - dvdnav_priv_t * priv = stream->priv; - - if(aid < 0) - return 0; - lg = dvdnav_get_audio_logical_stream(priv->dvdnav, aid & 0x7); - if(lg == 0xff) return 0; - lang = dvdnav_audio_stream_to_lang(priv->dvdnav, lg); - if(lang == 0xffff) return 0; - return lang; -} - - -/** - * \brief mp_dvdnav_sid_from_lang() returns the subtitle id corresponding to the language code 'lang' - * \param stream: - stream pointer - * \param lang: 2-characters language code[s], eventually separated by spaces of commas - * \return -1 on error, current subtitle id if successful - */ -int mp_dvdnav_sid_from_lang(stream_t *stream, char **language) { - dvdnav_priv_t * priv = stream->priv; - uint8_t lg, k; - uint16_t lang, lcode; - - for (int i = 0; language[i]; i++) { - lcode = (language[i][0] << 8) | (language[i][1]); - for(k=0; k<32; k++) { - lg = dvdnav_get_spu_logical_stream(priv->dvdnav, k); - if(lg == 0xff) continue; - lang = dvdnav_spu_stream_to_lang(priv->dvdnav, k); - if(lang != 0xFFFF && lang == lcode) { - return lg; - } - } - } - return -1; -} - -/** - * \brief mp_dvdnav_lang_from_sid() returns the language corresponding to subtitle id 'sid' - * \param stream: - stream pointer - * \param sid: physical subtitle id - * \return 0 on error, otherwise language id - */ -static int mp_dvdnav_lang_from_sid(stream_t *stream, int sid) { - uint8_t k; - uint16_t lang; - dvdnav_priv_t *priv = stream->priv; - if(sid < 0) return 0; - for (k=0; k<32; k++) - if (dvdnav_get_spu_logical_stream(priv->dvdnav, k) == sid) - break; - if (k == 32) - return 0; - lang = dvdnav_spu_stream_to_lang(priv->dvdnav, k); - if(lang == 0xffff) return 0; - return lang; -} - -/** - * \brief mp_dvdnav_number_of_subs() returns the count of available subtitles - * \param stream: - stream pointer - * \return 0 on error, something meaningful otherwise - */ -int mp_dvdnav_number_of_subs(stream_t *stream) { - dvdnav_priv_t * priv = stream->priv; - uint8_t lg, k, n=0; - - if (priv->state & NAV_FLAG_VTS_DOMAIN) return 0; - for(k=0; k<32; k++) { - lg = dvdnav_get_spu_logical_stream(priv->dvdnav, k); - if(lg == 0xff) continue; - if(lg >= n) n = lg + 1; - } - return n; -} - -/** - * \brief mp_dvdnav_get_spu_clut() returns the spu clut - * \param stream: - stream pointer - * \return spu clut pointer - */ -unsigned int *mp_dvdnav_get_spu_clut(stream_t *stream) { - dvdnav_priv_t *priv = stream->priv; - return (priv->state & NAV_FLAG_SPU_SET) ? priv->spu_clut : NULL; -} - -/** - * \brief mp_dvdnav_get_highlight() get dvdnav highlight struct - * \param stream: - stream pointer - * \param hl : - highlight struct pointer - */ -void mp_dvdnav_get_highlight (stream_t *stream, nav_highlight_t *hl) { - dvdnav_priv_t *priv = stream->priv; - dvdnav_highlight_event_t hlev = priv->hlev; - - hl->sx = hlev.sx; - hl->sy = hlev.sy; - hl->ex = hlev.ex; - hl->ey = hlev.ey; - hl->palette = hlev.palette; -} - -void mp_dvdnav_switch_title (stream_t *stream, int title) { - dvdnav_priv_t *priv = stream->priv; - uint32_t titles; - - dvdnav_get_number_of_titles (priv->dvdnav, &titles); - if (title > 0 && title <= titles) - dvdnav_title_play (priv->dvdnav, title); -} - -/** - * \brief Check if end of stream has been reached - * \param stream: - stream pointer - * \return 1 on really eof - */ -int mp_dvdnav_is_eof (stream_t *stream) { - return ((dvdnav_priv_t *) stream->priv)->state & NAV_FLAG_EOF; -} - -/** - * \brief Skip still frame - * \param stream: - stream pointer - * \return 0 on success - */ -int mp_dvdnav_skip_still (stream_t *stream) { - dvdnav_p