[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