mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 20:42:30 +00:00
ext/dvdread/dvdreadsrc.*: Rewrite seeking code and make seeking in DVDs work (#337834).
Original commit message from CVS: * ext/dvdread/dvdreadsrc.c: (gst_dvd_read_src_init), (gst_dvd_read_src_is_seekable), (gst_dvd_read_src_class_init), (gst_dvd_read_src_stop), (gst_dvd_read_src_goto_title), (gst_dvd_read_src_create), (gst_dvd_read_src_handle_seek_event), (gst_dvd_read_src_do_seek), (gst_dvd_read_src_src_event): * ext/dvdread/dvdreadsrc.h: Rewrite seeking code and make seeking in DVDs work (#337834).
This commit is contained in:
parent
9565d1bcff
commit
8d65dca6e9
3 changed files with 167 additions and 136 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2006-06-30 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* ext/dvdread/dvdreadsrc.c: (gst_dvd_read_src_init),
|
||||
(gst_dvd_read_src_is_seekable), (gst_dvd_read_src_class_init),
|
||||
(gst_dvd_read_src_stop), (gst_dvd_read_src_goto_title),
|
||||
(gst_dvd_read_src_create), (gst_dvd_read_src_handle_seek_event),
|
||||
(gst_dvd_read_src_do_seek), (gst_dvd_read_src_src_event):
|
||||
* ext/dvdread/dvdreadsrc.h:
|
||||
Rewrite seeking code and make seeking in DVDs work (#337834).
|
||||
|
||||
2006-06-29 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* autogen.sh:
|
||||
|
|
|
@ -87,6 +87,7 @@ static void gst_dvd_read_src_get_property (GObject * object, guint prop_id,
|
|||
static GstEvent *gst_dvd_read_src_make_clut_change_event (GstDvdReadSrc * src,
|
||||
const guint * clut);
|
||||
static gboolean gst_dvd_read_src_get_size (GstDvdReadSrc * src, gint64 * size);
|
||||
static gboolean gst_dvd_read_src_do_seek (GstBaseSrc * src, GstSegment * s);
|
||||
|
||||
GST_BOILERPLATE_FULL (GstDvdReadSrc, gst_dvd_read_src, GstPushSrc,
|
||||
GST_TYPE_PUSH_SRC, gst_dvd_read_src_do_init);
|
||||
|
@ -130,9 +131,6 @@ gst_dvd_read_src_init (GstDvdReadSrc * src, GstDvdReadSrcClass * klass)
|
|||
src->uri_chapter = 1;
|
||||
src->uri_angle = 1;
|
||||
|
||||
src->seek_pend = FALSE;
|
||||
src->flush_pend = FALSE;
|
||||
src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
|
||||
src->title_lang_event_pending = NULL;
|
||||
src->pending_clut_event = NULL;
|
||||
|
||||
|
@ -141,6 +139,12 @@ gst_dvd_read_src_init (GstDvdReadSrc * src, GstDvdReadSrcClass * klass)
|
|||
gst_static_pad_template_get_caps (&srctemplate));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_dvd_read_src_is_seekable (GstBaseSrc * src)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dvd_read_src_class_init (GstDvdReadSrcClass * klass)
|
||||
{
|
||||
|
@ -169,6 +173,9 @@ gst_dvd_read_src_class_init (GstDvdReadSrcClass * klass)
|
|||
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_dvd_read_src_stop);
|
||||
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_dvd_read_src_src_query);
|
||||
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_dvd_read_src_src_event);
|
||||
gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_dvd_read_src_do_seek);
|
||||
gstbasesrc_class->is_seekable =
|
||||
GST_DEBUG_FUNCPTR (gst_dvd_read_src_is_seekable);
|
||||
|
||||
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_dvd_read_src_create);
|
||||
}
|
||||
|
@ -264,9 +271,7 @@ gst_dvd_read_src_stop (GstBaseSrc * basesrc)
|
|||
src->change_cell = FALSE;
|
||||
src->chapter = 0;
|
||||
src->title = 0;
|
||||
src->flush_pend = FALSE;
|
||||
src->seek_pend = FALSE;
|
||||
src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
|
||||
src->need_newsegment = TRUE;
|
||||
if (src->title_lang_event_pending) {
|
||||
gst_event_unref (src->title_lang_event_pending);
|
||||
src->title_lang_event_pending = NULL;
|
||||
|
@ -379,7 +384,6 @@ gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title, gint angle)
|
|||
gchar lang_code[3] = { '\0', '\0', '\0' }, *t;
|
||||
gint title_set_nr;
|
||||
gint num_titles;
|
||||
gint num_angles;
|
||||
gint i;
|
||||
|
||||
/* make sure our title number is valid */
|
||||
|
@ -392,12 +396,12 @@ gst_dvd_read_src_goto_title (GstDvdReadSrc * src, gint title, gint angle)
|
|||
GST_INFO_OBJECT (src, "Title %d has %d chapters", title, src->num_chapters);
|
||||
|
||||
/* make sure the angle number is valid for this title */
|
||||
num_angles = src->tt_srpt->title[title].nr_of_angles;
|
||||
GST_LOG_OBJECT (src, "Title %d has %d angles", title, num_angles);
|
||||
if (angle < 0 || angle >= num_angles) {
|
||||
src->num_angles = src->tt_srpt->title[title].nr_of_angles;
|
||||
GST_LOG_OBJECT (src, "Title %d has %d angles", title, src->num_angles);
|
||||
if (angle < 0 || angle >= src->num_angles) {
|
||||
GST_WARNING_OBJECT (src, "Invalid angle %d (only %d available)",
|
||||
angle, num_angles);
|
||||
angle = CLAMP (angle, 0, num_angles - 1);
|
||||
angle, src->num_angles);
|
||||
angle = CLAMP (angle, 0, src->num_angles - 1);
|
||||
}
|
||||
|
||||
/* load the VTS information for the title set our title is in */
|
||||
|
@ -695,34 +699,11 @@ gst_dvd_read_src_create (GstPushSrc * pushsrc, GstBuffer ** p_buf)
|
|||
|
||||
srcpad = GST_BASE_SRC (src)->srcpad;
|
||||
|
||||
/* handle events, if any */
|
||||
if (src->seek_pend) {
|
||||
if (src->flush_pend) {
|
||||
gst_pad_push_event (srcpad, gst_event_new_flush_start ());
|
||||
gst_pad_push_event (srcpad, gst_event_new_flush_stop ());
|
||||
src->flush_pend = FALSE;
|
||||
}
|
||||
|
||||
if (src->seek_pend_fmt != GST_FORMAT_UNDEFINED) {
|
||||
if (src->seek_pend_fmt == title_format) {
|
||||
gst_dvd_read_src_goto_title (src, src->title, src->angle);
|
||||
}
|
||||
gst_dvd_read_src_goto_chapter (src, src->chapter);
|
||||
|
||||
src->seek_pend_fmt = GST_FORMAT_UNDEFINED;
|
||||
} else {
|
||||
if (!gst_dvd_read_src_goto_sector (src, src->angle)) {
|
||||
GST_DEBUG_OBJECT (src, "seek to sector failed, going EOS");
|
||||
gst_pad_push_event (srcpad, gst_event_new_eos ());
|
||||
return GST_FLOW_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->need_newsegment) {
|
||||
gst_pad_push_event (srcpad,
|
||||
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
|
||||
src->cur_pack * DVD_VIDEO_LB_LEN, -1, 0));
|
||||
|
||||
src->seek_pend = FALSE;
|
||||
src->need_newsegment = FALSE;
|
||||
}
|
||||
|
||||
if (src->new_seek) {
|
||||
|
@ -876,128 +857,169 @@ gst_dvd_read_src_get_size (GstDvdReadSrc * src, gint64 * size)
|
|||
/*** Querying and seeking ***/
|
||||
|
||||
static gboolean
|
||||
gst_dvd_read_src_do_seek (GstDvdReadSrc * src, GstEvent * event)
|
||||
gst_dvd_read_src_handle_seek_event (GstDvdReadSrc * src, GstEvent * event)
|
||||
{
|
||||
GstSeekFlags flags;
|
||||
GstSeekType cur_type, end_type;
|
||||
gint64 new_off, total, cur;
|
||||
gint64 new_off, total;
|
||||
GstFormat format;
|
||||
GstPad *srcpad;
|
||||
gboolean query_ok;
|
||||
gdouble rate;
|
||||
|
||||
srcpad = GST_BASE_SRC (src)->srcpad;
|
||||
|
||||
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &new_off,
|
||||
&end_type, NULL);
|
||||
|
||||
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_WARNING_OBJECT (src, "End seek type not supported, will be ignored");
|
||||
GST_DEBUG_OBJECT (src, "end seek type not supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case GST_FORMAT_BYTES:
|
||||
break;
|
||||
default:{
|
||||
if (format != chapter_format &&
|
||||
format != sector_format &&
|
||||
format != angle_format && format != title_format) {
|
||||
GST_DEBUG_OBJECT (src, "Unsupported seek format %d (%s)", format,
|
||||
gst_format_get_name (format));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (cur_type != GST_SEEK_TYPE_SET) {
|
||||
GST_DEBUG_OBJECT (src, "only SEEK_TYPE_SET is supported");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* get current offset and length */
|
||||
if (format == GST_FORMAT_BYTES) {
|
||||
if (format == angle_format) {
|
||||
GST_OBJECT_LOCK (src);
|
||||
query_ok = gst_dvd_read_src_get_size (src, &total);
|
||||
cur = (gint64) src->cur_pack * DVD_VIDEO_LB_LEN;
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
} else {
|
||||
query_ok = gst_pad_query_duration (srcpad, &format, &total)
|
||||
&& gst_pad_query_position (srcpad, &format, &cur);
|
||||
}
|
||||
|
||||
if (!query_ok) {
|
||||
GST_DEBUG_OBJECT (src, "Failed to query duration/position");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (src, "Current %s: %12" G_GINT64_FORMAT,
|
||||
gst_format_get_name (format), cur);
|
||||
GST_DEBUG_OBJECT (src, "Total %s: %12" G_GINT64_FORMAT,
|
||||
gst_format_get_name (format), total);
|
||||
|
||||
/* get absolute */
|
||||
switch (cur_type) {
|
||||
case GST_SEEK_TYPE_SET:
|
||||
/* no-op */
|
||||
break;
|
||||
case GST_SEEK_TYPE_CUR:
|
||||
new_off += cur;
|
||||
break;
|
||||
case GST_SEEK_TYPE_END:
|
||||
new_off = total - new_off;
|
||||
break;
|
||||
default:
|
||||
GST_DEBUG_OBJECT (src, "Unsupported seek method");
|
||||
if (new_off < 0 || new_off >= src->num_angles) {
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
GST_DEBUG_OBJECT (src, "invalid angle %d, only %d available",
|
||||
src->num_angles);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (new_off < 0 || new_off >= total) {
|
||||
GST_DEBUG_OBJECT (src, "Invalid seek position %" G_GINT64_FORMAT, new_off);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (cur == new_off) {
|
||||
GST_DEBUG_OBJECT (src, "We're already at that position!");
|
||||
}
|
||||
src->angle = (gint) new_off;
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
GST_DEBUG_OBJECT (src, "switched to angle %d", (gint) new_off);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (src, "Seeking to %s: %12" G_GINT64_FORMAT,
|
||||
gst_format_get_name (format), new_off);
|
||||
|
||||
GST_OBJECT_LOCK (src);
|
||||
|
||||
if (format == angle_format) {
|
||||
src->angle = new_off;
|
||||
goto done;
|
||||
if (format != chapter_format && format != title_format &&
|
||||
format != GST_FORMAT_BYTES) {
|
||||
GST_DEBUG_OBJECT (src, "unsupported seek format %d (%s)", format,
|
||||
gst_format_get_name (format));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (format == sector_format) {
|
||||
src->cur_pack = new_off;
|
||||
} else if (format == GST_FORMAT_BYTES) {
|
||||
src->cur_pack = new_off / DVD_VIDEO_LB_LEN;
|
||||
if ((src->cur_pack * DVD_VIDEO_LB_LEN) != new_off) {
|
||||
GST_LOG_OBJECT (src, "rounded down offset %" G_GINT64_FORMAT " => %"
|
||||
G_GINT64_FORMAT, new_off, (gint64) src->cur_pack * DVD_VIDEO_LB_LEN);
|
||||
}
|
||||
} else if (format == chapter_format) {
|
||||
src->cur_pack = 0;
|
||||
src->chapter = new_off;
|
||||
src->seek_pend_fmt = format;
|
||||
} else if (format == title_format) {
|
||||
src->cur_pack = 0;
|
||||
src->title = new_off;
|
||||
src->chapter = 0;
|
||||
src->seek_pend_fmt = format;
|
||||
} else {
|
||||
if (format == GST_FORMAT_BYTES) {
|
||||
GST_DEBUG_OBJECT (src, "Requested seek to byte %" G_GUINT64_FORMAT,
|
||||
new_off);
|
||||
} else if (format == GST_FORMAT_TIME) {
|
||||
GST_DEBUG_OBJECT (src, "Requested seek to time %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (new_off));
|
||||
}
|
||||
|
||||
srcpad = GST_BASE_SRC_PAD (src);
|
||||
|
||||
/* check whether the seek looks reasonable (ie within possible range) */
|
||||
if (format == GST_FORMAT_BYTES) {
|
||||
GST_OBJECT_LOCK (src);
|
||||
query_ok = gst_dvd_read_src_get_size (src, &total);
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
} else {
|
||||
query_ok = gst_pad_query_duration (srcpad, &format, &total);
|
||||
}
|
||||
|
||||
if (!query_ok) {
|
||||
GST_DEBUG_OBJECT (src, "Failed to query duration in format %s",
|
||||
gst_format_get_name (format));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (src, "Total %s: %12" G_GINT64_FORMAT,
|
||||
gst_format_get_name (format), total);
|
||||
GST_DEBUG_OBJECT (src, "Seek to %s: %12" G_GINT64_FORMAT,
|
||||
gst_format_get_name (format), new_off);
|
||||
|
||||
if (new_off >= total) {
|
||||
GST_DEBUG_OBJECT (src, "Seek position out of range");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* set segment to seek format; this allows us to use the do_seek
|
||||
* virtual function and let the base source handle all the tricky
|
||||
* stuff for us. We don't use the segment internally anyway */
|
||||
/* FIXME: can't take the stream lock here - what to do? */
|
||||
GST_OBJECT_LOCK (src);
|
||||
GST_BASE_SRC (src)->segment.format = format;
|
||||
GST_BASE_SRC (src)->segment.start = 0;
|
||||
GST_BASE_SRC (src)->segment.stop = total;
|
||||
GST_BASE_SRC (src)->segment.duration = total;
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
return GST_BASE_SRC_CLASS (parent_class)->event (GST_BASE_SRC (src), event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_dvd_read_src_do_seek (GstBaseSrc * basesrc, GstSegment * s)
|
||||
{
|
||||
GstDvdReadSrc *src;
|
||||
|
||||
src = GST_DVD_READ_SRC (basesrc);
|
||||
|
||||
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) {
|
||||
guint old;
|
||||
|
||||
old = src->cur_pack;
|
||||
|
||||
if (s->format == sector_format) {
|
||||
src->cur_pack = s->last_stop;
|
||||
} else {
|
||||
/* byte format */
|
||||
src->cur_pack = s->last_stop / DVD_VIDEO_LB_LEN;
|
||||
if ((src->cur_pack * DVD_VIDEO_LB_LEN) != s->last_stop) {
|
||||
GST_LOG_OBJECT (src, "rounded down offset %" G_GINT64_FORMAT " => %"
|
||||
G_GINT64_FORMAT, s->last_stop,
|
||||
(gint64) src->cur_pack * DVD_VIDEO_LB_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gst_dvd_read_src_goto_sector (src, src->angle)) {
|
||||
GST_DEBUG_OBJECT (src, "seek to sector 0x%08x failed", src->cur_pack);
|
||||
src->cur_pack = old;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (src, "seek to sector 0x%08x ok", src->cur_pack);
|
||||
} else if (s->format == chapter_format) {
|
||||
if (!gst_dvd_read_src_goto_chapter (src, (gint) s->last_stop)) {
|
||||
GST_DEBUG_OBJECT (src, "seek to chapter %d failed", (gint) s->last_stop);
|
||||
return FALSE;
|
||||
}
|
||||
GST_INFO_OBJECT (src, "seek to chapter %d ok", (gint) s->last_stop);
|
||||
src->chapter = s->last_stop;
|
||||
} else if (s->format == title_format) {
|
||||
if (!gst_dvd_read_src_goto_title (src, (gint) s->last_stop, src->angle) ||
|
||||
!gst_dvd_read_src_goto_chapter (src, 0)) {
|
||||
GST_DEBUG_OBJECT (src, "seek to title %d failed", (gint) s->last_stop);
|
||||
return FALSE;
|
||||
}
|
||||
src->title = (gint) s->last_stop;
|
||||
src->chapter = 0;
|
||||
GST_INFO_OBJECT (src, "seek to title %d ok", src->title);
|
||||
} else {
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
/* leave for events */
|
||||
src->seek_pend = TRUE;
|
||||
if ((flags & GST_SEEK_FLAG_FLUSH) != 0)
|
||||
src->flush_pend = TRUE;
|
||||
|
||||
done:
|
||||
|
||||
GST_OBJECT_UNLOCK (src);
|
||||
|
||||
src->need_newsegment = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -1011,7 +1033,7 @@ gst_dvd_read_src_src_event (GstBaseSrc * basesrc, GstEvent * event)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
res = gst_dvd_read_src_do_seek (src, event);
|
||||
res = gst_dvd_read_src_handle_seek_event (src, event);
|
||||
break;
|
||||
default:
|
||||
res = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
|
||||
|
|
|
@ -73,15 +73,14 @@ struct _GstDvdReadSrc {
|
|||
vts_ptt_srpt_t *vts_ptt_srpt;
|
||||
dvd_file_t *dvd_title;
|
||||
gint num_chapters;
|
||||
gint num_angles;
|
||||
|
||||
/* which program chain to watch (based on title and chapter number) */
|
||||
pgc_t *cur_pgc;
|
||||
gint pgc_id;
|
||||
gint pgn;
|
||||
|
||||
gboolean seek_pend;
|
||||
gboolean flush_pend;
|
||||
GstFormat seek_pend_fmt;
|
||||
gboolean need_newsegment;
|
||||
GstEvent *title_lang_event_pending;
|
||||
GstEvent *pending_clut_event;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue