ext/resindvd/: Add support for time based seeking.
authorJan Schmidt <thaytan@mad.scientist.com>
Thu, 8 Jan 2009 12:42:18 +0000 (12:42 +0000)
committerJan Schmidt <thaytan@mad.scientist.com>
Thu, 8 Jan 2009 12:42:18 +0000 (12:42 +0000)
Original commit message from CVS:
* ext/resindvd/resindvdbin.c:
* ext/resindvd/resindvdsrc.c:
* ext/resindvd/resindvdsrc.h:
* ext/resindvd/rsnaudiomunge.c:
Add support for time based seeking.
Make setting dvd:// reset to the default device.
Make the 'audiomunge' element send any new segment start before
the 'gap filler' buffer it generates, and any segment closes
after.
Fixes: #566957
ChangeLog
ext/resindvd/resindvdbin.c
ext/resindvd/resindvdsrc.c
ext/resindvd/resindvdsrc.h
ext/resindvd/rsnaudiomunge.c

index 18974ef30f3003d896f678757ffbacfdc4a03f1b..6e60b15a2b420b37b1176848deb23ce456a50cea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-01-08  Jan Schmidt  <jan.schmidt@sun.com>
+
+       * ext/resindvd/resindvdbin.c:
+       * ext/resindvd/resindvdsrc.c:
+       * ext/resindvd/resindvdsrc.h:
+       * ext/resindvd/rsnaudiomunge.c:
+       Add support for time based seeking.
+       Make setting dvd:// reset to the default device.
+       Make the 'audiomunge' element send any new segment start before
+       the 'gap filler' buffer it generates, and any segment closes
+       after.
+       Fixes: #566957
+
 2009-01-08  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
 
        * ext/ladspa/gstladspa.c: (plugin_init):
index ac50fb14d71539ce649cb7e157d4818521c751db..c96ff9446d4958ff84d5474a96a6dc67d84f92c9 100644 (file)
@@ -230,7 +230,10 @@ rsn_dvdbin_uri_set_uri (GstURIHandler * handler, const gchar * uri)
    */
   if (g_str_has_prefix (uri, "dvd://")) {
     g_free (dvdbin->device);
-    dvdbin->device = g_strdup (uri + 6);
+    if (strlen (uri) > 6)
+      dvdbin->device = g_strdup (uri + 6);
+    else
+      dvdbin->device = g_strdup (DEFAULT_DEVICE);
   }
 #if 0
   /*
index 2c742120b1c5149343165999aaeb37d7deda5d59..5844bb72da77023d6c22f93cb021db7d270f7cfe 100644 (file)
@@ -337,6 +337,14 @@ rsn_dvdsrc_start (RsnBaseSrc * bsrc)
     goto fail;
   }
 
+  if (dvdnav_set_PGC_positioning_flag (src->dvdnav, 1) != DVDNAV_STATUS_OK) {
+    GST_ELEMENT_ERROR (src, LIBRARY, FAILED,
+        (_("Failed to set PGC based seeking.")), GST_ERROR_SYSTEM);
+    goto fail;
+  }
+
+
+  src->first_seek = TRUE;
   src->running = TRUE;
   src->branching = FALSE;
   src->discont = TRUE;
@@ -767,10 +775,16 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
     case DVDNAV_VTS_CHANGE:{
       dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t *) data;
 
-      if (dvdnav_is_domain_vmgm (src->dvdnav))
+      if (dvdnav_is_domain_vmgm (src->dvdnav)) {
         src->vts_n = 0;
-      else
+      } else {
         src->vts_n = event->new_vtsN;
+        if (src->vts_file) {
+          ifoClose (src->vts_file);
+          src->vts_file = NULL;
+        }
+        src->vts_file = ifoOpen (src->dvdread, src->vts_n);
+      }
 
       src->in_menu = !dvdnav_is_domain_vtsm (src->dvdnav);
 
@@ -1873,23 +1887,90 @@ rsn_dvdsrc_prepare_seek (RsnBaseSrc * bsrc, GstEvent * event,
       event, segment);
 }
 
+/* Find sector from time using time map if available */
+static gint
+rsn_dvdsrc_get_sector_from_time_tmap (resinDvdSrc * src, GstClockTime ts)
+{
+  vts_tmapt_t *vts_tmapt;
+  vts_tmap_t *title_tmap;
+  gint32 title, part, vts_ttn;
+  guint32 entry;
+
+  if (ts == 0)
+    return 0;
+
+  if (src->vts_file == NULL)
+    return -1;
+
+  if (dvdnav_current_title_info (src->dvdnav, &title, &part) !=
+      DVDNAV_STATUS_OK)
+    return -1;
+
+  /* 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 -1;
+
+  vts_tmapt = src->vts_file->vts_tmapt;
+  if (vts_tmapt == NULL)
+    return -1;
+
+  vts_ttn = src->vmg_file->tt_srpt->title[title - 1].vts_ttn;
+
+  if (vts_ttn < 1 || vts_ttn > vts_tmapt->nr_of_tmaps)
+    return -1;
+
+  title_tmap = vts_tmapt->tmap + vts_ttn - 1;
+  entry = ts / (title_tmap->tmu * GST_SECOND);
+
+  if (entry < title_tmap->nr_of_entries)
+    return title_tmap->map_ent[entry] & 0x7fffffff;
+
+  return -1;
+}
+
+/* call with DVD lock held */
+static gboolean
+rsn_dvdsrc_seek_to_time (resinDvdSrc * src, GstClockTime ts)
+{
+  gint sector;
+  dvdnav_status_t res;
+
+  GST_DEBUG_OBJECT (src, "Time seek requested to ts %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (ts));
+
+  sector = rsn_dvdsrc_get_sector_from_time_tmap (src, ts);
+  if (sector < 0)
+    return FALSE;
+
+  src->discont = TRUE;
+  res = dvdnav_sector_search (src->dvdnav, sector, SEEK_SET);
+
+  if (res != DVDNAV_STATUS_OK)
+    return FALSE;
+
+  return TRUE;
+}
+
 static gboolean
 rsn_dvdsrc_do_seek (RsnBaseSrc * bsrc, GstSegment * segment)
 {
   resinDvdSrc *src = RESINDVDSRC (bsrc);
   gboolean ret = FALSE;
 
-  if (segment->format == rsndvd_format) {
+  if (segment->format == rsndvd_format || src->first_seek) {
     /* The internal format has alread served its purpose of waking
      * everything up and flushing, we just need to step to the next
      * data block (below) so we know our new position */
     ret = TRUE;
+    src->first_seek = FALSE;
   } else {
     /* FIXME: Handle other formats: Time, title, chapter, angle */
     /* HACK to make initial seek work: */
     if (segment->format == GST_FORMAT_TIME) {
-      ret = TRUE;
-      src->discont = TRUE;
+      g_mutex_lock (src->dvd_lock);
+      ret = rsn_dvdsrc_seek_to_time (src, segment->start);
+      g_mutex_unlock (src->dvd_lock);
     } else if (segment->format == title_format) {
       gint titles;
 
index ae88b134de2add25b56b2cb197bb85e85a33a86e..9bd5341345c4eb6c3b6786b0d07810a1b3b93e43 100644 (file)
@@ -85,6 +85,7 @@ struct _resinDvdSrc
 
   gboolean     running;
   gboolean     discont;
+  gboolean     first_seek;
   gboolean     flushing_seek;
   gboolean     need_segment;
   gboolean     active_highlight;
index 457be163ec8db242249eb8fb2e4ea2e77339741f..500671c8d10504fa9e86cd6434a86cbcf157a8a2 100644 (file)
@@ -311,6 +311,15 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
        * Otherwise, send the buffer before the newsegment, so that it appears
        * in the closing segment.
        */
+      if (!update) {
+        GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
+            " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+            GST_TIME_ARGS (segment->accum));
+
+        ret = gst_pad_push_event (munge->srcpad, event);
+      }
+
       if (segment->accum >= AUDIO_FILL_THRESHOLD || munge->in_still) {
         g_print ("***********  Sending audio fill: accum = %" GST_TIME_FORMAT
             " still-state=%d\n", GST_TIME_ARGS (segment->accum),
@@ -326,12 +335,15 @@ rsn_audiomunge_sink_event (GstPad * pad, GstEvent * event)
             GST_TIME_ARGS (segment->accum));
       }
 
-      GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
-          " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
-          GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
-          GST_TIME_ARGS (segment->accum));
+      if (update) {
+        GST_DEBUG_OBJECT (munge, "Sending newsegment: start %" GST_TIME_FORMAT
+            " stop %" GST_TIME_FORMAT " accum now %" GST_TIME_FORMAT,
+            GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
+            GST_TIME_ARGS (segment->accum));
+
+        ret = gst_pad_push_event (munge->srcpad, event);
+      }
 
-      ret = gst_pad_push_event (munge->srcpad, event);
       break;
     }
     case GST_EVENT_CUSTOM_DOWNSTREAM: