[SCM] libbluray/master: Merge branch 'upstream'
ceros-guest at users.alioth.debian.org
ceros-guest at users.alioth.debian.org
Mon Jul 18 00:36:42 UTC 2011
Imported Upstream version 0.0~git20110717.3477b65
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Git-Refname: refs/heads/master
X-Git-Reftype: branch
X-Git-Oldrev: 5fd5314c12fd74e743efefb50752eaf5f321ce33
X-Git-Newrev: 541638fdd458c41ec711afe632b48bc051d1e35c
The following commit has been merged in the master branch:
commit 399bed314566bab2e90f9fddc0f14731092a9411
Merge: 2b6e11f2819a78841ac7198261cebe16526504c1 ddd1a206f1c24c128124e6a3e2992fba855b7da3
Author: Andres Mejia <mcitadel at gmail.com>
Date: Sun Jul 17 20:33:08 2011 -0400
Merge branch 'upstream'
diff --combined configure
index 2cb7b2d,98d4581..7ec2c45
--- a/configure
+++ b/configure
@@@ -11585,7 -11585,7 +11585,7 @@@ f
done
-for ac_header in stdlib.h mntent.h linux/cdrom.h inttypes.h strings.h
+for ac_header in stdlib.h mntent.h linux/cdrom.h inttypes.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@@ -12128,7 -12128,8 +12128,8 @@@ $as_echo "#define DLOPEN_CRYPTO_LIBS 1
fi
elif [ $use_dlopen_crypto_libs = "yes" ]; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+ if test "${SYS}" != "mingw32" ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
$as_echo_n "checking for dlopen in -ldl... " >&6; }
if ${ac_cv_lib_dl_dlopen+:} false; then :
$as_echo_n "(cached) " >&6
@@@ -12174,6 -12175,11 +12175,11 @@@ els
as_fn_error $? "$library_not_found" "$LINENO" 5
fi
+ else
+
+ $as_echo "#define DLOPEN_CRYPTO_LIBS 1" >>confdefs.h
+
+ fi
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for aacs_open in -laacs" >&5
$as_echo_n "checking for aacs_open in -laacs... " >&6; }
diff --combined configure.ac
index 97b4a2c,316ad47..525a31d
--- a/configure.ac
+++ b/configure.ac
@@@ -97,7 -97,7 +97,7 @@@ AC_TYPE_SIGNA
# required headers
AC_CHECK_HEADERS([stdarg.h sys/types.h dirent.h errno.h libgen.h malloc.h])
-AC_CHECK_HEADERS([stdlib.h mntent.h linux/cdrom.h inttypes.h strings.h])
+AC_CHECK_HEADERS([stdlib.h mntent.h linux/cdrom.h inttypes.h])
AC_CHECK_HEADERS([sys/time.h time.h])
if test "${SYS}" != "mingw32" ; then
AC_CHECK_HEADERS(pthread.h,, [AC_MSG_ERROR([pthread.h required])])
@@@ -129,10 -129,14 +129,14 @@@ if [[ $use_dlopen_crypto_libs = "auto"
AC_DEFINE([DLOPEN_CRYPTO_LIBS], [1], ["Define to 1 if dlopening crypto libs"])
fi
elif [[ $use_dlopen_crypto_libs = "yes" ]]; then
- AC_CHECK_LIB([dl], [dlopen],
- [DLOPEN_LDFLAGS="-ldl"; AC_MSG_NOTICE($using_dlopen_crypto_libs)
- AC_DEFINE([DLOPEN_CRYPTO_LIBS], [1], ["Define to 1 if dlopening crypto libs"])],
- [AC_MSG_ERROR($library_not_found)])
+ if test "${SYS}" != "mingw32" ; then
+ AC_CHECK_LIB([dl], [dlopen],
+ [DLOPEN_LDFLAGS="-ldl"; AC_MSG_NOTICE($using_dlopen_crypto_libs)
+ AC_DEFINE([DLOPEN_CRYPTO_LIBS], [1], ["Define to 1 if dlopening crypto libs"])],
+ [AC_MSG_ERROR($library_not_found)])
+ else
+ AC_DEFINE([DLOPEN_CRYPTO_LIBS], [1], ["Define to 1 if dlopening crypto libs"])
+ fi
else
AC_CHECK_LIB([aacs], [aacs_open],,
[AC_MSG_ERROR($library_not_found)])
diff --combined player_wrappers/xine/input_bluray.c
index 4088b50,21f5009..9e13cfc
--- a/player_wrappers/xine/input_bluray.c
+++ b/player_wrappers/xine/input_bluray.c
@@@ -38,6 -38,7 +38,6 @@@
#include <string.h>
#include <errno.h>
#include <dlfcn.h>
-#include <pthread.h>
#include <libbluray/bluray.h>
#include <libbluray/keys.h>
@@@ -51,7 -52,7 +51,7 @@@
#define LOGMSG(x...) xine_log (this->stream->xine, XINE_LOG_MSG, "input_bluray: " x);
-#define XINE_ENGINE_INTERNAL // stream->demux_plugin
+#define XINE_ENGINE_INTERNAL
#ifdef HAVE_CONFIG_H
# include "xine_internal.h"
@@@ -80,6 -81,8 +80,8 @@@
#define PKT_SIZE 192
#define TICKS_IN_MS 45
+ #define MIN_TITLE_LENGTH 180
+
typedef struct {
input_class_t input_class;
@@@ -99,7 -102,7 +101,7 @@@ typedef struct
xine_stream_t *stream;
xine_event_queue_t *event_queue;
- xine_osd_t *osd;
+ xine_osd_t *osd[2];
bluray_input_class_t *class;
@@@ -117,122 -120,153 +119,142 @@@
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;
- int current_clip;
+ 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 error;
int menu_open;
+ int stream_flushed;
int pg_enable;
int pg_stream;
+ int mouse_inside_button;
uint32_t cap_seekable;
uint8_t nav_mode;
} bluray_input_plugin_t;
- static void close_overlay(bluray_input_plugin_t *this)
+ static void send_num_buttons(bluray_input_plugin_t *this, int n)
{
- if (this->osd) {
- xine_osd_free(this->osd);
- this->osd = NULL;
+ 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 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 overlay_proc(void *this_gen, const BD_OVERLAY * const ov)
{
bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+ uint32_t color[256];
+ uint8_t trans[256];
unsigned i;
if (!this) {
return;
}
- if (!ov || ov->plane == 1)
- this->menu_open = 0;
-
- if (!ov || !ov->img) {
+ if (!ov) {
/* hide OSD */
- close_overlay(this);
+ close_overlay(this, -1);
+ return;
+ }
+
+ if (ov->plane > 1) {
return;
}
/* open xine OSD */
- if (!this->osd) {
- this->osd = xine_osd_new(this->stream, 0, 0, 1920, 1080);
+ if (!this->osd[ov->plane]) {
+ this->osd[ov->plane] = xine_osd_new(this->stream, 0, 0, 1920, 1080);
}
- if (!this->pg_enable)
+ xine_osd_t *osd = this->osd[ov->plane];
+ if (!this->pg_enable) {
_x_select_spu_channel(this->stream, -1);
- }
/* 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;
- }
- 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_set_palette(this->osd, color, trans);
- /* uncompress and draw bitmap */
+ xine_osd_draw_bitmap(osd, img, ov->x, ov->y, ov->w, ov->h, NULL);
- free(img);
+ const BD_PG_RLE_ELEM *rlep = ov->img;
+ uint8_t *img = malloc(ov->w * ov->h);
+ unsigned pixels = ov->w * ov->h;
- } else {
+ for (i = 0; i < pixels; i += rlep->len, rlep++) {
+ memset(img + i, rlep->color, rlep->len);
+ }
- xine_osd_draw_bitmap(this->osd, img, ov->x, ov->y, ov->w, ov->h, NULL);
+ if (ov->x == 0 && ov->y == 0 && ov->w == 1920 && ov->h == 1080) {
+ /* Nothing to display, close OSD */
+ close_overlay(this, ov->plane);
+ return;
+ }
- free(img);
+ /* wipe rect */
+ xine_osd_draw_rect(osd, ov->x, ov->y, ov->x + ov->w - 1, ov->y + ov->h - 1, 0xff, 1);
+ }
/* display */
- xine_osd_show(this->osd, 0);
+ xine_osd_show(osd, 0);
- if (ov->plane == 1)
+ if (ov->plane == 1) {
this->menu_open = 1;
+ send_num_buttons(this, 1);
+ }
}
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);
- }
+ /* 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_info(bluray_input_plugin_t *this, int playlist_id)
+ static void update_title_name(bluray_input_plugin_t *this)
{
- 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);
- else
- this->title_info = bd_get_playlist_info(this->bdh, playlist_id);
-
- if (!this->title_info) {
- LOGMSG("bd_get_title_info(%d) failed\n", this->current_title_idx);
- return;
- }
-
- /* set title */
-
+ char title_name[64] = "";
xine_ui_data_t udata;
- xine_event_t uevent = {
- .type = XINE_EVENT_UI_SET_TITLE,
- .stream = this->stream,
- .data = &udata,
+ xine_event_t uevent = {
+ .type = XINE_EVENT_UI_SET_TITLE,
+ .stream = this->stream,
+ .data = &udata,
.data_length = sizeof(udata)
};
- char title_name[64] = "";
-
+ /* check disc library metadata */
if (this->meta_dl) {
unsigned i;
for (i = 0; i < this->meta_dl->toc_count; i++)
@@@ -242,6 -276,7 +264,7 @@@
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");
@@@ -256,6 -291,7 +279,7 @@@
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);
@@@ -263,10 -299,33 +287,33 @@@
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;
+ }
+
/* calculate and set stream rate */
uint64_t rate = bd_get_title_size(this->bdh) * UINT64_C(8) // bits
@@@ -276,10 -335,18 +323,18 @@@
/* set stream info */
- _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);
+ 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 */
+ update_title_name(this);
}
static int open_title (bluray_input_plugin_t *this, int title_idx)
@@@ -296,6 -363,27 +351,27 @@@
return 1;
}
+ #ifndef DEMUX_OPTIONAL_DATA_FLUSH
+ # define DEMUX_OPTIONAL_DATA_FLUSH 0x10000
+ #endif
+
+ static void stream_flush(bluray_input_plugin_t *this)
+ {
+ if (this->stream_flushed)
+ return;
+
+ lprintf("Stream flush\n");
+
+ this->stream_flushed = 1;
+
+ int tmp = 0;
+ if (DEMUX_OPTIONAL_SUCCESS !=
+ this->stream->demux_plugin->get_optional_data(this->stream->demux_plugin, &tmp, DEMUX_OPTIONAL_DATA_FLUSH)) {
+ LOGMSG("stream flush not supported by the demuxer !\n");
+ return;
+ }
+ }
+
static void stream_reset(bluray_input_plugin_t *this)
{
if (!this || !this->stream || !this->stream->demux_plugin)
@@@ -305,7 -393,7 +381,7 @@@
this->cap_seekable = 0;
- _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL);
+ xine_set_param(this->stream, XINE_PARAM_FINE_SPEED, XINE_FINE_SPEED_NORMAL);
this->stream->demux_plugin->seek(this->stream->demux_plugin, 0, 0, 1);
_x_demux_control_start(this->stream);
@@@ -314,34 -402,28 +390,28 @@@
static void wait_secs(bluray_input_plugin_t *this, unsigned seconds)
{
- // infinite still mode ?
- if (!seconds) {
- xine_usec_sleep(10*1000);
- return;
- }
-
- // clip to allowed range
- if (seconds > 300) {
- seconds = 300;
+ 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;
+ }
}
- // pause the stream
- int paused = _x_get_fine_speed(this->stream) == XINE_SPEED_PAUSE;
- if (!paused) {
- _x_set_fine_speed(this->stream, XINE_SPEED_PAUSE);
- }
+ else if (seconds) {
+ if (seconds > 300) {
+ seconds = 300;
+ }
- // wait until interrupted
- int loops = seconds * 25; /* N * 40 ms */
- while (!this->stream->demux_action_pending && loops-- > 0) {
- xine_usec_sleep(40*1000);
+ lprintf("still image, pause for %d seconds\n", seconds);
+ this->still_end_time = time(NULL) + seconds;
}
- lprintf("paused for %d seconds (%d ms left)\n", seconds - loops/25, loops * 40);
-
- if (!paused) {
- _x_set_fine_speed(this->stream, XINE_FINE_SPEED_NORMAL);
- }
+ xine_usec_sleep(40*1000);
}
static void update_spu_channel(bluray_input_plugin_t *this, int channel)
@@@ -387,6 -469,7 +457,7 @@@ static void handle_libbluray_event(blur
case BD_EVENT_SEEK:
lprintf("BD_EVENT_SEEK\n");
+ this->still_end_time = 0;
stream_reset(this);
break;
@@@ -413,6 -496,11 +484,11 @@@
_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);
+ break;
+
case BD_EVENT_TITLE:
this->current_title = ev.param;
break;
@@@ -427,10 -515,8 +503,8 @@@
case BD_EVENT_PLAYITEM:
lprintf("BD_EVENT_PLAYITEM %d\n", ev.param);
- if (ev.param < this->title_info->clip_count)
- this->current_clip = ev.param;
- else
- this->current_clip = 0;
+ this->current_clip = ev.param;
+ this->still_end_time = 0;
break;
case BD_EVENT_CHAPTER:
@@@ -470,6 -556,7 +544,7 @@@
break;
default:
+ LOGMSG("unhandled libbluray event %d [param %d]\n", ev.event, ev.param);
break;
}
}
@@@ -484,6 -571,25 +559,25 @@@ static void handle_libbluray_events(blu
}
}
+ 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)
{
if (!this->event_queue)
@@@ -515,6 -621,7 +609,7 @@@
} else {
bd_play_title(this->bdh, MAX(1, this->current_title - 1));
}
+ stream_reset(this);
break;
case XINE_EVENT_INPUT_RIGHT:
@@@ -524,6 -631,7 +619,7 @@@
} else {
bd_play_title(this->bdh, MIN(this->num_titles, this->current_title + 1));
}
+ stream_reset(this);
break;
}
}
@@@ -536,13 -644,18 +632,18 @@@
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;
- bd_mouse_select(this->bdh, pts, input->x, input->y);
+ 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;
}
@@@ -571,37 -684,42 +672,42 @@@
case XINE_EVENT_INPUT_NUMBER_9: bd_user_input(this->bdh, pts, BD_VK_9); break;
case XINE_EVENT_INPUT_NEXT: {
- unsigned chapter = bd_get_current_chapter(this->bdh) + 1;
-
- lprintf("XINE_EVENT_INPUT_NEXT: next chapter\n");
-
- if (chapter >= this->title_info->chapter_count) {
- if (this->current_title_idx < this->num_title_idx - 1) {
- open_title(this, this->current_title_idx + 1);
- stream_reset(this);
- }
- } else {
- bd_seek_chapter(this->bdh, chapter);
- update_stream_info(this);
- stream_reset(this);
+ 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: {
- int chapter = bd_get_current_chapter(this->bdh) - 1;
-
- lprintf("XINE_EVENT_INPUT_PREVIOUS: previous chapter\n");
-
- if (chapter < 0 && this->current_title_idx > 0) {
- open_title(this, this->current_title_idx - 1);
- stream_reset(this);
- } else {
- chapter = MAX(0, chapter);
- bd_seek_chapter(this->bdh, chapter);
- update_stream_info(this);
- stream_reset(this);
+ 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;
}
@@@ -638,7 -756,8 +744,8 @@@ static uint32_t bluray_plugin_get_capab
return this->cap_seekable |
INPUT_CAP_BLOCK |
INPUT_CAP_AUDIOLANG |
- INPUT_CAP_SPULANG;
+ INPUT_CAP_SPULANG |
+ INPUT_CAP_CHAPTERS;
}
#if XINE_VERSION_CODE >= 10190
@@@ -663,7 -782,7 +770,7 @@@ static off_t bluray_plugin_read (input_
if (result == 0) {
handle_events(this);
if (ev.event == BD_EVENT_NONE) {
- if (_x_action_pending(this->stream)) {
+ if (this->stream->demux_action_pending) {
break;
}
}
@@@ -677,6 -796,8 +784,8 @@@
if (result < 0)
LOGMSG("bd_read() failed: %s (%d of %d)\n", strerror(errno), (int)result, (int)len);
+ this->stream_flushed = 0;
+
return result;
}
@@@ -713,7 -834,7 +822,7 @@@ static off_t bluray_plugin_seek (input_
if (!this || !this->bdh)
return -1;
- if (this->current_title_idx < 0)
+ if (this->still_end_time)
return offset;
/* convert relative seeks to absolute */
@@@ -737,20 -858,33 +846,23 @@@ static off_t bluray_plugin_seek_time (i
{
bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
- if (!this || !this->bdh)
+ if (!this || !this->bdh || !this->title_info)
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);
@@@ -793,12 -927,9 +905,12 @@@ static const char* bluray_plugin_get_mr
return this->mrl;
}
-static int get_optional_data_impl (bluray_input_plugin_t *this, void *data, int data_type)
+static int bluray_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type)
{
- unsigned int current_clip = this->current_clip;
+ bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen;
+
+ if (!this || !this->stream || !data)
+ return INPUT_OPTIONAL_UNSUPPORTED;
switch (data_type) {
case INPUT_OPTIONAL_DATA_DEMUXER:
@@@ -810,9 -941,9 +922,9 @@@
* - channel number can be mpeg-ts PID (0x1100 ... 0x11ff)
*/
case INPUT_OPTIONAL_DATA_AUDIOLANG:
- if (this->title_info && this->title_info->clip_count < current_clip) {
+ if (this->title_info) {
int channel = *((int *)data);
- BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip];
+ BLURAY_CLIP_INFO *clip = &this->title_info->clips[this->current_clip];
if (channel >= 0 && channel < clip->audio_stream_count) {
memcpy(data, clip->audio_streams[channel].lang, 4);
@@@ -840,9 -971,9 +952,9 @@@
* - channel number can be mpeg-ts PID (0x1200 ... 0x12ff)
*/
case INPUT_OPTIONAL_DATA_SPULANG:
- if (this->title_info && this->title_info->clip_count < current_clip) {
+ if (this->title_info) {
int channel = *((int *)data);
- BLURAY_CLIP_INFO *clip = &this->title_info->clips[current_clip];
+ BLURAY_CLIP_INFO *clip = &this->title_info->clips[this->current_clip];
if (channel >= 0 && channel < clip->pg_stream_count) {
memcpy(data, clip->pg_streams[channel].lang, 4);
@@@ -872,6 -1003,20 +984,6 @@@
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;
@@@ -879,13 -1024,18 +991,13 @@@
if (this->bdh)
bd_register_overlay_proc(this->bdh, NULL, NULL);
- close_overlay(this);
+ 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);
@@@ -1044,7 -1194,7 +1156,7 @@@ static int bluray_plugin_open (input_pl
/* load title list */
- this->num_title_idx = bd_get_titles(this->bdh, TITLES_RELEVANT);
+ 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)
@@@ -1057,7 -1207,7 +1169,7 @@@
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);
+ BLURAY_TITLE_INFO *info = bd_get_title_info(this->bdh, i);
if (info->duration > duration) {
title = i;
duration = info->duration;
@@@ -1077,9 -1227,8 +1189,8 @@@
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 eq */
- BD_EVENT ev;
- bd_get_event(this->bdh, &ev);
+ /* init event queue */
+ bd_get_event(this->bdh, NULL);
/* get disc name */
@@@ -1166,6 -1315,8 +1277,6 @@@ static input_plugin_t *bluray_class_get
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;
@@@ -1262,6 -1413,8 +1373,8 @@@ static void *bluray_init_plugin (xine_
{
(void)data;
+ static char *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));
@@@ -1318,6 -1471,14 +1431,14 @@@
"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;
}
diff --combined src/libbluray/bluray.c
index 38d1ee1,4e2fce3..8f627ee
--- a/src/libbluray/bluray.c
+++ b/src/libbluray/bluray.c
@@@ -28,6 -28,7 +28,7 @@@
#include "util/macro.h"
#include "util/logging.h"
#include "util/strutl.h"
+ #include "util/mutex.h"
#include "bdnav/navigation.h"
#include "bdnav/index_parse.h"
#include "bdnav/meta_parse.h"
@@@ -56,6 -57,7 +57,7 @@@ typedef void* (*fptr_p_void)()
#define MAX_EVENTS 31 /* 2^n - 1 */
typedef struct bd_event_queue_s {
+ BD_MUTEX mutex;
unsigned in; /* next free slot */
unsigned out; /* next event */
BD_EVENT ev[MAX_EVENTS+1];
@@@ -78,6 -80,8 +80,6 @@@ typedef struct
/* current aligned unit */
uint16_t int_buf_off;
- BD_UO_MASK uo_mask;
-
} BD_STREAM;
typedef struct {
@@@ -168,8 -172,21 +170,21 @@@ static void _init_event_queue(BLURAY *b
{
if (!bd->event_queue) {
bd->event_queue = calloc(1, sizeof(struct bd_event_queue_s));
+ bd_mutex_init(&bd->event_queue->mutex);
} else {
- memset(bd->event_queue, 0, sizeof(struct bd_event_queue_s));
+ bd_mutex_lock(&bd->event_queue->mutex);
+ bd->event_queue->in = 0;
+ bd->event_queue->out = 0;
+ memset(bd->event_queue->ev, 0, sizeof(bd->event_queue->ev));
+ bd_mutex_unlock(&bd->event_queue->mutex);
+ }
+ }
+
+ static void _free_event_queue(BLURAY *bd)
+ {
+ if (bd->event_queue) {
+ bd_mutex_destroy(&bd->event_queue->mutex);
+ X_FREE(bd->event_queue);
}
}
@@@ -178,11 -195,18 +193,18 @@@ static int _get_event(BLURAY *bd, BD_EV
struct bd_event_queue_s *eq = bd->event_queue;
if (eq) {
+ bd_mutex_lock(&eq->mutex);
+
if (eq->in != eq->out) {
+
*ev = eq->ev[eq->out];
eq->out = (eq->out + 1) & MAX_EVENTS;
+
+ bd_mutex_unlock(&eq->mutex);
return 1;
}
+
+ bd_mutex_unlock(&eq->mutex);
}
ev->event = BD_EVENT_NONE;
@@@ -195,14 -219,20 +217,20 @@@ static int _queue_event(BLURAY *bd, BD_
struct bd_event_queue_s *eq = bd->event_queue;
if (eq) {
+ bd_mutex_lock(&eq->mutex);
+
unsigned new_in = (eq->in + 1) & MAX_EVENTS;
if (new_in != eq->out) {
eq->ev[eq->in] = ev;
eq->in = new_in;
+
+ bd_mutex_unlock(&eq->mutex);
return 1;
}
+ bd_mutex_unlock(&eq->mutex);
+
BD_DEBUG(DBG_BLURAY|DBG_CRIT, "_queue_event(%d, %d): queue overflow !\n", ev.event, ev.param);
}
@@@ -295,6 -325,9 +323,6 @@@ static void _close_m2ts(BD_STREAM *st
file_close(st->fp);
st->fp = NULL;
}
-
- /* reset UO mask */
- memset(&st->uo_mask, 0, sizeof(st->uo_mask));
}
static int _open_m2ts(BLURAY *bd, BD_STREAM *st)
@@@ -328,6 -361,10 +356,6 @@@
}
if (st == &bd->st0) {
- MPLS_PL *pl = st->clip->title->pl;
- st->uo_mask = bd_uo_mask_combine(pl->app_info.uo_mask,
- pl->play_item[st->clip->ref].uo_mask);
-
_update_clip_psrs(bd, st->clip);
}
@@@ -738,7 -775,8 +766,7 @@@ static int _libbdplus_open(BLURAY *bd,
return 0;
}
- const uint8_t *aacs_vid = (const uint8_t *)_libaacs_get_vid(bd);
- bd->bdplus = bd->bdplus_init(bd->device_path, keyfile_path, aacs_vid ? aacs_vid : vid);
+ bd->bdplus = bd->bdplus_init(bd->device_path, keyfile_path, _libaacs_get_vid(bd) ?: vid);
if (bd->bdplus) {
BD_DEBUG(DBG_BLURAY,"libbdplus initialized\n");
@@@ -887,7 -925,7 +915,7 @@@ void bd_close(BLURAY *bd
indx_free(&bd->index);
bd_registers_free(bd->regs);
- X_FREE(bd->event_queue);
+ _free_event_queue(bd);
X_FREE(bd->device_path);
BD_DEBUG(DBG_BLURAY, "BLURAY destroyed! (%p)\n", bd);
@@@ -1163,7 -1201,10 +1191,7 @@@ int bd_read(BLURAY *bd, unsigned char *
return 0;
}
if (pi->still_mode == BLURAY_STILL_TIME) {
- if (bd->event_queue) {
- _queue_event(bd, (BD_EVENT){BD_EVENT_STILL_TIME, pi->still_time});
- return 0;
- }
+ _queue_event(bd, (BD_EVENT){BD_EVENT_STILL_TIME, pi->still_time});
}
// find next clip
@@@ -1176,14 -1217,6 +1204,14 @@@
if (!_open_m2ts(bd, st)) {
return -1;
}
+
+ // timed still mode: allow application to process BD_EVENT_STILL_TIME.
+ // next bd_read() will return new data.
+ if (bd->event_queue) {
+ if (pi->still_mode == BLURAY_STILL_TIME) {
+ return 0;
+ }
+ }
}
if (_read_block(bd, st, bd->int_buf)) {
@@@ -1221,6 -1254,24 +1249,6 @@@
return -1;
}
-int bd_read_skip_still(BLURAY *bd)
-{
- BD_STREAM *st = &bd->st0;
-
- if (st->clip) {
- MPLS_PI *pi = &st->clip->title->pl->play_item[st->clip->ref];
-
- if (pi->still_mode == BLURAY_STILL_TIME) {
- st->clip = nav_next_clip(bd->title, st->clip);
- if (st->clip) {
- return _open_m2ts(bd, st);
- }
- }
- }
-
- return 0;
-}
-
/*
* preloader for asynchronous sub paths
*/
@@@ -1299,11 -1350,11 +1327,11 @@@ static void _close_playlist(BLURAY *bd
}
}
-static int _open_playlist(BLURAY *bd, const char *f_name, unsigned angle)
+static int _open_playlist(BLURAY *bd, const char *f_name)
{
_close_playlist(bd);
- bd->title = nav_title_open(bd->device_path, f_name, angle);
+ bd->title = nav_title_open(bd->device_path, f_name);
if (bd->title == NULL) {
BD_DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (%p)\n",
f_name, bd);
@@@ -1347,7 -1398,7 +1375,7 @@@ int bd_select_playlist(BLURAY *bd, uint
}
}
- result = _open_playlist(bd, f_name, 0);
+ result = _open_playlist(bd, f_name);
X_FREE(f_name);
return result;
@@@ -1373,7 -1424,7 +1401,7 @@@ int bd_select_title(BLURAY *bd, uint32_
bd->title_idx = title_idx;
f_name = bd->title_list->title_info[title_idx].name;
- return _open_playlist(bd, f_name, 0);
+ return _open_playlist(bd, f_name);
}
uint32_t bd_get_current_title(BLURAY *bd)
@@@ -1432,7 -1483,7 +1460,7 @@@ void bd_seamless_angle_change(BLURAY *b
* title lists
*/
-uint32_t bd_get_titles(BLURAY *bd, uint8_t flags, uint32_t min_title_length)
+uint32_t bd_get_titles(BLURAY *bd, uint8_t flags)
{
if (!bd) {
BD_DEBUG(DBG_BLURAY | DBG_CRIT, "bd_get_titles(NULL) failed (%p)\n", bd);
@@@ -1442,7 -1493,7 +1470,7 @@@
if (bd->title_list != NULL) {
nav_free_title_list(bd->title_list);
}
- bd->title_list = nav_get_title_list(bd->device_path, flags, min_title_length);
+ bd->title_list = nav_get_title_list(bd->device_path, flags);
if (!bd->title_list) {
BD_DEBUG(DBG_BLURAY | DBG_CRIT, "nav_get_title_list(%s) failed (%p)\n", bd->device_path, bd);
@@@ -1518,12 -1569,13 +1546,12 @@@ static BLURAY_TITLE_INFO* _fill_title_i
return title_info;
}
-static BLURAY_TITLE_INFO *_get_title_info(BLURAY *bd, uint32_t title_idx, uint32_t playlist, const char *mpls_name,
- unsigned angle)
+static BLURAY_TITLE_INFO *_get_title_info(BLURAY *bd, uint32_t title_idx, uint32_t playlist, const char *mpls_name)
{
NAV_TITLE *title;
BLURAY_TITLE_INFO *title_info;
- title = nav_title_open(bd->device_path, mpls_name, angle);
+ title = nav_title_open(bd->device_path, mpls_name);
if (title == NULL) {
BD_DEBUG(DBG_BLURAY | DBG_CRIT, "Unable to open title %s! (%p)\n",
mpls_name, bd);
@@@ -1536,7 -1588,7 +1564,7 @@@
return title_info;
}
-BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx, unsigned angle)
+BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx)
{
if (bd->title_list == NULL) {
BD_DEBUG(DBG_BLURAY, "Title list not yet read! (%p)\n", bd);
@@@ -1549,15 -1601,16 +1577,15 @@@
return _get_title_info(bd,
title_idx, bd->title_list->title_info[title_idx].mpls_id,
- bd->title_list->title_info[title_idx].name,
- angle);
+ bd->title_list->title_info[title_idx].name);
}
-BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist, unsigned angle)
+BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist)
{
char *f_name = str_printf("%05d.mpls", playlist);
BLURAY_TITLE_INFO *title_info;
- title_info = _get_title_info(bd, 0, playlist, f_name, angle);
+ title_info = _get_title_info(bd, 0, playlist, f_name);
X_FREE(f_name);
@@@ -1667,24 -1720,78 +1695,78 @@@ void bd_stop_bdj(BLURAY *bd
* Navigation mode interface
*/
+ static void _process_psr_restore_event(BLURAY *bd, BD_PSR_EVENT *ev)
+ {
+ /* PSR restore events are handled internally.
+ * Restore stored playback position.
+ */
+
+ BD_DEBUG(DBG_BLURAY, "PSR restore: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
+
+ switch (ev->psr_idx) {
+ case PSR_ANGLE_NUMBER:
+ /* can't set angle before playlist is opened */
+ return;
+ case PSR_TITLE_NUMBER:
+ /* pass to the application */
+ _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val});
+ return;
+ case PSR_CHAPTER:
+ /* will be selected automatically */
+ return;
+ case PSR_PLAYLIST:
+ bd_select_playlist(bd, ev->new_val);
+ nav_set_angle(bd->title, bd->st0.clip, bd_psr_read(bd->regs, PSR_ANGLE_NUMBER) - 1);
+ return;
+ case PSR_PLAYITEM:
+ bd_seek_playitem(bd, ev->new_val);
+ return;
+ case PSR_TIME:
+ bd_seek_time(bd, ((int64_t)ev->new_val) << 1);
+ return;
+
+ case PSR_SELECTED_BUTTON_ID:
+ case PSR_MENU_PAGE_ID:
+ /* handled by graphics controller */
+ return;
+
+ default:
+ /* others: ignore */
+ return;
+ }
+ }
+
/*
* notification events to APP
*/
- static void _process_psr_event(void *handle, BD_PSR_EVENT *ev)
- {
- BLURAY *bd = (BLURAY*)handle;
- BD_DEBUG(DBG_BLURAY, "PSR event %d %d (%p)\n", ev->psr_idx, ev->new_val, bd);
+ static void _process_psr_write_event(BLURAY *bd, BD_PSR_EVENT *ev)
+ {
+ if (ev->ev_type == BD_PSR_WRITE) {
+ BD_DEBUG(DBG_BLURAY, "PSR write: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
+ }
switch (ev->psr_idx) {
/* current playback position */
- case PSR_ANGLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_ANGLE, ev->new_val}); break;
- case PSR_TITLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val}); break;
- case PSR_PLAYLIST: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYLIST, ev->new_val}); break;
- case PSR_PLAYITEM: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYITEM, ev->new_val}); break;
- case PSR_CHAPTER: _queue_event(bd, (BD_EVENT){BD_EVENT_CHAPTER, ev->new_val}); break;
+ case PSR_ANGLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_ANGLE, ev->new_val}); break;
+ case PSR_TITLE_NUMBER: _queue_event(bd, (BD_EVENT){BD_EVENT_TITLE, ev->new_val}); break;
+ case PSR_PLAYLIST: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYLIST, ev->new_val}); break;
+ case PSR_PLAYITEM: _queue_event(bd, (BD_EVENT){BD_EVENT_PLAYITEM, ev->new_val}); break;
+ case PSR_CHAPTER: _queue_event(bd, (BD_EVENT){BD_EVENT_CHAPTER, ev->new_val}); break;
+
+ default:;
+ }
+ }
+
+ static void _process_psr_change_event(BLURAY *bd, BD_PSR_EVENT *ev)
+ {
+ BD_DEBUG(DBG_BLURAY, "PSR change: psr%u = %u (%p)\n", ev->psr_idx, ev->new_val, bd);
+
+ _process_psr_write_event(bd, ev);
+
+ switch (ev->psr_idx) {
/* stream selection */
@@@ -1721,6 -1828,30 +1803,30 @@@
}
}
+ static void _process_psr_event(void *handle, BD_PSR_EVENT *ev)
+ {
+ BLURAY *bd = (BLURAY*)handle;
+
+ switch(ev->ev_type) {
+ case BD_PSR_WRITE:
+ _process_psr_write_event(bd, ev);
+ break;
+ case BD_PSR_CHANGE:
+ _process_psr_change_event(bd, ev);
+ break;
+ case BD_PSR_RESTORE:
+ _process_psr_restore_event(bd, ev);
+ break;
+
+ case BD_PSR_SAVE:
+ BD_DEBUG(DBG_BLURAY, "PSR save event (%p)\n", bd);
+ break;
+ default:
+ BD_DEBUG(DBG_BLURAY, "PSR event %d: psr%u = %u (%p)\n", ev->ev_type, ev->psr_idx, ev->new_val, bd);
+ break;
+ }
+ }
+
static void _queue_initial_psr_events(BLURAY *bd)
{
const uint32_t psrs[] = {
@@@ -1738,13 -1869,13 +1844,13 @@@
for (ii = 0; ii < sizeof(psrs) / sizeof(psrs[0]); ii++) {
BD_PSR_EVENT ev = {
- .ev_type = 0,
+ .ev_type = BD_PSR_CHANGE,
.psr_idx = psrs[ii],
.old_val = 0,
.new_val = bd_psr_read(bd->regs, psrs[ii]),
};
- _process_psr_event(bd, &ev);
+ _process_psr_change_event(bd, &ev);
}
}
@@@ -1763,6 -1894,8 +1869,6 @@@ static int _play_bdj(BLURAY *bd, const
static int _play_hdmv(BLURAY *bd, unsigned id_ref)
{
- int result = 1;
-
bd->title_type = title_hdmv;
#ifdef USING_BDJAVA
@@@ -1770,16 -1903,16 +1876,16 @@@
#endif
if (!bd->hdmv_vm) {
- bd->hdmv_vm = hdmv_vm_init(bd->device_path, bd->regs, bd->index);
+ bd->hdmv_vm = hdmv_vm_init(bd->device_path, bd->regs);
}
if (hdmv_vm_select_object(bd->hdmv_vm, id_ref)) {
- result = 0;
+ return 0;
}
bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
- return result;
+ return 1;
}
static int _play_title(BLURAY *bd, unsigned title)
@@@ -1862,8 -1995,10 +1968,8 @@@ int bd_play(BLURAY *bd
_init_event_queue(bd);
- bd_psr_lock(bd->regs);
bd_psr_register_cb(bd->regs, _process_psr_event, bd);
_queue_initial_psr_events(bd);
- bd_psr_unlock(bd->regs);
return _play_title(bd, BLURAY_TITLE_FIRST_PLAY);
}
@@@ -1871,7 -2006,12 +1977,7 @@@
int bd_play_title(BLURAY *bd, unsigned title)
{
if (bd->title_type == title_undef && title != BLURAY_TITLE_FIRST_PLAY) {
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_play_title(): bd_play() not called\n");
- return 0;
- }
-
- if (bd->st0.uo_mask.title_search) {
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "title search masked by stream\n");
+ // bd_play not called
return 0;
}
@@@ -1892,7 -2032,12 +1998,7 @@@ int bd_menu_call(BLURAY *bd, int64_t pt
}
if (bd->title_type == title_undef) {
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_menu_call(): bd_play() not called\n");
- return 0;
- }
-
- if (bd->st0.uo_mask.menu_call) {
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "menu call masked by stream\n");
+ // bd_play not called
return 0;
}
@@@ -1901,23 -2046,31 +2007,27 @@@
BD_DEBUG(DBG_BLURAY|DBG_CRIT, "menu call masked by movie object\n");
return 0;
}
-
- if (hdmv_vm_suspend_pl(bd->hdmv_vm) < 0) {
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "bd_menu_call(): error storing playback location\n");
- }
}
return _play_title(bd, BLURAY_TITLE_TOP_MENU);
}
- static void _run_gc(BLURAY *bd, gc_ctrl_e msg, uint32_t param)
+ static int _run_gc(BLURAY *bd, gc_ctrl_e msg, uint32_t param)
{
+ int result = -1;
+
if (bd && bd->graphics_controller && bd->hdmv_vm) {
GC_NAV_CMDS cmds = {-1, NULL, -1};
- gc_run(bd->graphics_controller, msg, param, &cmds);
+ result = gc_run(bd->graphics_controller, msg, param, &cmds);
if (cmds.num_nav_cmds > 0) {
hdmv_vm_set_object(bd->hdmv_vm, cmds.num_nav_cmds, cmds.nav_cmds);
bd->hdmv_suspended = !hdmv_vm_running(bd->hdmv_vm);
}
}
+
+ return result;
}
static void _process_hdmv_vm_event(BLURAY *bd, HDMV_EVENT *hev)
@@@ -1926,6 -2079,7 +2036,7 @@@
switch (hev->event) {
case HDMV_EVENT_TITLE:
+ _close_playlist(bd);
_play_title(bd, hev->param);
break;
@@@ -1946,12 -2100,8 +2057,8 @@@
break;
case HDMV_EVENT_PLAY_STOP:
- BD_DEBUG(DBG_BLURAY|DBG_CRIT, "HDMV_EVENT_PLAY_STOP: not tested !\n");
// stop current playlist
- bd_seek(bd, (uint64_t)bd->title->packets * 192 - 1);
- bd->st0.clip = NULL;
- // resume suspended movie object
- hdmv_vm_resume(bd->hdmv_vm);
+ _close_playlist(bd);
break;
case HDMV_EVENT_STILL:
@@@ -1975,7 -2125,6 +2082,7 @@@
break;
case HDMV_EVENT_IG_END:
+ BD_DEBUG(DBG_BLURAY|DBG_CRIT, "HDMV_EVENT_IG_END\n");
_run_gc(bd, GC_CTRL_IG_END, 0);
break;
@@@ -2062,29 -2211,36 +2169,36 @@@ int bd_get_event(BLURAY *bd, BD_EVENT *
_queue_initial_psr_events(bd);
}
- return _get_event(bd, event);
+ if (event) {
+ return _get_event(bd, event);
+ }
+
+ return 0;
}
/*
* user interaction
*/
- void bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y)
+ void bd_set_scr(BLURAY *bd, int64_t pts)
{
if (pts >= 0) {
bd_psr_write(bd->regs, PSR_TIME, (uint32_t)(((uint64_t)pts) >> 1));
}
+ }
+
+ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y)
+ {
+ bd_set_scr(bd, pts);
- _run_gc(bd, GC_CTRL_MOUSE_MOVE, (x << 16) | y);
+ return _run_gc(bd, GC_CTRL_MOUSE_MOVE, (x << 16) | y);
}
- void bd_user_input(BLURAY *bd, int64_t pts, uint32_t key)
+ int bd_user_input(BLURAY *bd, int64_t pts, uint32_t key)
{
- if (pts >= 0) {
- bd_psr_write(bd->regs, PSR_TIME, (uint32_t)(((uint64_t)pts) >> 1));
- }
+ bd_set_scr(bd, pts);
- _run_gc(bd, GC_CTRL_VK_KEY, key);
+ return _run_gc(bd, GC_CTRL_VK_KEY, key);
}
void bd_register_overlay_proc(BLURAY *bd, void *handle, bd_overlay_proc_f func)
@@@ -2100,6 -2256,10 +2214,10 @@@
}
}
+ /*
+ *
+ */
+
struct meta_dl *bd_get_meta(BLURAY *bd)
{
if (!bd) {
diff --combined src/libbluray/bluray.h
index 6f5dd1f,11f838c..d2ace64
--- a/src/libbluray/bluray.h
+++ b/src/libbluray/bluray.h
@@@ -22,6 -22,10 +22,6 @@@
#ifndef BLURAY_H_
#define BLURAY_H_
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/**
* @file libbluray/bluray.h
* external API header
@@@ -170,9 -174,10 +170,9 @@@ typedef struct bd_title_info
*
* @param bd BLURAY object
* @param flags title flags
- * @param min_title_length filter out titles shorter than min_title_length seconds
* @return number of titles found
*/
-uint32_t bd_get_titles(BLURAY *bd, uint8_t flags, uint32_t min_title_length);
+uint32_t bd_get_titles(BLURAY *bd, uint8_t flags);
/**
*
@@@ -180,9 -185,10 +180,9 @@@
*
* @param bd BLURAY object
* @param title_idx title index number
- * @param angle angle number (chapter offsets and clip size depend on selected angle)
* @return allocated BLURAY_TITLE_INFO object, NULL on error
*/
-BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx, unsigned angle);
+BLURAY_TITLE_INFO* bd_get_title_info(BLURAY *bd, uint32_t title_idx);
/**
*
@@@ -190,9 -196,10 +190,9 @@@
*
* @param bd BLURAY object
* @param playlist playlist number
- * @param angle angle number (chapter offsets and clip size depend on selected angle)
* @return allocated BLURAY_TITLE_INFO object, NULL on error
*/
-BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist, unsigned angle);
+BLURAY_TITLE_INFO* bd_get_playlist_info(BLURAY *bd, uint32_t playlist);
/**
*
@@@ -244,12 -251,21 +244,12 @@@ int64_t bd_seek_time(BLURAY *bd, uint64
* @param bd BLURAY object
* @param buf buffer to read data into
* @param len size of data to be read
- * @return size of data read, -1 if error
+ * @return size of data read, -1 if error, 0 if EOF
*/
int bd_read(BLURAY *bd, unsigned char *buf, int len);
/**
*
- * Continue reading after still mode clip
- *
- * @param bd BLURAY object
- * @return 0 on error
- */
-int bd_read_skip_still(BLURAY *bd);
-
-/**
- *
* Seek to a chapter. First chapter is 0
*
* @param bd BLURAY object
@@@ -496,7 -512,7 +496,7 @@@ typedef struct
* Get event from libbluray event queue.
*
* @param bd BLURAY object
- * @param event next BD_EVENT from event queue
+ * @param event next BD_EVENT from event queue, NULL to initialize event queue
* @return 1 on success, 0 if no events
*/
int bd_get_event(BLURAY *bd, BD_EVENT *event);
@@@ -507,7 -523,7 +507,7 @@@
/**
*
- * Start playing disc in navigation mode.
+ * Start playing disc in navigation mode (using on-disc menus).
*
* Playback is started from "First Play" title.
*
@@@ -583,9 -599,9 +583,9 @@@ void bd_register_overlay_proc(BLURAY *b
* @param bd BLURAY object
* @param pts current playback position (1/90000s) or -1
* @param key input key
- * @return 1 on success, 0 if error
+ * @return <0 on error, 0 on success, >0 if selection/activation changed
*/
- void bd_user_input(BLURAY *bd, int64_t pts, uint32_t key);
+ int bd_user_input(BLURAY *bd, int64_t pts, uint32_t key);
/**
*
@@@ -595,9 -611,13 +595,13 @@@
* @param pts current playback position (1/90000s) or -1
* @param x mouse pointer x-position
* @param y mouse pointer y-position
- * @return none
+ * @return <0 on error, 0 when mouse is outside of buttons, 1 when mouse is inside button
+ */
+ int bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y);
+
+ /*
+ *
*/
- void bd_mouse_select(BLURAY *bd, int64_t pts, uint16_t x, uint16_t y);
struct meta_dl;
/**
@@@ -629,4 -649,8 +633,4 @@@ struct clpi_cl *bd_get_clpi(BLURAY *bd
*/
void bd_free_clpi(struct clpi_cl *cl);
-#ifdef __cplusplus
-};
-#endif
-
#endif /* BLURAY_H_ */
diff --combined src/libbluray/decoders/graphics_controller.c
index a2c595d,8b33b81..d48b057
--- a/src/libbluray/decoders/graphics_controller.c
+++ b/src/libbluray/decoders/graphics_controller.c
@@@ -31,6 -31,7 +31,6 @@@
#include "../keys.h"
#include <inttypes.h>
-#include <string.h>
#define GC_ERROR(...) BD_DEBUG(DBG_GC | DBG_CRIT, __VA_ARGS__)
#define GC_TRACE(...) BD_DEBUG(DBG_GC, __VA_ARGS__)
@@@ -39,6 -40,12 +39,12 @@@
*
*/
+ typedef struct {
+ uint16_t enabled_button; /* enabled button id */
+ uint16_t x, y, w, h; /* button rect on overlay plane (if drawn) */
+ int animate_indx; /* currently showing object index of animated button, < 0 for static buttons */
+ } BOG_DATA;
+
struct graphics_controller_s {
BD_REGISTERS *regs;
@@@ -54,11 -61,12 +60,13 @@@
unsigned pg_drawn;
unsigned popup_visible;
unsigned valid_mouse_position;
+ BOG_DATA *bog_data;
+ BOG_DATA *saved_bog_data;
/* data */
PG_DISPLAY_SET *pgs;
PG_DISPLAY_SET *igs;
+ uint16_t *enabled_button;
/* */
GRAPHICS_PROCESSOR *pgp;
@@@ -141,23 -149,53 +149,53 @@@ static BD_IG_PAGE *_find_page(BD_IG_INT
enum { BTN_NORMAL, BTN_SELECTED, BTN_ACTIVATED };
static BD_PG_OBJECT *_find_object_for_button(PG_DISPLAY_SET *s,
- BD_IG_BUTTON *button, int state)
+ BD_IG_BUTTON *button, int state,
+ BOG_DATA *bog_data)
{
BD_PG_OBJECT *object = NULL;
unsigned object_id = 0xffff;
+ unsigned object_id_end = 0xffff;
+ unsigned repeat = 0;
switch (state) {
case BTN_NORMAL:
- object_id = button->normal_start_object_id_ref;
+ object_id = button->normal_start_object_id_ref;
+ object_id_end = button->normal_end_object_id_ref;
+ repeat = button->normal_repeat_flag;
break;
case BTN_SELECTED:
- object_id = button->selected_start_object_id_ref;
+ object_id = button->selected_start_object_id_ref;
+ object_id_end = button->selected_end_object_id_ref;
+ repeat = button->selected_repeat_flag;
break;
case BTN_ACTIVATED:
- object_id = button->activated_start_object_id_ref;
+ object_id = button->activated_start_object_id_ref;
+ object_id_end = button->activated_end_object_id_ref;
break;
}
+ if (bog_data) {
+ if (bog_data->animate_indx >= 0) {
+ int range = object_id_end - object_id;
+
+ if (range > 0 && object_id < 0xffff && object_id_end < 0xffff) {
+ GC_TRACE("animate button #%d: animate_indx %d, range %d, repeat %d\n",
+ button->id, bog_data->animate_indx, range, repeat);
+
+ object_id += bog_data->animate_indx % (range + 1);
+ bog_data->animate_indx++;
+ if (!repeat && bog_data->animate_indx > range) {
+ /* terminate animation to the last object */
+ bog_data->animate_indx = -1;
+ }
+
+ } else {
+ /* no animation for this button */
+ bog_data->animate_indx = -1;
+ }
+ }
+ }
+
object = _find_object(s, object_id);
return object;
@@@ -171,7 -209,7 +209,7 @@@ static int _is_button_enabled(GRAPHICS_
{
unsigned ii;
for (ii = 0; ii < page->num_bogs; ii++) {
- if (gc->bog_data[ii].enabled_button == button_id) {
+ if (gc->enabled_button[ii] == button_id) {
return 1;
}
}
@@@ -207,11 -245,12 +245,11 @@@ static uint16_t _find_selected_button_i
/* 2) fallback to current PSR10 value if it is valid */
for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BOG *bog = &page->bog[ii];
- uint16_t enabled_button = gc->bog_data[ii].enabled_button;
- if (button_id == enabled_button) {
- if (_find_button_bog(bog, enabled_button)) {
- GC_TRACE("_find_selected_button_id() -> PSR10 #%d\n", enabled_button);
- return enabled_button;
+ if (button_id == gc->enabled_button[ii]) {
+ if (_find_button_bog(bog, gc->enabled_button[ii])) {
+ GC_TRACE("_find_selected_button_id() -> PSR10 #%d\n", gc->enabled_button[ii]);
+ return gc->enabled_button[ii];
}
}
}
@@@ -219,10 -258,11 +257,10 @@@
/* 3) fallback to find first valid_button_id_ref from page */
for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BOG *bog = &page->bog[ii];
- uint16_t enabled_button = gc->bog_data[ii].enabled_button;
- if (_find_button_bog(bog, enabled_button)) {
- GC_TRACE("_find_selected_button_id() -> first valid #%d\n", enabled_button);
- return enabled_button;
+ if (_find_button_bog(bog, gc->enabled_button[ii])) {
+ GC_TRACE("_find_selected_button_id() -> first valid #%d\n", gc->enabled_button[ii]);
+ return gc->enabled_button[ii];
}
}
@@@ -230,7 -270,54 +268,54 @@@
return 0xffff;
}
- static void _reset_enabled_button(GRAPHICS_CONTROLLER *gc)
+ static int _save_page_state(GRAPHICS_CONTROLLER *gc)
+ {
+ if (!gc->bog_data) {
+ GC_ERROR("_save_page_state(): no bog data !\n");
+ return -1;
+ }
+
+ PG_DISPLAY_SET *s = gc->igs;
+ BD_IG_PAGE *page = NULL;
+ unsigned page_id = bd_psr_read(gc->regs, PSR_MENU_PAGE_ID);
+ unsigned ii;
+
+ page = _find_page(&s->ics->interactive_composition, page_id);
+ if (!page) {
+ GC_ERROR("_save_page_state(): unknown page #%d (have %d pages)\n",
+ page_id, s->ics->interactive_composition.num_pages);
+ return -1;
+ }
+
+ /* copy enabled button state, clear draw state */
+
+ X_FREE(gc->saved_bog_data);
+ gc->saved_bog_data = calloc(page->num_bogs, sizeof(*gc->saved_bog_data));
+
+ for (ii = 0; ii < page->num_bogs; ii++) {
+ gc->saved_bog_data[ii].enabled_button = gc->bog_data[ii].enabled_button;
+ gc->saved_bog_data[ii].animate_indx = gc->bog_data[ii].animate_indx >= 0 ? 0 : -1;
+ }
+
+ return 1;
+ }
+
+ static int _restore_page_state(GRAPHICS_CONTROLLER *gc)
+ {
+ if (gc->saved_bog_data) {
+ if (gc->bog_data) {
+ GC_ERROR("_restore_page_state(): bog data already exists !\n");
+ X_FREE(gc->bog_data);
+ }
+ gc->bog_data = gc->saved_bog_data;
+ gc->saved_bog_data = NULL;
+
+ return 1;
+ }
+ return -1;
+ }
+
+ static void _reset_page_state(GRAPHICS_CONTROLLER *gc)
{
PG_DISPLAY_SET *s = gc->igs;
BD_IG_PAGE *page = NULL;
@@@ -239,58 -326,82 +324,74 @@@
page = _find_page(&s->ics->interactive_composition, page_id);
if (!page) {
- GC_ERROR("_reset_page_state(): unknown page #%d (have %d pages)\n",
+ GC_ERROR("_reset_enabled_button(): unknown page #%d (have %d pages)\n",
page_id, s->ics->interactive_composition.num_pages);
return;
}
- size_t size = page->num_bogs * sizeof(*gc->bog_data);
- gc->bog_data = realloc(gc->bog_data, size);
-
- memset(gc->bog_data, 0, size);
+ gc->enabled_button = realloc(gc->enabled_button,
+ page->num_bogs * sizeof(uint16_t));
for (ii = 0; ii < page->num_bogs; ii++) {
- gc->enabled_button[ii] = page->bog[ii].default_valid_button_id_ref;
+ gc->bog_data[ii].enabled_button = page->bog[ii].default_valid_button_id_ref;
+ gc->bog_data[ii].animate_indx = 0;
}
}
-static void _clear_osd_area(GRAPHICS_CONTROLLER *gc, int plane,
- uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+static void _clear_osd(GRAPHICS_CONTROLLER *gc, int plane)
{
if (gc->overlay_proc) {
/* clear plane */
const BD_OVERLAY ov = {
.pts = -1,
.plane = plane,
- .x = x,
- .y = y,
- .w = w,
- .h = h,
+ .x = 0,
+ .y = 0,
+ .w = 1920,
+ .h = 1080,
.palette = NULL,
.img = NULL,
};
gc->overlay_proc(gc->overlay_proc_handle, &ov);
}
-}
-
-static void _clear_osd(GRAPHICS_CONTROLLER *gc, int plane)
-{
- _clear_osd_area(gc, plane, 0, 0, 1920, 1080);
- if (plane) {
+ if (plane == BD_OVERLAY_IG) {
gc->ig_drawn = 0;
} else {
gc->pg_drawn = 0;
}
}
+ static void _clear_bog_area(GRAPHICS_CONTROLLER *gc, BOG_DATA *bog_data)
+ {
+ if (gc->ig_drawn && bog_data->w && bog_data->h) {
+
+ _clear_osd_area(gc, BD_OVERLAY_IG, bog_data->x, bog_data->y, bog_data->w, bog_data->h);
+
+ bog_data->x = bog_data->y = bog_data->w = bog_data->h = 0;
+ }
+ }
+
+ static void _select_button(GRAPHICS_CONTROLLER *gc, uint32_t button_id)
+ {
+ bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id);
+ }
+
static void _select_page(GRAPHICS_CONTROLLER *gc, uint16_t page_id)
{
bd_psr_write(gc->regs, PSR_MENU_PAGE_ID, page_id);
- _clear_osd(gc, 1);
- _reset_enabled_button(gc);
+ _clear_osd(gc, BD_OVERLAY_IG);
+ _reset_page_state(gc);
uint16_t button_id = _find_selected_button_id(gc);
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id);
+ _select_button(gc, button_id);
}
static void _gc_reset(GRAPHICS_CONTROLLER *gc)
{
- _clear_osd(gc, 0);
- _clear_osd(gc, 1);
+ _clear_osd(gc, BD_OVERLAY_PG);
+ _clear_osd(gc, BD_OVERLAY_IG);
gc->popup_visible = 0;
@@@ -300,10 -411,48 +401,48 @@@
pg_display_set_free(&gc->pgs);
pg_display_set_free(&gc->igs);
- X_FREE(gc->bog_data);
+ X_FREE(gc->enabled_button);
}
/*
+ * register hook
+ */
+ static void _process_psr_event(void *handle, BD_PSR_EVENT *ev)
+ {
+ GRAPHICS_CONTROLLER *gc = (GRAPHICS_CONTROLLER *)handle;
+
+ if (ev->ev_type == BD_PSR_SAVE) {
+ BD_DEBUG(DBG_GC, "PSR SAVE event\n");
+
+ /* save menu page state */
+ bd_mutex_lock(&gc->mutex);
+ _save_page_state(gc);
+ bd_mutex_unlock(&gc->mutex);
+
+ return;
+ }
+
+ if (ev->ev_type == BD_PSR_RESTORE) {
+ switch (ev->psr_idx) {
+
+ case PSR_SELECTED_BUTTON_ID:
+ return;
+
+ case PSR_MENU_PAGE_ID:
+ /* restore menus */
+ bd_mutex_lock(&gc->mutex);
+ _restore_page_state(gc);
+ bd_mutex_unlock(&gc->mutex);
+ return;
+
+ default:
+ /* others: ignore */
+ return;
+ }
+ }
+ }
+
+ /*
* init / free
*/
@@@ -318,6 -467,8 +457,8 @@@ GRAPHICS_CONTROLLER *gc_init(BD_REGISTE
bd_mutex_init(&p->mutex);
+ bd_psr_register_cb(regs, _process_psr_event, p);
+
return p;
}
@@@ -325,13 -476,17 +466,17 @@@ void gc_free(GRAPHICS_CONTROLLER **p
{
if (p && *p) {
- _gc_reset(*p);
+ GRAPHICS_CONTROLLER *gc = *p;
+
+ bd_psr_unregister_cb(gc->regs, _process_psr_event, gc);
+
+ _gc_reset(gc);
- if ((*p)->overlay_proc) {
- (*p)->overlay_proc((*p)->overlay_proc_handle, NULL);
+ if (gc->overlay_proc) {
+ gc->overlay_proc(gc->overlay_proc_handle, NULL);
}
- bd_mutex_destroy(&(*p)->mutex);
+ bd_mutex_destroy(&gc->mutex);
X_FREE(*p);
}
@@@ -341,11 -496,11 +486,11 @@@
* graphics stream input
*/
-int gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigned num_blocks, int64_t stc)
+void gc_decode_ts(GRAPHICS_CONTROLLER *gc, uint16_t pid, uint8_t *block, unsigned num_blocks, int64_t stc)
{
if (!gc) {
GC_TRACE("gc_decode_ts(): no graphics controller\n");
- return -1;
+ return;
}
if (pid >= 0x1400 && pid < 0x1500) {
@@@ -357,12 -512,17 +502,17 @@@
bd_mutex_lock(&gc->mutex);
- graphics_processor_decode_ts(gc->igp, &gc->igs,
- pid, block, num_blocks,
- stc);
+ if (!graphics_processor_decode_ts(gc->igp, &gc->igs,
+ pid, block, num_blocks,
+ stc)) {
+ /* no new complete display set */
+ bd_mutex_unlock(&gc->mutex);
+ return 0;
+ }
+
if (!gc->igs || !gc->igs->complete) {
bd_mutex_unlock(&gc->mutex);
- return 0;
+ return;
}
gc->popup_visible = 0;
@@@ -370,6 -530,8 +520,6 @@@
_select_page(gc, 0);
bd_mutex_unlock(&gc->mutex);
-
- return 1;
}
else if (pid >= 0x1200 && pid < 0x1300) {
@@@ -382,9 -544,13 +532,9 @@@
stc);
if (!gc->pgs || !gc->pgs->complete) {
- return 0;
+ return;
}
-
- return 1;
}
-
- return -1;
}
/*
@@@ -392,24 -558,27 +542,24 @@@
*/
static void _render_button(GRAPHICS_CONTROLLER *gc, BD_IG_BUTTON *button, BD_PG_PALETTE *palette,
- int state, BOG_DATA *bog_data)
+ int state)
{
BD_PG_OBJECT *object = NULL;
BD_OVERLAY ov;
- object = _find_object_for_button(gc->igs, button, state);
+ object = _find_object_for_button(gc->igs, button, state, bog_data);
if (!object) {
GC_TRACE("_render_button(#%d): object (state %d) not found\n", button->id, state);
-
- _clear_bog_area(gc, bog_data);
-
return;
}
ov.pts = -1;
- ov.plane = 1; /* IG */
+ ov.plane = BD_OVERLAY_IG;
- ov.x = bog_data->x = button->x_pos;
- ov.y = bog_data->y = button->y_pos;
- ov.w = bog_data->w = object->width;
- ov.h = bog_data->h = object->height;
+ ov.x = button->x_pos;
+ ov.y = button->y_pos;
+ ov.w = object->width;
+ ov.h = object->height;
ov.img = object->img;
ov.palette = palette->entry;
@@@ -434,7 -603,7 +584,7 @@@ static void _render_page(GRAPHICS_CONTR
if (s->ics->interactive_composition.ui_model == IG_UI_MODEL_POPUP && !gc->popup_visible) {
GC_TRACE("_render_page(): popup menu not visible\n");
- _clear_osd(gc, 1);
+ _clear_osd(gc, BD_OVERLAY_IG);
return;
}
@@@ -458,7 -627,7 +608,7 @@@
for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BOG *bog = &page->bog[ii];
- unsigned valid_id = gc->bog_data[ii].enabled_button;
+ unsigned valid_id = gc->enabled_button[ii];
BD_IG_BUTTON *button;
button = _find_button_bog(bog, valid_id);
@@@ -467,21 -636,19 +617,19 @@@
GC_TRACE("_render_page(): bog %d: button %d not found\n", ii, valid_id);
} else if (button->id == activated_button_id) {
- _render_button(gc, button, palette, BTN_ACTIVATED, &gc->bog_data[ii]);
+ _render_button(gc, button, palette, BTN_ACTIVATED);
} else if (button->id == selected_button_id) {
- _render_button(gc, button, palette, BTN_SELECTED, &gc->bog_data[ii]);
+ _render_button(gc, button, palette, BTN_SELECTED);
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, selected_button_id);
-
- if (button->auto_action_flag) {
+ if (button->auto_action_flag && cmds) {
cmds->num_nav_cmds = button->num_nav_cmds;
cmds->nav_cmds = button->nav_cmds;
}
} else {
- _render_button(gc, button, palette, BTN_NORMAL, &gc->bog_data[ii]);
+ _render_button(gc, button, palette, BTN_NORMAL);
}
}
@@@ -533,7 -700,7 +681,7 @@@ static int _user_input(GRAPHICS_CONTROL
for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BOG *bog = &page->bog[ii];
- unsigned valid_id = gc->bog_data[ii].enabled_button;
+ unsigned valid_id = gc->enabled_button[ii];
BD_IG_BUTTON *button = _find_button_bog(bog, valid_id);
if (!button) {
continue;
@@@ -585,7 -752,7 +733,7 @@@
/* render page ? */
if (new_btn_id != cur_btn_id || activated_btn_id >= 0) {
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, new_btn_id);
+ _select_button(gc, new_btn_id);
_render_page(gc, activated_btn_id, cmds);
@@@ -596,7 -763,7 +744,7 @@@
return 0;
}
-static void _set_button_page(GRAPHICS_CONTROLLER *gc, uint32_t param)
+static void _set_button_page(GRAPHICS_CONTROLLER *gc, uint32_t param, GC_NAV_CMDS *cmds)
{
unsigned page_flag = param & 0x80000000;
unsigned effect_flag = param & 0x40000000;
@@@ -668,11 -835,11 +816,11 @@@
}
if (button) {
- gc->enabled_button[bog_idx] = button_id;
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id);
+ gc->bog_data[bog_idx].enabled_button = button_id;
+ _select_button(gc, button_id);
}
- _render_page(gc, 0xffff, NULL);
+ _render_page(gc, 0xffff, cmds);
}
static void _enable_button(GRAPHICS_CONTROLLER *gc, uint32_t button_id, unsigned enable)
@@@ -701,15 -868,15 +849,15 @@@
}
if (enable) {
- if (gc->bog_data[bog_idx].enabled_button == cur_btn_id) {
+ if (gc->enabled_button[bog_idx] == cur_btn_id) {
/* selected button goes to disabled state */
bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, 0x10000|button_id);
}
- gc->bog_data[bog_idx].enabled_button = button_id;
+ gc->enabled_button[bog_idx] = button_id;
} else {
- if (gc->bog_data[bog_idx].enabled_button == button_id) {
- gc->bog_data[bog_idx].enabled_button = 0xffff;
+ if (gc->enabled_button[bog_idx] == button_id) {
+ gc->enabled_button[bog_idx] = 0xffff;
}
if (cur_btn_id == button_id) {
@@@ -728,14 -895,14 +876,14 @@@ static void _update_selected_button(GRA
/* special case: triggered only after enable button disables selected button */
if (button_id & 0x10000) {
button_id &= 0xffff;
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id);
+ _select_button(gc, button_id);
GC_TRACE("_update_selected_button() -> #%d [last enabled]\n", button_id);
return;
}
if (button_id == 0xffff) {
button_id = _find_selected_button_id(gc);
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, button_id);
+ _select_button(gc, button_id);
}
}
@@@ -751,7 -918,7 +899,7 @@@ static int _mouse_move(GRAPHICS_CONTROL
gc->valid_mouse_position = 0;
if (!gc->ig_drawn) {
- GC_ERROR("_mouse_move(): menu not visible\n");
+ GC_TRACE("_mouse_move(): menu not visible\n");
return -1;
}
@@@ -764,7 -931,7 +912,7 @@@
for (ii = 0; ii < page->num_bogs; ii++) {
BD_IG_BOG *bog = &page->bog[ii];
- unsigned valid_id = gc->bog_data[ii].enabled_button;
+ unsigned valid_id = gc->enabled_button[ii];
BD_IG_BUTTON *button = _find_button_bog(bog, valid_id);
if (!button)
@@@ -774,7 -941,7 +922,7 @@@
continue;
/* Check for SELECTED state object (button that can be selected) */
- BD_PG_OBJECT *object = _find_object_for_button(s, button, BTN_SELECTED);
+ BD_PG_OBJECT *object = _find_object_for_button(s, button, BTN_SELECTED, NULL);
if (!object)
continue;
@@@ -786,7 -953,7 +934,7 @@@
/* is button already selected? */
if (button->id == cur_btn_id) {
- return 0;
+ return 1;
}
new_btn_id = button->id;
@@@ -794,7 -961,7 +942,7 @@@
}
if (new_btn_id != 0xffff) {
- bd_psr_write(gc->regs, PSR_SELECTED_BUTTON_ID, new_btn_id);
+ _select_button(gc, new_btn_id);
_render_page(gc, -1, cmds);
}
@@@ -826,6 -993,7 +974,7 @@@ int gc_run(GRAPHICS_CONTROLLER *gc, gc_
bd_mutex_unlock(&gc->mutex);
return 0;
+
default:;
}
@@@ -839,7 -1007,7 +988,7 @@@
switch (ctrl) {
case GC_CTRL_SET_BUTTON_PAGE:
- _set_button_page(gc, param);
+ _set_button_page(gc, param, cmds);
break;
case GC_CTRL_VK_KEY:
@@@ -884,6 -1052,7 +1033,7 @@@
case GC_CTRL_MOUSE_MOVE:
result = _mouse_move(gc, param >> 16, param & 0xffff, cmds);
break;
+
case GC_CTRL_RESET:
/* already handled */
break;
diff --combined src/libbluray/hdmv/hdmv_vm.c
index 3453d2f,715ed3a..24707d8
--- a/src/libbluray/hdmv/hdmv_vm.c
+++ b/src/libbluray/hdmv/hdmv_vm.c
@@@ -23,6 -23,7 +23,6 @@@
#include "hdmv_insn.h"
#include "../register.h"
-#include "../bdnav/index_parse.h"
#include "util/macro.h"
#include "util/strutl.h"
#include "util/logging.h"
@@@ -55,9 -56,16 +55,13 @@@ struct hdmv_vm_s
MOBJ_OBJECTS *movie_objects; /* disc movie objects */
MOBJ_OBJECT *ig_object; /* current object from IG stream */
+ /* object currently playing playlist */
+ MOBJ_OBJECT *playing_object;
+ int playing_pc;
+
/* suspended object */
MOBJ_OBJECT *suspended_object;
int suspended_pc;
-
- /* disc index (used to verify CALL_TITLE/JUMP_TITLE) */
- INDX_ROOT *indx;
};
/*
@@@ -231,7 -239,7 +235,7 @@@ static int _queue_event(HDMV_VM *p, uin
* vm init
*/
-HDMV_VM *hdmv_vm_init(const char *disc_root, BD_REGISTERS *regs, INDX_ROOT *indx)
+HDMV_VM *hdmv_vm_init(const char *disc_root, BD_REGISTERS *regs)
{
HDMV_VM *p = calloc(1, sizeof(HDMV_VM));
char *file;
@@@ -246,6 -254,7 +250,6 @@@
}
p->regs = regs;
- p->indx = indx;
bd_mutex_init(&p->mutex);
@@@ -278,6 -287,54 +282,54 @@@ void hdmv_vm_free(HDMV_VM **p
* suspend/resume ("function call")
*/
+ static int _suspended_at_play_pl(HDMV_VM *p)
+ {
+ int play_pl = 0;
+ if (p && p->suspended_object) {
+ MOBJ_CMD *cmd = &p->suspended_object->cmds[p->suspended_pc];
+ HDMV_INSN *insn = &cmd->insn;
+ play_pl = (insn->grp == INSN_GROUP_BRANCH &&
+ insn->sub_grp == BRANCH_PLAY &&
+ ( insn->branch_opt == INSN_PLAY_PL ||
+ insn->branch_opt == INSN_PLAY_PL_PI ||
+ insn->branch_opt == INSN_PLAY_PL_PM));
+ }
+
+ return play_pl;
+ }
+
+ static int _suspend_for_play_pl(HDMV_VM *p)
+ {
+ if (p->playing_object) {
+ BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_for_play_pl(): object already playing playlist !\n");
+ return -1;
+ }
+
+ p->playing_object = p->object;
+ p->playing_pc = p->pc;
+
+ p->object = NULL;
+
+ return 0;
+ }
+
+ static int _resume_from_play_pl(HDMV_VM *p)
+ {
+ if (!p->playing_object) {
+ BD_DEBUG(DBG_HDMV|DBG_CRIT, "_resume_from_play_pl(): object not playing playlist !\n");
+ return -1;
+ }
+
+ p->object = p->playing_object;
+ p->pc = p->playing_pc + 1;
+
+ p->playing_object = NULL;
+
+ _free_ig_object(p);
+
+ return 0;
+ }
+
static void _suspend_object(HDMV_VM *p, int psr_backup)
{
BD_DEBUG(DBG_HDMV, "_suspend_object()\n");
@@@ -291,10 -348,31 +343,31 @@@
bd_psr_save_state(p->regs);
}
- p->suspended_object = p->object;
- p->suspended_pc = p->pc;
+ if (p->ig_object) {
+ if (!p->playing_object) {
+ BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_object: IG object tries to suspend, no playing object !\n");
+ return;
+ }
+ p->suspended_object = p->playing_object;
+ p->suspended_pc = p->playing_pc;
+
+ p->playing_object = NULL;
+
+ } else {
+
+ if (p->playing_object) {
+ BD_DEBUG(DBG_HDMV|DBG_CRIT, "_suspend_object: Movie object tries to suspend, also playing object present !\n");
+ return;
+ }
+
+ p->suspended_object = p->object;
+ p->suspended_pc = p->pc;
+
+ }
p->object = NULL;
+
+ _free_ig_object(p);
}
static int _resume_object(HDMV_VM *p, int psr_restore)
@@@ -304,17 -382,33 +377,33 @@@
return -1;
}
- p->object = p->suspended_object;
- p->pc = p->suspended_pc + 1;
+ p->object = NULL;
+ p->playing_object = NULL;
+ _free_ig_object(p);
if (psr_restore) {
+ /* check if suspended in play_pl */
+ if (_suspended_at_play_pl(p)) {
+ BD_DEBUG(DBG_HDMV, "resuming playlist playback\n");
+ p->playing_object = p->suspended_object;
+ p->playing_pc = p->suspended_pc;
+ p->suspended_object = NULL;
+ bd_psr_restore_state(p->regs);
+
+ return 0;
+ }
bd_psr_restore_state(p->regs);
}
- BD_DEBUG(DBG_HDMV, "resuming object %p at %d\n", p->object, p->pc + 1);
+ p->object = p->suspended_object;
+ p->pc = p->suspended_pc + 1;
p->suspended_object = NULL;
+ BD_DEBUG(DBG_HDMV, "resuming object %p at %d\n", p->object, p->pc);
+
+ _queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
+
return 0;
}
@@@ -323,6 -417,21 +412,6 @@@
* branching
*/
-static int _is_valid_title(HDMV_VM *p, int title)
-{
- if (title == 0 || title == 0xffff) {
- INDX_PLAY_ITEM *pi = (!title) ? &p->indx->top_menu : &p->indx->first_play;
-
- if (pi->object_type == indx_object_type_hdmv && pi->hdmv.id_ref == 0xffff) {
- /* no top menu or first play title (5.2.3.3) */
- return 0;
- }
- return 1;
- }
-
- return title > 0 && title <= p->indx->num_titles;
-}
-
static int _jump_object(HDMV_VM *p, int object)
{
if (object < 0 || object >= p->movie_objects->num_objects) {
@@@ -332,8 -441,12 +421,12 @@@
BD_DEBUG(DBG_HDMV, "_jump_object(): jumping to object %d\n", object);
+ _queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
+
_free_ig_object(p);
+ p->playing_object = NULL;
+
p->pc = 0;
p->object = &p->movie_objects->objects[object];
@@@ -344,11 -457,12 +437,12 @@@
static int _jump_title(HDMV_VM *p, int title)
{
- if (_is_valid_title(p, title)) {
+ if (title >= 0 && title <= 0xffff) {
BD_DEBUG(DBG_HDMV, "_jump_title(%d)\n", title);
/* discard suspended object */
p->suspended_object = NULL;
+ p->playing_object = NULL;
bd_psr_reset_backup_registers(p->regs);
_queue_event(p, HDMV_EVENT_TITLE, title);
@@@ -364,6 -478,7 +458,7 @@@ static int _call_object(HDMV_VM *p, in
{
BD_DEBUG(DBG_HDMV, "_call_object(%d)\n", object);
+ _queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
_suspend_object(p, 1);
return _jump_object(p, object);
@@@ -371,12 -486,13 +466,13 @@@
static int _call_title(HDMV_VM *p, int title)
{
- if (_is_valid_title(p, title)) {
+ if (title >= 0 && title <= 0xffff) {
BD_DEBUG(DBG_HDMV, "_call_title(%d)\n", title);
_suspend_object(p, 1);
_queue_event(p, HDMV_EVENT_TITLE, title);
+
return 0;
}
@@@ -410,7 -526,7 +506,7 @@@ static int _play_at(HDMV_VM *p, int pla
if (playlist >= 0) {
_queue_event(p, HDMV_EVENT_PLAY_PL, playlist);
- _suspend_object(p, 0);
+ _suspend_for_play_pl(p);
}
if (playitem >= 0) {
@@@ -433,6 -549,7 +529,7 @@@ static int _play_stop(HDMV_VM *p
BD_DEBUG(DBG_HDMV, "_play_stop()\n");
_queue_event(p, HDMV_EVENT_PLAY_STOP, 0);
+
return 0;
}
@@@ -954,7 -1071,7 +1051,7 @@@ uint32_t hdmv_vm_get_uo_mask(HDMV_VM *p
bd_mutex_lock(&p->mutex);
- if ((o = p->object ? p->object : p->suspended_object)) {
+ if ((o = p->object ? p->object : (p->playing_object ? p->playing_object : p->suspended_object))) {
mask |= o->menu_call_mask;
mask |= o->title_search_mask << 1;
}
@@@ -968,19 -1085,36 +1065,36 @@@ int hdmv_vm_resume(HDMV_VM *p
int result;
bd_mutex_lock(&p->mutex);
- result = _resume_object(p, 0);
+ result = _resume_from_play_pl(p);
bd_mutex_unlock(&p->mutex);
return result;
}
-int hdmv_vm_suspend_pl(HDMV_VM *p)
+int hdmv_vm_suspend(HDMV_VM *p)
{
int result = -1;
bd_mutex_lock(&p->mutex);
- if (p->object && !p->ig_object) {
- _suspend_object(p, 1);
+ if (p->object || p->ig_object) {
+ BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): HDMV VM is still running\n");
+
+ } else if (!p->playing_object) {
+ BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): No playing object\n");
+
+ } else if (!p->playing_object->resume_intention_flag) {
+ BD_DEBUG(DBG_HDMV, "hdmv_vm_suspend_pl(): no resume intention flag\n");
+
+ p->playing_object = NULL;
+ result = 0;
+
+ } else {
+ p->suspended_object = p->playing_object;
+ p->suspended_pc = p->playing_pc;
+
+ p->playing_object = NULL;
+
+ bd_psr_save_state(p->regs);
result = 0;
}
@@@ -1008,6 -1142,13 +1122,13 @@@ static int _vm_run(HDMV_VM *p, HDMV_EVE
while (--max_loop > 0) {
+ /* suspended ? */
+ if (!p->object) {
+ BD_DEBUG(DBG_HDMV, "hdmv_vm_run(): object suspended\n");
+ _get_event(p, ev);
+ return 0;
+ }
+
/* terminated ? */
if (p->pc >= p->object->num_cmds) {
BD_DEBUG(DBG_HDMV, "terminated with PC=%d\n", p->pc);
diff --combined src/libbluray/register.c
index 07032f8,7621866..c83fd7a
--- a/src/libbluray/register.c
+++ b/src/libbluray/register.c
@@@ -252,6 -252,22 +252,22 @@@ void bd_psr_save_state(BD_REGISTERS *p
memcpy(p->psr + 36, p->psr + 4, sizeof(uint32_t) * 5);
memcpy(p->psr + 42, p->psr + 10, sizeof(uint32_t) * 3);
+ /* generate save event */
+
+ if (p->num_cb) {
+ BD_PSR_EVENT ev = {
+ .ev_type = BD_PSR_SAVE,
+ .psr_idx = -1,
+ .old_val = 0,
+ .new_val = 0,
+ };
+
+ unsigned j;
+ for (j = 0; j < p->num_cb; j++) {
+ p->cb[j].cb(p->cb[j].handle, &ev);
+ }
+ }
+
bd_psr_unlock(p);
}
@@@ -268,17 -284,23 +284,17 @@@ void bd_psr_reset_backup_registers(BD_R
void bd_psr_restore_state(BD_REGISTERS *p)
{
- uint32_t old_psr[13];
- uint32_t new_psr[13];
+ uint32_t old_psr[BD_PSR_COUNT];
bd_psr_lock(p);
- if (p->num_cb) {
- memcpy(old_psr, p->psr, sizeof(old_psr[0]) * 13);
- }
+ if (p->num_cb)
+ memcpy(old_psr, p->psr, sizeof(old_psr));
/* restore backup registers */
memcpy(p->psr + 4, p->psr + 36, sizeof(uint32_t) * 5);
memcpy(p->psr + 10, p->psr + 42, sizeof(uint32_t) * 3);
- if (p->num_cb) {
- memcpy(new_psr, p->psr, sizeof(new_psr[0]) * 13);
- }
-
/* init backup registers to default */
memcpy(p->psr + 36, bd_psr_init + 36, sizeof(uint32_t) * 5);
memcpy(p->psr + 42, bd_psr_init + 42, sizeof(uint32_t) * 3);
@@@ -291,11 -313,11 +307,11 @@@
ev.ev_type = BD_PSR_RESTORE;
for (i = 4; i < 13; i++) {
- if (i != PSR_NAV_TIMER) {
+ if (i != 9 && old_psr[i] != p->psr[i]) {
ev.psr_idx = i;
ev.old_val = old_psr[i];
- ev.new_val = new_psr[i];
+ ev.new_val = p->psr[i];
for (j = 0; j < p->num_cb; j++) {
p->cb[j].cb(p->cb[j].handle, &ev);
@@@ -361,14 -383,11 +377,11 @@@ int bd_psr_setting_write(BD_REGISTERS *
return -1;
}
- if (p->psr[reg] == val) {
- BD_DEBUG(DBG_BLURAY, "bd_psr_write(%d, %d): no change in value\n", reg, val);
- return 0;
- }
-
bd_psr_lock(p);
- if (bd_psr_name[reg]) {
+ if (p->psr[reg] == val) {
+ BD_DEBUG(DBG_BLURAY, "bd_psr_write(%d, %d): no change in value\n", reg, val);
+ } else if (bd_psr_name[reg]) {
BD_DEBUG(DBG_BLURAY, "bd_psr_write(): PSR%-4d (%s) 0x%x -> 0x%x\n", reg, bd_psr_name[reg], p->psr[reg], val);
} else {
BD_DEBUG(DBG_BLURAY, "bd_psr_write(): PSR%-4d 0x%x -> 0x%x\n", reg, p->psr[reg], val);
@@@ -378,7 -397,7 +391,7 @@@
BD_PSR_EVENT ev;
unsigned i;
- ev.ev_type = BD_PSR_CHANGE;
+ ev.ev_type = p->psr[reg] == val ? BD_PSR_WRITE : BD_PSR_CHANGE;
ev.psr_idx = reg;
ev.old_val = p->psr[reg];
ev.new_val = val;
--
libbluray packaging
More information about the pkg-multimedia-commits
mailing list