From 8244a3d688fd963536e6ac9ce7dd4344cf357234 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 24 Mar 2009 01:02:28 +0000 Subject: resindvd: Add faststart, and work around some multi-angle issues Add a 'fast-start' property to the rsndvdsrc element, that attempts to jump directly to the DVD menu when starting. Doesn't work correctly on all titles yet. Add workarounds for issues with multiple angles in libdvdnav: Use a heuristic to avoid detecting discontinuities during multiple-angle titles, it seems caused by libdvdnav losing some NAV packets in multiangle titles. Fix seeking in multi-angle titles by aligning our sector calculation logic with libdvdnav's. Also, use libdvdnav's dvdnav_get_current_time() method to determine the logical position of the current cell when it changes, as the cell_start value in the cell_change event provides a number that doesn't compensate for angle cell blocks. --- ext/resindvd/resindvdsrc.c | 121 ++++++++++++++++++++++++++++++++++++++------- ext/resindvd/resindvdsrc.h | 2 + 2 files changed, 106 insertions(+), 17 deletions(-) (limited to 'ext/resindvd') diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c index e76682a0..a9707a64 100644 --- a/ext/resindvd/resindvdsrc.c +++ b/ext/resindvd/resindvdsrc.c @@ -32,6 +32,7 @@ GST_DEBUG_CATEGORY_STATIC (rsndvdsrc_debug); #define GST_CAT_DEFAULT rsndvdsrc_debug #define DEFAULT_DEVICE "/dev/dvd" +#define DEFAULT_FASTSTART TRUE #define GST_FLOW_WOULD_BLOCK GST_FLOW_CUSTOM_SUCCESS @@ -68,7 +69,8 @@ enum enum { ARG_0, - ARG_DEVICE + ARG_DEVICE, + ARG_FASTSTART }; typedef struct @@ -228,11 +230,18 @@ rsn_dvdsrc_class_init (resinDvdSrcClass * klass) g_object_class_install_property (gobject_class, ARG_DEVICE, g_param_spec_string ("device", "Device", "DVD device location", NULL, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, ARG_FASTSTART, + g_param_spec_boolean ("fast-start", "Fast start", + "Skip straight to the DVD menu on start", DEFAULT_FASTSTART, + G_PARAM_READWRITE)); } static void rsn_dvdsrc_init (resinDvdSrc * rsndvdsrc, resinDvdSrcClass * gclass) { + rsndvdsrc->faststart = DEFAULT_FASTSTART; + rsndvdsrc->device = g_strdup (DEFAULT_DEVICE); rsndvdsrc->dvd_lock = g_mutex_new (); rsndvdsrc->branch_lock = g_mutex_new (); @@ -298,6 +307,11 @@ rsn_dvdsrc_set_property (GObject * object, guint prop_id, src->device = g_value_dup_string (value); GST_OBJECT_UNLOCK (src); break; + case ARG_FASTSTART: + GST_OBJECT_LOCK (src); + src->faststart = g_value_get_boolean (value); + GST_OBJECT_UNLOCK (src); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -316,6 +330,11 @@ rsn_dvdsrc_get_property (GObject * object, guint prop_id, g_value_set_string (value, src->device); GST_OBJECT_UNLOCK (src); break; + case ARG_FASTSTART: + GST_OBJECT_LOCK (src); + g_value_set_boolean (value, src->faststart); + GST_OBJECT_UNLOCK (src); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -346,6 +365,15 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc) goto fail; } + if (src->faststart) { + if (dvdnav_title_play (src->dvdnav, 1) != DVDNAV_STATUS_OK || + (dvdnav_menu_call (src->dvdnav, DVD_MENU_Title) != DVDNAV_STATUS_OK && + dvdnav_menu_call (src->dvdnav, + DVD_MENU_Root) != DVDNAV_STATUS_OK)) { + /* Fast start failed. Do normal start */ + dvdnav_reset (src->dvdnav); + } + } src->first_seek = TRUE; src->running = TRUE; @@ -635,6 +663,56 @@ rsn_dvdsrc_do_still (resinDvdSrc * src, int duration) return TRUE; } +static pgc_t * +get_current_pgc (resinDvdSrc * src) +{ + gint title, part, pgc_n; + gint32 vts_ttn; + pgc_t *pgc; + + if (dvdnav_is_domain_fp (src->dvdnav)) { + return src->vmg_file->first_play_pgc; + } + + if (src->vts_n == 0 || src->in_menu) { + /* FIXME: look up current menu PGC */ + return NULL; + } + + if (dvdnav_current_title_info (src->dvdnav, &title, &part) != + DVDNAV_STATUS_OK) + return NULL; + + /* To find the right tmap, we need the title number within this VTS (vts_ttn) + * * from the VMG tt_srpt table... */ + if (title < 1 || title > src->vmg_file->tt_srpt->nr_of_srpts) + return NULL; + + /* We must be in the correct VTS for any of this to succeed... */ + if (src->vts_n != src->vmg_file->tt_srpt->title[title - 1].title_set_nr) + return NULL; + + /* We must also be in the VTS domain to use the tmap table */ + if (src->vts_n == 0) + return NULL; + + vts_ttn = src->vmg_file->tt_srpt->title[title - 1].vts_ttn; + + if (vts_ttn < 1 || vts_ttn > src->vts_file->vts_ptt_srpt->nr_of_srpts) + return NULL; + + if (src->vts_file->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts == 0) + return NULL; + + pgc_n = src->vts_file->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn; + if (pgc_n > src->vts_file->vts_pgcit->nr_of_pgci_srp) + return NULL; + + pgc = src->vts_file->vts_pgcit->pgci_srp[pgc_n - 1].pgc; + + return pgc; +} + static GstFlowReturn rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) { @@ -677,8 +755,14 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) src->in_still_state = FALSE; - if (new_start_ptm != src->cur_end_ts) - discont = TRUE; + if (new_start_ptm != src->cur_end_ts) { + /* Hack because libdvdnav seems to lose a NAV packet during + * angle block changes */ + GstClockTimeDiff diff = GST_CLOCK_DIFF (src->cur_end_ts, new_start_ptm); + if (src->cur_end_ts == GST_CLOCK_TIME_NONE || diff > 2 * GST_SECOND) { + discont = TRUE; + } + } GST_LOG_OBJECT (src, "NAV packet start TS %" GST_TIME_FORMAT " end TS %" GST_TIME_FORMAT " base %" G_GINT64_FORMAT " %s", @@ -764,7 +848,11 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock) dvdnav_cell_change_event_t *event = (dvdnav_cell_change_event_t *) data; src->pgc_duration = MPEGTIME_TO_GSTTIME (event->pgc_length); - src->cur_position = MPEGTIME_TO_GSTTIME (event->cell_start); + /* event->cell_start has the wrong time - it doesn't handle + * multi-angle correctly (as of libdvdnav 4.1.3). The current_time() + * calculates it correctly. */ + src->cur_position = + MPEGTIME_TO_GSTTIME (dvdnav_get_current_time (src->dvdnav)); GST_DEBUG_OBJECT (src, "CELL change dur now %" GST_TIME_FORMAT " position now %" @@ -1908,7 +1996,7 @@ rsn_dvdsrc_get_sector_from_time_tmap (resinDvdSrc * src, GstClockTime ts) vts_tmap_t *title_tmap; gint32 title, part, vts_ttn; guint32 entry, sector, logical_sector; - gint pgc_n, cell_n; + gint cell_n; pgc_t *pgc; if (ts == 0) @@ -1927,7 +2015,7 @@ rsn_dvdsrc_get_sector_from_time_tmap (resinDvdSrc * src, GstClockTime ts) /* To find the right tmap, we need the title number within this VTS (vts_ttn) * from the VMG tt_srpt table... */ - if (title < 1 || title >= src->vmg_file->tt_srpt->nr_of_srpts) + if (title < 1 || title > src->vmg_file->tt_srpt->nr_of_srpts) return -1; /* We must be in the correct VTS for any of this to succeed... */ @@ -1947,10 +2035,11 @@ rsn_dvdsrc_get_sector_from_time_tmap (resinDvdSrc * src, GstClockTime ts) if (vts_ttn < 1 || vts_ttn > vts_tmapt->nr_of_tmaps) return -1; - /* We'll be needing to look up the PGC later, so it better exist */ - if (vts_ttn > src->vts_file->vts_ptt_srpt->nr_of_srpts) + pgc = get_current_pgc (src); + if (pgc == NULL) return -1; + /* Get the time map */ title_tmap = vts_tmapt->tmap + vts_ttn - 1; entry = ts / (title_tmap->tmu * GST_SECOND); if (entry == 0) @@ -1970,24 +2059,22 @@ rsn_dvdsrc_get_sector_from_time_tmap (resinDvdSrc * src, GstClockTime ts) * the cell that contains the time and sector we want, accumulating * the logical sector offsets until we find it */ - if (src->vts_file->vts_ptt_srpt->title[vts_ttn - 1].nr_of_ptts == 0) - return -1; - - pgc_n = src->vts_file->vts_ptt_srpt->title[vts_ttn - 1].ptt[0].pgcn; - if (pgc_n > src->vts_file->vts_pgcit->nr_of_pgci_srp) - return -1; - - pgc = src->vts_file->vts_pgcit->pgci_srp[pgc_n - 1].pgc; - logical_sector = 0; for (cell_n = 0; cell_n < pgc->nr_of_cells; cell_n++) { cell_playback_t *cell = pgc->cell_playback + cell_n; + /* This matches how libdvdnav calculates the logical sector + * in dvdnav_sector_search(): */ + if (sector >= cell->first_sector && sector <= cell->last_sector) { logical_sector += sector - cell->first_sector; break; } + if (cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && + cell->block_mode != BLOCK_MODE_FIRST_CELL) + continue; + logical_sector += (cell->last_sector - cell->first_sector + 1); } diff --git a/ext/resindvd/resindvdsrc.h b/ext/resindvd/resindvdsrc.h index 9bd53413..52f3f349 100644 --- a/ext/resindvd/resindvdsrc.h +++ b/ext/resindvd/resindvdsrc.h @@ -60,6 +60,8 @@ struct _resinDvdSrc { RsnPushSrc parent; + gboolean faststart; + GMutex *dvd_lock; GCond *still_cond; GMutex *branch_lock; -- cgit v1.2.1