diff options
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | gst/qtdemux/qtdemux.c | 122 | ||||
-rw-r--r-- | win32/common/config.h | 8 |
3 files changed, 95 insertions, 47 deletions
@@ -1,3 +1,15 @@ +2008-05-31 Julien Moutte <julien@fluendo.com> + + * gst/qtdemux/qtdemux.c: (gst_qtdemux_find_keyframe), + (gst_qtdemux_find_segment), (gst_qtdemux_perform_seek), + (gst_qtdemux_seek_to_previous_keyframe), + (gst_qtdemux_activate_segment), (gst_qtdemux_loop): Make sure we + we don't clip the segment's stop using the main segment duration as + that could crop quite some video frames. Make reverse playback support + more robust and support edit lists. Support seeking to the last frame, + and fix reverse looping playback. Add some debugging. + * win32/common/config.h: Updated. + 2008-05-31 Sebastian Dröge <slomo@circular-chaos.org> * gst/equalizer/gstiirequalizer.c: diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 5290fb13..6b87dad0 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -528,24 +528,35 @@ static guint32 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str, guint32 index) { - if (index >= str->n_samples) - return str->n_samples; + guint32 new_index = index; + + if (index >= str->n_samples) { + new_index = str->n_samples; + goto beach; + } /* all keyframes, return index */ - if (str->all_keyframe) - return index; + if (str->all_keyframe) { + new_index = index; + goto beach; + } /* else go back until we have a keyframe */ while (TRUE) { - if (str->samples[index].keyframe) + if (str->samples[new_index].keyframe) break; - if (index == 0) + if (new_index == 0) break; - index--; + new_index--; } - return index; + +beach: + GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u " + "gave %u", index, new_index); + + return new_index; } /* find the segment for @time_position for @stream @@ -572,10 +583,19 @@ gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT, GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time)); - if (segment->time <= time_position && time_position < segment->stop_time) { - GST_LOG_OBJECT (qtdemux, "segment %d matches", i); - seg_idx = i; - break; + /* For the last segment we include stop_time in the last segment */ + if (i < stream->n_segments - 1) { + if (segment->time <= time_position && time_position < segment->stop_time) { + GST_LOG_OBJECT (qtdemux, "segment %d matches", i); + seg_idx = i; + break; + } + } else { + if (segment->time <= time_position && time_position <= segment->stop_time) { + GST_LOG_OBJECT (qtdemux, "segment %d matches", i); + seg_idx = i; + break; + } } } return seg_idx; @@ -671,8 +691,6 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment) /* find previous keyframe */ kindex = gst_qtdemux_find_keyframe (qtdemux, str, index); - GST_DEBUG_OBJECT (qtdemux, "keyframe at %u", kindex); - /* if the keyframe is at a different position, we need to update the * requiested seek time */ if (index != kindex) { @@ -1078,16 +1096,17 @@ static GstFlowReturn gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) { guint8 n = 0; - guint32 seg_idx = 0, index = 0, kindex = 0; - guint64 desired_offset = 0, last_stop = 0, media_start = 0, seg_time = 0; + guint32 seg_idx = 0, k_index = 0; + guint64 k_pos = 0, last_stop = 0; QtDemuxSegment *seg = NULL; - QtDemuxStream *ref_str = NULL, *str = NULL; + QtDemuxStream *ref_str = NULL; /* Now we choose an arbitrary stream, get the previous keyframe timestamp * and finally align all the other streams on that timestamp with their * respective keyframes */ for (n = 0; n < qtdemux->n_streams; n++) { - str = qtdemux->streams[n]; + QtDemuxStream *str = qtdemux->streams[n]; + seg_idx = gst_qtdemux_find_segment (qtdemux, str, qtdemux->segment.last_stop); @@ -1109,35 +1128,46 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) } if (G_UNLIKELY (!ref_str)) { - GST_WARNING_OBJECT (qtdemux, "couldn't find any stream"); - return GST_FLOW_ERROR; + GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream"); + goto eos; } if (G_UNLIKELY (!ref_str->from_sample)) { GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file"); - return GST_FLOW_UNEXPECTED; + goto eos; } /* So that stream has been playing from from_sample to to_sample. We will * get the timestamp of the previous sample and search for a keyframe before * that. For audio streams we do an arbitrary jump in the past (10 samples) */ if (ref_str->subtype == FOURCC_vide) { - kindex = gst_qtdemux_find_keyframe (qtdemux, ref_str, + k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str, ref_str->from_sample - 1); } else { - kindex = ref_str->from_sample - 10; + k_index = ref_str->from_sample - 10; } - desired_offset = ref_str->samples[kindex].timestamp; + + /* get current segment for that stream */ + seg = &ref_str->segments[ref_str->segment_index]; + /* Crawl back through segments to find the one containing this I frame */ + while (ref_str->samples[k_index].timestamp < seg->media_start) { + GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u", + ref_str->segment_index); + if (G_UNLIKELY (!ref_str->segment_index)) { + /* Reached first segment, let's consider it's EOS */ + goto eos; + } + ref_str->segment_index--; + seg = &ref_str->segments[ref_str->segment_index]; + } + /* Calculate time position of the keyframe and where we should stop */ + k_pos = (ref_str->samples[k_index].timestamp - seg->media_start) + seg->time; last_stop = ref_str->samples[ref_str->from_sample].timestamp; - /* Bring that back to global time */ - seg = &ref_str->segments[seg_idx]; - /* Sample global timestamp is timestamp - seg_start + seg_time */ - desired_offset = (desired_offset - seg->media_start) + seg->time; last_stop = (last_stop - seg->media_start) + seg->time; GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, " "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample, - kindex, GST_TIME_ARGS (desired_offset)); + k_index, GST_TIME_ARGS (k_pos)); /* Set last_stop with the keyframe timestamp we pushed of that stream */ gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop); @@ -1146,14 +1176,16 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) if (G_UNLIKELY (last_stop < qtdemux->segment.start)) { GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment"); - return GST_FLOW_UNEXPECTED; + goto eos; } /* Align them all on this */ for (n = 0; n < qtdemux->n_streams; n++) { - str = qtdemux->streams[n]; + guint32 index = 0; + guint64 media_start = 0, seg_time = 0; + QtDemuxStream *str = qtdemux->streams[n]; - seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_offset); + seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos); GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx); /* segment not found, continue with normal flow */ @@ -1162,7 +1194,7 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) /* get segment and time in the segment */ seg = &str->segments[seg_idx]; - seg_time = desired_offset - seg->time; + seg_time = k_pos - seg->time; /* get the media time in the segment */ media_start = seg->media_start + seg_time; @@ -1173,21 +1205,24 @@ gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux) GST_TIME_ARGS (media_start), index); /* find previous keyframe */ - kindex = gst_qtdemux_find_keyframe (qtdemux, str, index); + k_index = gst_qtdemux_find_keyframe (qtdemux, str, index); /* Remember until where we want to go */ str->to_sample = str->from_sample - 1; /* Define our time position */ str->time_position = - (str->samples[kindex].timestamp - seg->media_start) + seg->time; + (str->samples[k_index].timestamp - seg->media_start) + seg->time; /* Now seek back in time */ - gst_qtdemux_move_stream (qtdemux, str, kindex); + gst_qtdemux_move_stream (qtdemux, str, k_index); GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %" - GST_TIME_FORMAT " playing from sample %u to %u", kindex, + GST_TIME_FORMAT " playing from sample %u to %u", k_index, GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample); } return GST_FLOW_OK; + +eos: + return GST_FLOW_UNEXPECTED; } /* activate the given segment number @seg_idx of @stream at time @offset. @@ -1235,18 +1270,14 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream, return FALSE; } - /* calc media start/stop */ - if (qtdemux->segment.stop == -1) - stop = segment->media_stop; - else - stop = MIN (segment->media_stop, qtdemux->segment.stop); + stop = segment->media_stop; if (qtdemux->segment.rate >= 0) { start = MIN (segment->media_start + seg_time, stop); time = offset; } else { start = segment->media_start; stop = MIN (segment->media_start + seg_time, stop); - time = segment->media_start; + time = segment->time; } GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT @@ -1837,6 +1868,11 @@ pause: if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) { gint64 stop; + /* FIXME: I am not sure this is the right fix. If the sinks are + * supposed to detect the segment is complete and accumulate + * automatically, it does not seem to work here. Need more work */ + qtdemux->segment_running = TRUE; + if ((stop = qtdemux->segment.stop) == -1) stop = qtdemux->segment.duration; diff --git a/win32/common/config.h b/win32/common/config.h index fa1afc4f..8103c7b5 100644 --- a/win32/common/config.h +++ b/win32/common/config.h @@ -36,7 +36,7 @@ #define GST_LICENSE "LGPL" /* package name in plugins */ -#define GST_PACKAGE_NAME "GStreamer Good Plug-ins source release" +#define GST_PACKAGE_NAME "GStreamer Good Plug-ins CVS/prerelease" /* package origin */ #define GST_PACKAGE_ORIGIN "Unknown package origin" @@ -244,13 +244,13 @@ #define PACKAGE_NAME "GStreamer Good Plug-ins" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "GStreamer Good Plug-ins 0.10.8" +#define PACKAGE_STRING "GStreamer Good Plug-ins 0.10.8.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "gst-plugins-good" /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.10.8" +#define PACKAGE_VERSION "0.10.8.1" /* Define the plugin directory */ #ifdef _DEBUG @@ -266,7 +266,7 @@ #undef STDC_HEADERS /* Version number of package */ -#define VERSION "0.10.8" +#define VERSION "0.10.8.1" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ |