[prev in list] [next in list] [prev in thread] [next in thread] 

List:       gstreamer-devel
Subject:    [gst-devel] [RFC][PATCH] Fix and add needed features to dvdnavsrc
From:       Simone Gotti <simone.gotti () email ! it>
Date:       2007-09-11 10:47:01
Message-ID: 1189507621.3150.15.camel () localhost
[Download RAW message or body]

[Attachment #2 (multipart/signed)]

[Attachment #4 (multipart/mixed)]


Hi all,

I worked in the past days to fix dvdnavsrc as it wasn't working (at
least for me) and missing some important features like seeking. I did an
initial patch that I'm attaching here and I'll really appreciate any
comment.

To test all I used this simple pipeline (hadn't tested subpicture
again):

gst-launch dvdnavsrc ! dvddemux name=demux .video_00 ! { queue !
mpeg2dec ! xvimagesink } { demux.current_audio ! queue ! a52dec !
audioconvert ! audioresample ! alsasink }


I'll try to list all the changes I did plus some problems and questions:

*) Add still frame management:
It uses gst_clock_new_single_shot_id on the system clock to wait. The
user operation works correctly during still frames.

*) Add query convert ability.
The functions converts between sectors, bytes and time.
The sector/bytes to time conversion and the opposite con be done in 2
ways:
using the DVD time maps if available (like dvdreadsrc does) or using
time/sector interpolation.

Looks like there a bug in dvdnav_get_position where the pos and length
values aren't correctly calculated. I did a patch that will fix it and
I'll submit it for discussion to the dvdnav developers. In the mean time
dvdnavsrc does a check and if the max sector reported by the tmaps is
less or equal that the one reported by dvdnav_get_position the tmaps
aren't used.

*) Add seeking ability.

*) Also the NAV packets needs to be sended to the demuxer as they
carries
data.

*) Fix chapter number retrieve call (it was using
dvdnav_get_number_of_titles instead of dvdnav_get_number_of_parts).

*) In gst_dvd_nav_src_tca_seek rename program variable to chapter
variable.

*) Remove did_seek gboolean as it's not used anymore.


TODO:
*) Handle seek on title chapter angle: easy to do, I'm waiting to look
if what I did until now is right or it simply sucks :D


Problems / Questions:

1) I removed a lot of segment events as the seek ones are already
managed by the parent basesrc. The other one doesn't do any effect
because looks like dvddemux (and it's parent class) prefer to use the
SRC/pts times provided by the strean to report newsegments downstream.

2) Now, the use of SCR/pts for syncronization is the unique and right
way so no problem.
But I don't think that they are the right way when we are doing position
queries.
The problem is that I have some DVD where the SCR and pts restarts from
0 after some time:

t1: 0
...
tX: 342242432
...
tX+Y: 0 (again)


As a query on the pipeline is asked starting from the sinks a
position query with a time format is reported in the wrong way as the
position time will restart from 0.

By now the unique right way to get a position is asking directly to the
dvdnavsrc. The position will be an aproximation but it will be quite
right and continous. Looking at various codes this way to get the
position is the same done by other projects like VLC and xine.

What do you think about this? The applications that uses dvdnavsrc (but
this problem also affects dvdreadsrc) should do the query directly on it
instead of the pipeline? But how to handle this with
playbin?

Thanks!
Bye!

-- 
Simone Gotti

["dvdnavsrc-megafix-20070911-1227.patch" (dvdnavsrc-megafix-20070911-1227.patch)]

Index: dvdnavsrc.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/ext/dvdnav/dvdnavsrc.c,v
retrieving revision 1.49
diff -u -b -B -p -r1.49 dvdnavsrc.c
--- dvdnavsrc.c	13 Jun 2007 14:29:39 -0000	1.49
+++ dvdnavsrc.c	11 Sep 2007 10:27:38 -0000
@@ -111,6 +111,7 @@ gst_dvd_nav_src_make_dvd_event (GstDvdNa
     GstEvent * event);
      static gboolean gst_dvd_nav_src_query (GstBaseSrc * basesrc,
     GstQuery * query);
+     static gboolean gst_dvd_nav_src_do_seek (GstBaseSrc * src, GstSegment * s);
      static gboolean gst_dvd_nav_src_is_open (GstDvdNavSrc * src);
 
 #if 0
@@ -132,6 +133,11 @@ gst_dvd_nav_src_make_dvd_event (GstDvdNa
 
      static void gst_dvd_nav_src_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
+     static gboolean gst_dvd_nav_src_query_position (GstDvdNavSrc * src,
+    GstFormat format, gint64 * p_val);
+     static gboolean gst_dvd_nav_src_query_duration (GstDvdNavSrc * src,
+    GstFormat format, gint64 * p_val);
+
 
      static guint gst_dvd_nav_src_signals[LAST_SIGNAL];
 
@@ -162,6 +168,13 @@ GST_BOILERPLATE_FULL (GstDvdNavSrc, gst_
   gst_element_class_set_details (element_class, &gst_dvd_nav_src_details);
 }
 
+static gboolean
+gst_dvd_nav_src_is_seekable (GstBaseSrc * src)
+{
+  return TRUE;
+}
+
+
 static void
 gst_dvd_nav_src_class_init (GstDvdNavSrcClass * klass)
 {
@@ -229,7 +242,8 @@ gst_dvd_nav_src_class_init (GstDvdNavSrc
   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_dvd_nav_src_query);
 
   gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_dvd_nav_src_create);
-
+  gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_dvd_nav_src_do_seek);
+  gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_dvd_nav_src_is_seekable);
 #if 0
   gstelement_class->set_clock = gst_dvd_nav_src_set_clock;
 #endif
@@ -248,10 +263,11 @@ gst_dvd_nav_src_init (GstDvdNavSrc * src
   src->last_uri = NULL;
 
   src->pending_offset = -1;
-  src->did_seek = FALSE;
   src->new_seek = FALSE;
   src->seek_pending = FALSE;
   src->need_flush = FALSE;
+  src->use_tmaps = FALSE;
+  src->still_frame = FALSE;
 
   /* Pause mode is initially inactive. */
   src->pause_mode = GST_DVD_NAV_SRC_PAUSE_OFF;
@@ -280,7 +296,9 @@ gst_dvd_nav_src_init (GstDvdNavSrc * src
   src->cell_start = 0;
   src->pg_start = 0;
 
+  src->vmg_file = NULL;
   src->vts_attrs = NULL;
+  src->vts_file = NULL;
   src->cur_vts = 0;
 
   /* avoid unnecessary start/stop in gst_base_src_check_get_range() */
@@ -335,11 +353,9 @@ gst_dvd_nav_src_set_property (GObject * 
 #if 0
     case ARG_TITLE:
       src->uri_title = g_value_get_int (value);
-      src->did_seek = TRUE;
       break;
     case ARG_CHAPTER:
       src->uri_chapter = g_value_get_int (value);
-      src->did_seek = TRUE;
       break;
     case ARG_ANGLE:
       src->uri_angle = g_value_get_int (value);
@@ -517,11 +533,338 @@ gst_dvd_nav_src_set_clock (GstElement * 
 }
 #endif
 
+/* update the time map when the title change */
+static gint
+gst_dvd_nav_src_update_tmaps(GstDvdNavSrc * src)
+{
+  int32_t title, part;
+  gint title_set_nr;
+
+  /* FIXME: check if the title really changed, by now it's called on every
+   * DVDNAV_CELL_CHANGE event.
+   */
+  if (dvdnav_current_title_info(src->dvdnav, &title, &part) != DVDNAV_STATUS_OK)
+    goto current_title_info_failed;
+
+  GST_LOG_OBJECT (src, "title = %d, part = %d", title, part);
+
+  /* load the VTS information for the title set our title is in */
+
+  /* Close old vts file */
+  if (src->vts_file) {
+    ifoClose (src->vts_file);
+    src->vts_file = NULL;
+  }
+   
+  /* There isn't a timemap for the menus */
+  if (title < 1)
+    goto no_tmap;
+
+  title_set_nr = src->tt_srpt->title[title-1].title_set_nr;
+  GST_LOG_OBJECT (src, "titlesetnr = %d", title_set_nr);
+
+  src->vts_file = ifoOpen (src->dvd, title_set_nr);
+  if (src->vts_file == NULL)
+    goto ifo_open_failed;
+
+  src->vts_tmapt = src->vts_file->vts_tmapt;
+  src->vts_ptt_srpt = src->vts_file->vts_ptt_srpt;
+
+  /* Check that the max map entry sector size is >= then the length reported
+   * by dvdnav_get_position, as looks like this function doesn't compute 
+   * correctly the pos and length values.
+   */ 
+  guint32 pos;
+  guint32 length;
+  if (dvdnav_get_position (src->dvdnav, &pos, &length) != DVDNAV_STATUS_OK) {
+    GST_WARNING_OBJECT (src, "Cannot get stream length, "
+      "won't enable tmaps use as we cannot check if they're interaction with dvdnav \
is right"); +  } else {
+    gint i, j;
+    for (i = 0; i < src->vts_tmapt->nr_of_tmaps; ++i) {
+      for (j = 0; j < src->vts_tmapt->tmap[i].nr_of_entries; j++) {
+        if ((src->vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff) >= length)
+          src->use_tmaps = TRUE;
+      }
+    }
+    if (src->use_tmaps) {
+      GST_LOG_OBJECT (src, "Using time maps for seeking");
+    } else {
+      GST_WARNING_OBJECT (src, "Time maps as max sector < than length reported by \
dvdnav: " +        "tmap problem or dvdnav bug?");
+    }
+  }
+
+  
+  if (src->vts_tmapt) {
+    gint i, j;
+
+    GST_LOG_OBJECT (src, "nr_of_tmaps = %d", src->vts_tmapt->nr_of_tmaps);
+    for (i = 0; i < src->vts_tmapt->nr_of_tmaps; ++i) {
+      GST_LOG_OBJECT (src, "======= Table %d ===================", i);
+      GST_LOG_OBJECT (src, "Offset relative to VTS_TMAPTI: %d",
+          src->vts_tmapt->tmap_offset[i]);
+      GST_LOG_OBJECT (src, "Time unit (seconds)          : %d",
+          src->vts_tmapt->tmap[i].tmu);
+      GST_LOG_OBJECT (src, "Number of entries            : %d",
+          src->vts_tmapt->tmap[i].nr_of_entries);
+      for (j = 0; j < src->vts_tmapt->tmap[i].nr_of_entries; j++) {
+        guint64 time;
+
+        time = src->vts_tmapt->tmap[i].tmu * (j + 1) * GST_SECOND;
+        GST_LOG_OBJECT (src, "Time: %" GST_TIME_FORMAT " VOBU "
+            "Sector: %d %s", GST_TIME_ARGS (time),
+            src->vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff,
+            (src->vts_tmapt->tmap[i].map_ent[j] >> 31) ? "discontinuity" : "");
+      }
+    }
+  } else {
+    GST_WARNING_OBJECT (src, "no vts_tmapt - will use time interpolation");
+  }
+
+  return TRUE;
+
+ifo_open_failed:
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("Could not open DVD")),
+        ("ifoOpen() failed: %s", g_strerror (errno)));
+    return FALSE;
+  }
+
+current_title_info_failed:
+  {
+    GST_LOG_OBJECT (src, "Failed getting current title informations!");
+    return FALSE;
+  }
+
+no_tmap:
+  {
+    GST_LOG_OBJECT (src, "Time map not available for menus");
+    src->use_tmaps = FALSE;
+    return FALSE;
+  }
+}
+
+/* Find sector from time using time map if available */
+/* FIXME: do interpolation as in gst_dvd_nav_src_get_time_for_sector_tmap */
+static gint
+gst_dvd_nav_src_get_sector_from_time_tmap (GstDvdNavSrc * src, GstClockTime ts)
+{
+  gint sector, i, j;
+
+  if (src->vts_tmapt == NULL || src->vts_tmapt->nr_of_tmaps == 0)
+    return -1;
+
+  sector = 0;
+  for (i = 0; i < src->vts_tmapt->nr_of_tmaps; ++i) {
+    for (j = 0; j < src->vts_tmapt->tmap[i].nr_of_entries; ++j) {
+      GstClockTime entry_time;
+
+      entry_time = src->vts_tmapt->tmap[i].tmu * (j + 1) * GST_SECOND;
+      if (entry_time <= ts) {
+        sector = src->vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff;
+      }
+      if (entry_time >= ts) {
+        return sector;
+      }
+    }
+  }
+
+  if (ts == 0)
+    return 0;
+
+  return -1;
+}
+
+/* Find time for sector using time map, does interpolation */
+static GstClockTime
+gst_dvd_nav_src_get_time_for_sector_tmap (GstDvdNavSrc * src, guint sector)
+{
+  gint i, j;
+  guint prev_sector = 0;
+  guint cur_sector = 0;
+  GstClockTime target, diff;
+
+  if (src->vts_tmapt == NULL || src->vts_tmapt->nr_of_tmaps == 0) {
+    return GST_CLOCK_TIME_NONE;
+  }
+
+  for (i = 0; i < src->vts_tmapt->nr_of_tmaps; ++i) {
+    for (j = 0; j < src->vts_tmapt->tmap[i].nr_of_entries; ++j) {
+      prev_sector = cur_sector;
+      cur_sector = src->vts_tmapt->tmap[i].map_ent[j] & 0x7fffffff;
+      if (sector >= prev_sector && sector <= cur_sector) {
+        target = src->vts_tmapt->tmap[i].tmu * j * GST_SECOND;
+        if (j < src->vts_tmapt->tmap[i].nr_of_entries - 1) {
+          diff = src->vts_tmapt->tmap[i].tmu * GST_SECOND * ( sector - prev_sector) \
/ ( cur_sector - prev_sector); +          target += diff;
+        }
+        return target;
+      }
+    }
+  }
+
+  if (sector == 0)
+    return (GstClockTime) 0;
+
+  return GST_CLOCK_TIME_NONE;
+}
+
+/* Find time for sector */
+static GstClockTime
+gst_dvd_nav_src_get_time_for_sector (GstDvdNavSrc * src, guint sector)
+{
+  GstClockTime time;
+
+  if (src->use_tmaps) {
+    time = gst_dvd_nav_src_get_time_for_sector_tmap (src, sector);
+    if (time != GST_CLOCK_TIME_NONE)
+      return time;
+  }
+  /* Fallback to average time calculation */
+  time = (GstClockTime)((float)sector / src->sector_length * src->pgc_length);
+
+  return time;
+}
+
+/* Find sector from time */
+static GstClockTime
+gst_dvd_nav_src_get_sector_from_time (GstDvdNavSrc * src, GstClockTime time)
+{
+  gint sector;
+
+  if (src->use_tmaps) {
+    sector = gst_dvd_nav_src_get_sector_from_time_tmap (src, time);
+    if (sector >= 0)
+      return sector;
+  }
+
+  /* Fallback to average sector calculation */
+  sector = (GstClockTime)((float)time / src->pgc_length * src->sector_length);
+
+  return sector;
+}
+
+static gboolean
+gst_dvd_nav_src_do_convert_query (GstDvdNavSrc * src, GstQuery * query)
+{
+  GstFormat src_format, dest_format;
+  gboolean ret = FALSE;
+  gint64 src_val, dest_val = -1;
+
+  gst_query_parse_convert (query, &src_format, &src_val, &dest_format, NULL);
+
+  if (src_format == dest_format) {
+    dest_val = src_val;
+    ret = TRUE;
+    goto done;
+  }
+  
+  /* FIXME: handle also chapter format */
+  /* Formats to consider: TIME, DEFAULT, BYTES, title, chapter, sector.
+   * Note: title and chapter are counted as starting from 0 here, just like
+   * in the context of seek events. Another note: DEFAULT format is undefined */
+
+  if (src_format == GST_FORMAT_BYTES) {
+    src_format = sector_format;
+    src_val /= DVD_SECTOR_SIZE;
+  }
+
+  if (src_format == sector_format) {
+    /* SECTOR => xyz */
+    if (dest_format == GST_FORMAT_TIME && src_val < G_MAXUINT) {
+      dest_val = gst_dvd_nav_src_get_time_for_sector(src, src_val);
+      ret = (dest_val >= 0);
+    } else if (dest_format == GST_FORMAT_BYTES) {
+      dest_val = src_val * DVD_SECTOR_SIZE;
+      ret = TRUE;
+    } else {
+      ret = FALSE;
+    }
+  } else if (src_format == title_format) {
+    /* TITLE => xyz */
+    if (dest_format == GST_FORMAT_TIME) {
+      /* not really true, but we use this to trick the base source into
+       * handling seeks in title-format for us (the source won't know that
+       * we changed the title in this case) (changing titles should really
+       * be done with an interface rather than a seek, but for now we're
+       * stuck with this mechanism. Fix in 0.11) */
+      dest_val = (GstClockTime) 0;
+      ret = TRUE;
+    } else {
+      ret = FALSE;
+    }
+  } else if (src_format == GST_FORMAT_TIME) {
+    /* TIME => sectors */
+    if (dest_format == sector_format || dest_format == GST_FORMAT_BYTES) {
+      dest_val = gst_dvd_nav_src_get_sector_from_time(src, src_val);
+      ret = (dest_val >= 0);
+      /* TIME => bytes */
+      if (dest_format == GST_FORMAT_BYTES) {
+        dest_val *= DVD_VIDEO_LB_LEN;
+      }
+    }
+  } else {
+    ret = FALSE;
+  }
+
+done:
+
+  if (ret) {
+    gst_query_set_convert (query, src_format, src_val, dest_format, dest_val);
+  }
+
+  return ret;
+}
+
+/* FIXME: handle also title, chapter, angle format */
+static gboolean
+gst_dvd_nav_src_do_seek (GstBaseSrc * basesrc, GstSegment * s)
+{
+  GstDvdNavSrc *src;
+
+  src = GST_DVD_NAV_SRC (basesrc);
+
+  /* On the first call of do_seek in gstbasesrc during gst_base_src_activate_push \
the dvdnav vm +   * isn't running. Return TRUE as the seek was done.
+   */
+  if (src->first_seek == TRUE) {
+      src->first_seek = FALSE;
+      return TRUE;
+  }
+
+  GST_DEBUG_OBJECT (src, "Seeking to %s: %12" G_GINT64_FORMAT,
+      gst_format_get_name (s->format), s->last_stop);
+
+  if (s->format == sector_format || s->format == GST_FORMAT_BYTES || s->format == \
GST_FORMAT_TIME) { +    gint sector = 0;
+
+    /* Convert in sector format */
+    if(s->format == GST_FORMAT_BYTES) {
+      sector = s->last_stop / DVD_SECTOR_SIZE;
+    } else if (s->format == GST_FORMAT_TIME) {
+      sector = gst_dvd_nav_src_get_sector_from_time (src, s->last_stop);
+    } 
+
+    if (dvdnav_sector_search (src->dvdnav, sector , SEEK_SET) != DVDNAV_STATUS_OK) {
+      GST_DEBUG_OBJECT (src, "seek to %s %d failed", gst_format_get_name \
(s->format), s->last_stop); +      return FALSE;
+    }
+    GST_LOG_OBJECT (src, "seek to %s %d ok", gst_format_get_name (s->format), \
s->last_stop); +  
+    } else {
+    g_return_val_if_reached (FALSE);
+  }
+  return TRUE;
+}
+
+
 static gboolean
 gst_dvd_nav_src_tca_seek (GstDvdNavSrc * src, gint title, gint chapter,
     gint angle)
 {
-  int titles, programs, curangle, angles;
+  int titles, chapters, curangle, angles;
 
   g_return_val_if_fail (src != NULL, FALSE);
   g_return_val_if_fail (src->dvdnav != NULL, FALSE);
@@ -554,14 +897,14 @@ gst_dvd_nav_src_tca_seek (GstDvdNavSrc *
   }
 
   /* Make sure the chapter number is valid for this title */
-  if (dvdnav_get_number_of_titles (src->dvdnav, &programs)
+  if (dvdnav_get_number_of_parts (src->dvdnav, title, &chapters)
       != DVDNAV_STATUS_OK) {
     GST_ERROR ("dvdnav_get_number_of_programs: %s",
         dvdnav_err_to_string (src->dvdnav));
     return FALSE;
   }
-  GST_INFO_OBJECT (src, "there are %d chapters in this title", programs);
-  if (chapter < 0 || chapter > programs) {
+  GST_INFO_OBJECT (src, "there are %d chapters in this title", chapters);
+  if (chapter < 0 || chapter > chapters) {
     GST_ERROR_OBJECT (src, "invalid chapter %d", chapter);
     return FALSE;
   }
@@ -599,7 +942,6 @@ gst_dvd_nav_src_tca_seek (GstDvdNavSrc *
     return FALSE;
   }
 
-  src->did_seek = TRUE;
 
   return TRUE;
 }
@@ -741,7 +1083,8 @@ gst_dvd_nav_src_update_highlight (GstDvd
     src->button = button;
 
     GST_DEBUG ("Sending dvd-spu-highlight for button %d", button);
-    gst_pad_push_event (GST_BASE_SRC_PAD (src), event);
+    int ret = gst_pad_push_event (GST_BASE_SRC_PAD (src), event);
+    GST_DEBUG ("End Sending dvd-spu-highlight for button %d, ret: %d", button, ret);
   }
 }
 
@@ -1252,6 +1595,11 @@ gst_dvd_nav_src_process_next_block (GstD
     return GST_FLOW_ERROR;
   }
 
+  /* If the next block is not DVDNAV_STILL_FRAME we can seek */
+  if (event != DVDNAV_STILL_FRAME) {
+    src->still_frame = FALSE;
+  } 
+
   switch (event) {
     case DVDNAV_NOP:
       break;
@@ -1261,7 +1609,9 @@ gst_dvd_nav_src_process_next_block (GstD
       break;
     }
     case DVDNAV_STILL_FRAME:{
+      src->still_frame = TRUE;
       dvdnav_still_event_t *info = (dvdnav_still_event_t *) data;
+        gst_dvd_nav_src_print_event (src, data, event, len);
 
       if (src->pause_mode == GST_DVD_NAV_SRC_PAUSE_OFF) {
         gst_dvd_nav_src_print_event (src, data, event, len);
@@ -1274,12 +1624,11 @@ gst_dvd_nav_src_process_next_block (GstD
         } else {
           src->pause_mode = GST_DVD_NAV_SRC_PAUSE_LIMITED;
           src->pause_remain = info->length * GST_SECOND;
-/* FIXME */
-#if 0
+          gint64 val;
+          gst_dvd_nav_src_query_position (src, GST_FORMAT_TIME, &val);
           GST_INFO_OBJECT (src,
-              "starting limited pause: %d seconds at %llu",
-              info->length, gst_element_get_time (GST_ELEMENT (src)));
-#endif
+              "starting limited pause: %d seconds at %" GST_TIME_FORMAT,
+              info->length, GST_TIME_ARGS(val));
         }
 
         /* For the moment, send the first empty event to let
@@ -1295,22 +1645,15 @@ gst_dvd_nav_src_process_next_block (GstD
 
       if (src->pause_mode == GST_DVD_NAV_SRC_PAUSE_UNLIMITED ||
           src->pause_remain > 0) {
-/* FIXME */
-#if 0
-        GstEvent *event;
 
-        /* Send a filler event to keep the pipeline going */
-        event = gst_event_new_filler_stamped (GST_CLOCK_TIME_NONE,
-            MIN (src->pause_remain, DVD_NAV_SRC_PAUSE_INTERVAL));
-        send_data = GST_DATA (event);
+        GST_DEBUG_OBJECT (src, "sleeping %d during still frame", \
GST_DVD_NAV_SRC_PAUSE_INTERVAL); +        GstClock* system_clock = \
gst_system_clock_obtain(); +        GstClockTime cur_time = \
gst_clock_get_internal_time(system_clock); +        GstClockID id = \
gst_clock_new_single_shot_id (system_clock, cur_time + \
GST_DVD_NAV_SRC_PAUSE_INTERVAL); +        gst_clock_id_wait (id, NULL);
+        gst_clock_id_unref (id);
+        
 
-        GST_DEBUG_OBJECT (src,
-            "Pause mode %d, Sending filler at %" G_GUINT64_FORMAT
-            ", dur %" G_GINT64_FORMAT ", remain %" G_GINT64_FORMAT,
-            src->pause_mode, gst_element_get_time (GST_ELEMENT (src)),
-            MIN (src->pause_remain, DVD_NAV_SRC_PAUSE_INTERVAL),
-            src->pause_remain);
-#endif
         if (src->pause_mode == GST_DVD_NAV_SRC_PAUSE_LIMITED) {
           if (src->pause_remain < GST_DVD_NAV_SRC_PAUSE_INTERVAL)
             src->pause_remain = 0;
@@ -1322,7 +1665,6 @@ gst_dvd_nav_src_process_next_block (GstD
          * advancing */
         if (src->pause_mode == GST_DVD_NAV_SRC_PAUSE_UNLIMITED ||
             src->pause_remain > 0)
-          src->did_seek = TRUE;
 
         break;
       } else {
@@ -1332,8 +1674,8 @@ gst_dvd_nav_src_process_next_block (GstD
           GST_WARNING_OBJECT (src, "dvdnav_still_skip failed: %s",
               dvdnav_err_to_string (src->dvdnav));
         }
-        /* Schedule a discont to reset the time */
-        src->did_seek = TRUE;
+        /* Flush to ensure that data after the wait is played correctly */
+        src->need_flush = TRUE;
       }
       break;
     }
@@ -1378,7 +1720,17 @@ gst_dvd_nav_src_process_next_block (GstD
           " cell_start %" GST_TIME_FORMAT ", pg_start %" GST_TIME_FORMAT,
           GST_TIME_ARGS (src->pgc_length),
           GST_TIME_ARGS (src->cell_start), GST_TIME_ARGS (src->pg_start));
+
+      /* Update the current length in sectors */
+      guint32 pos;
+      if (dvdnav_get_position (src->dvdnav, &pos, &src->sector_length) != \
DVDNAV_STATUS_OK)  +        GST_WARNING_OBJECT (src, "Cannot get new stream length \
after DVDNAV_CELL_CHANGE"); +
+      /* Update the time maps */
+      gst_dvd_nav_src_update_tmaps (src);
+
       gst_dvd_nav_src_update_streaminfo (src);
+
       break;
     }
     case DVDNAV_NAV_PACKET:{
@@ -1397,11 +1749,15 @@ gst_dvd_nav_src_process_next_block (GstD
 
       /* Send a dvd nav packet event. */
       gst_dvd_nav_src_push_dvd_nav_packet_event (src, pci);
+
+      /* The NAV packet contains also data, so send it */
+      *p_buf = src->cur_buf;
+      src->cur_buf = NULL;
       break;
     }
     case DVDNAV_SPU_CLUT_CHANGE:{
       /* FIXME: does this work on 64-bit/big-endian machines? (tpm) */
-      gst_dvd_nav_src_push_clut_change_event (src, (guint *) data);
+      //gst_dvd_nav_src_push_clut_change_event (src, (guint *) data);
       break;
     }
     case DVDNAV_VTS_CHANGE:{
@@ -1504,6 +1861,8 @@ gst_dvd_nav_src_process_next_block (GstD
 
       src->button = 0;
       src->pause_mode = GST_DVD_NAV_SRC_PAUSE_OFF;
+      /* If seeking the flush is already sent by the basesrc parent class */
+      if (!src->seek_pending)
       src->need_flush = TRUE;
       /* was commented out already: */
       /* send_data = GST_DATA (gst_event_new_flush ()); */
@@ -1548,36 +1907,10 @@ gst_dvd_nav_src_create (GstPushSrc * pus
       GST_INFO_OBJECT (src, "sending flush");
       gst_pad_push_event (GST_BASE_SRC_PAD (src), gst_event_new_flush_start ());
       gst_pad_push_event (GST_BASE_SRC_PAD (src), gst_event_new_flush_stop ());
-      gst_dvd_nav_src_update_highlight (src, TRUE);
-    }
-
-    if (src->pause_mode == GST_DVD_NAV_SRC_PAUSE_OFF) {
-/* FIXME */
-      if (src->did_seek) {
-        GstEvent *event;
-
-        src->did_seek = FALSE;
-        GST_INFO_OBJECT (src, "sending newsegment event with offset %"
-            G_GINT64_FORMAT, src->pending_offset);
-
-        if (src->pending_offset != -1) {
-          event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
-              src->pending_offset, -1, src->pending_offset);
-          src->pending_offset = -1;
-        } else {
-          /* g_warning ("dvdnav: FIXME - what newsegment to send here?"); */
-          event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
-              0, -1, 0);
-          /* was: gst_event_new_discontinuous (FALSE, GST_FORMAT_UNDEFINED); */
-        }
 
-        gst_pad_push_event (GST_BASE_SRC_PAD (src), event);
-
-        /* Sent a discont, make sure to enable highlight */
-        src->button = 0;
         gst_dvd_nav_src_update_highlight (src, TRUE);
       }
-    }
+
     ret = gst_dvd_nav_src_process_next_block (src, p_buf);
   }
   while (ret == GST_FLOW_OK && *p_buf == NULL);
@@ -1599,6 +1932,23 @@ gst_dvd_nav_src_start (GstBaseSrc * base
     return FALSE;
   }
 
+  /* Load the video manager to find out the information about the titles */
+  src->dvd = DVDOpen (src->device);
+  if (!src->dvd)
+    return FALSE;
+ 
+  GST_DEBUG_OBJECT (src, "Loading VMG info");
+
+  if (!(src->vmg_file = ifoOpen (src->dvd, 0)))
+  {
+    GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
+        (_("Could not open DVD")),
+        ("ifoOpen() failed: %s", g_strerror (errno)));
+    return FALSE;
+  }
+
+  src->tt_srpt = src->vmg_file->tt_srpt;
+
   if (dvdnav_open (&src->dvdnav, src->device) != DVDNAV_STATUS_OK) {
     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
         (_("Failed to open DVD device '%s'."), src->device));
@@ -1662,7 +2012,8 @@ gst_dvd_nav_src_start (GstBaseSrc * base
   }
 
   src->streaminfo = NULL;
-  src->did_seek = TRUE;
+  src->use_tmaps = FALSE;
+  src->first_seek = TRUE;
 
   return TRUE;
 }
@@ -1678,6 +2029,15 @@ gst_dvd_nav_src_stop (GstBaseSrc * bases
     return FALSE;
   }
 
+  /* Close old vts file if opened */
+  if (src->vts_file)
+    ifoClose (src->vts_file);
+
+  /* Close the video manager */
+  ifoClose (src->vmg_file);
+
+  DVDClose (src->dvd);
+
   return TRUE;
 }
 
@@ -1724,7 +2084,6 @@ gst_dvd_nav_src_handle_navigation_event 
       if (dvdnav_current_title_info (src->dvdnav, &title, &part) && title > 0
           && part > 1) {
         dvdnav_part_play (src->dvdnav, title, part - 1);
-        src->did_seek = TRUE;
       }
     } else if (g_str_equal (key, "period")) {
       gint title = 0;
@@ -1732,7 +2091,6 @@ gst_dvd_nav_src_handle_navigation_event 
 
       if (dvdnav_current_title_info (src->dvdnav, &title, &part) && title > 0) {
         dvdnav_part_play (src->dvdnav, title, part + 1);
-        src->did_seek = TRUE;
       }
     }
 
@@ -1761,11 +2119,73 @@ gst_dvd_nav_src_handle_navigation_event 
   return TRUE;
 }
 
+/* FIXME: handle also angle format */
 static gboolean
 gst_dvd_nav_src_handle_seek_event (GstDvdNavSrc * src, GstEvent * event)
 {
-/* FIXME: */
+  GstSeekFlags flags;
+  GstSeekType cur_type, end_type;
+  gint64 new_off;
+  GstFormat format;
+  gdouble rate;
+
+  gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &new_off,
+      &end_type, NULL);
+
+  /* Cannot seek during another seek */
+  if (src->seek_pending) {
+    GST_WARNING_OBJECT(src, "Cannot seek during another seek");
+    return FALSE;
+  }
+
+  /* If we are in a still frame we cannot seek */
+  if (src->still_frame) {
+    GST_WARNING_OBJECT(src, "Cannot seek during a still frame");
+    return FALSE;
+  }
+ 
+  if (rate <= 0.0) {
+    GST_DEBUG_OBJECT (src, "cannot do backwards playback yet");
+    return FALSE;
+  }
+
+  if ((flags & GST_SEEK_FLAG_SEGMENT) != 0) {
+    GST_DEBUG_OBJECT (src, "segment seek not supported");
+    return FALSE;
+  }
+
+  if ((flags & GST_SEEK_FLAG_FLUSH) == 0) {
+    GST_DEBUG_OBJECT (src, "can only do flushing seeks at the moment");
+    return FALSE;
+  }
+
+  if (end_type != GST_SEEK_TYPE_NONE) {
+    GST_DEBUG_OBJECT (src, "end seek type not supported");
+    return FALSE;
+  }
+
+  if (cur_type != GST_SEEK_TYPE_SET) {
+    GST_DEBUG_OBJECT (src, "only SEEK_TYPE_SET is supported");
+    return FALSE;
+  }
+
+  if (format != chapter_format && format != title_format &&
+      format != GST_FORMAT_BYTES && format != GST_FORMAT_TIME) {
+    GST_DEBUG_OBJECT (src, "unsupported seek format %d (%s)", format,
+        gst_format_get_name (format));
+    return FALSE;
+  }
+
+  src->seek_pending = TRUE;
+
+  return GST_BASE_SRC_CLASS (parent_class)->event (GST_BASE_SRC (src), event);
+}
+
+/* FIXME: please remove me, I use disk space without a reason. thanks. */
 #if 0
+static gboolean
+gst_dvd_nav_src_handle_seek_event (GstDvdNavSrc * src, GstEvent * event)
+{
   gint64 offset;
   gint format;
   int titles, title, new_title;
@@ -1912,9 +2332,9 @@ gst_dvd_nav_src_handle_seek_event (GstDv
 error:
 
   GST_DEBUG_OBJECT (src, "seek failed");
-#endif
   return FALSE;
 }
+#endif
 
 static gboolean
 gst_dvd_nav_src_src_event (GstBaseSrc * basesrc, GstEvent * event)
@@ -1962,6 +2382,16 @@ gst_dvd_nav_src_query_position (GstDvdNa
   } else if (format == GST_FORMAT_BYTES) {
     if (dvdnav_get_position (src->dvdnav, &pos, &len) == DVDNAV_STATUS_OK)
       *p_val = (gint64) pos *DVD_SECTOR_SIZE;
+  } else if (format == GST_FORMAT_TIME) {
+    if (dvdnav_get_position (src->dvdnav, &pos, &len) == DVDNAV_STATUS_OK)
+      *p_val = (gint64) gst_dvd_nav_src_get_time_for_sector(src, pos);
+      /* libdvnav from svn at at least 20070503 provide this new function
+       * dvdnav_get_current_time, I used it just to test that the values
+       * provided by the timemap were rights but I won't use it as the values
+       * it return changes only every ~0.5 seconds or less depending on how
+       * much sectors are contained in a cell.
+       *p_val = dvdnav_get_current_time(src->dvdnav) * GST_SECOND / 90000;
+       */
   } else if (format == title_format) {
     if (dvdnav_current_title_info (src->dvdnav, &title, &x) == DVDNAV_STATUS_OK)
       *p_val = title;
@@ -2039,6 +2469,10 @@ gst_dvd_nav_src_query (GstBaseSrc * base
       }
       break;
     }
+    case GST_QUERY_CONVERT:{
+      res = gst_dvd_nav_src_do_convert_query (src, query);
+      break;
+    }
     default:{
       res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
       break;
@@ -2174,7 +2608,7 @@ gst_dvd_nav_src_do_init (GType dvdnavsrc
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-  if (!gst_element_register (plugin, "dvdnavsrc", GST_RANK_NONE,
+  if (!gst_element_register (plugin, "dvdnavsrc", GST_RANK_PRIMARY,
           /* GST_RANK_PRIMARY + 1, */ GST_TYPE_DVD_NAV_SRC)) {
     return FALSE;
   }
Index: dvdnavsrc.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-ugly/ext/dvdnav/dvdnavsrc.h,v
retrieving revision 1.3
diff -u -b -B -p -r1.3 dvdnavsrc.h
--- dvdnavsrc.h	26 Feb 2006 22:33:33 -0000	1.3
+++ dvdnavsrc.h	11 Sep 2007 10:27:39 -0000
@@ -66,10 +66,12 @@ struct _GstDvdNavSrc
   gchar                   *last_uri;
 
   gint64                   pending_offset;  /* Next newsegment event offset */
-  gboolean                 did_seek;
   gboolean                 new_seek;
   gboolean                 seek_pending;
   gboolean                 need_flush;
+  gboolean                 first_seek;
+  gboolean                 use_tmaps;
+  gboolean                 still_frame;
 
   /* Timing */
 #if 0
@@ -123,6 +125,14 @@ struct _GstDvdNavSrc
   GArray                   *vts_attrs;       /* Array of vts_attributes_t    *
                                               * structures  cached from      *
                                               * the VMG ifo                  */
+  guint32                   sector_length;
+
+  dvd_reader_t              *dvd;
+  ifo_handle_t              *vmg_file;
+  tt_srpt_t                 *tt_srpt;
+  vts_ptt_srpt_t            *vts_ptt_srpt;
+  ifo_handle_t              *vts_file;
+  vts_tmapt_t               *vts_tmapt;
 };
 
 struct _GstDvdNavSrcClass


["signature.asc" (application/pgp-signature)]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/

_______________________________________________
gstreamer-devel mailing list
gstreamer-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gstreamer-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic