gdouble rate;
};
+#define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
+
struct _QtDemuxStream
{
GstPad *pad;
}
segment->position = desired_offset;
segment->time = desired_offset;
+ qtdemux->segment_base = desired_offset;
/* we stop at the end */
if (segment->stop == -1)
qtdemux->offset = 0;
gst_adapter_clear (qtdemux->adapter);
gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+ qtdemux->segment_base = 0;
if (hard) {
for (n = 0; n < qtdemux->n_streams; n++) {
stop =
MIN (segment->media_stop, stop - segment->time + segment->media_start);
- if (qtdemux->segment.rate >= 0) {
+ if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
+ start = segment->time + seg_time;
+ time = offset;
+ } else if (qtdemux->segment.rate >= 0) {
start = MIN (segment->media_start + seg_time, stop);
time = offset;
} else {
stream->segment.stop = stop;
stream->segment.time = time;
stream->segment.position = start;
+ stream->segment.base =
+ segment->time >
+ qtdemux->segment_base ? segment->time - qtdemux->segment_base : 0;
/* now prepare and send the segment */
if (stream->pad) {
/* and move to the keyframe before the indicated media time of the
* segment */
- if (qtdemux->segment.rate >= 0) {
- index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
- stream->to_sample = G_MAXUINT32;
- GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
- ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
- GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
- GST_SECOND, stream->timescale)));
+ if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
+ if (qtdemux->segment.rate >= 0) {
+ index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
+ stream->to_sample = G_MAXUINT32;
+ GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
+ ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
+ GST_TIME_ARGS (gst_util_uint64_scale (stream->
+ samples[index].timestamp, GST_SECOND, stream->timescale)));
+ } else {
+ index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
+ stream->to_sample = index;
+ GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
+ ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
+ GST_TIME_ARGS (gst_util_uint64_scale (stream->
+ samples[index].timestamp, GST_SECOND, stream->timescale)));
+ }
} else {
- index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
- stream->to_sample = index;
- GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
- ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
- GST_TIME_ARGS (gst_util_uint64_scale (stream->samples[index].timestamp,
- GST_SECOND, stream->timescale)));
+ GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
+ "this is an empty segment");
+ return TRUE;
}
/* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
*/
static gboolean
gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
- QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * dts,
- guint64 * pts, guint64 * duration, gboolean * keyframe)
+ QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
+ guint64 * dts, guint64 * pts, guint64 * duration, gboolean * keyframe)
{
QtDemuxSample *sample;
guint64 time_position;
if (G_UNLIKELY (stream->segment_index != seg_idx))
gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
+ if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
+ segments[stream->segment_index]))) {
+ QtDemuxSegment *seg = &stream->segments[stream->segment_index];
+
+ GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
+ " prepare empty sample");
+
+ *empty = TRUE;
+ *pts = *dts = time_position;
+ *duration = seg->duration - (time_position - seg->time);
+
+ return TRUE;
+ }
+
+ *empty = FALSE;
+
GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
stream->sample_index, stream->n_samples);
QtDemuxSample *sample;
QtDemuxSegment *segment;
+ /* get current segment */
+ segment = &stream->segments[stream->segment_index];
+
+ if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
+ GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
+ goto next_segment;
+ }
+
if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
/* Mark the stream as EOS */
GST_DEBUG_OBJECT (qtdemux,
stream->sample_index++;
stream->offset_in_sample = 0;
- /* get current segment */
- segment = &stream->segments[stream->segment_index];
-
/* reached the last sample, we need the next segment */
if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
goto next_segment;
guint64 duration = 0;
gboolean keyframe = FALSE;
guint sample_size = 0;
+ gboolean empty = 0;
guint size;
gint index;
gint i;
}
/* fetch info for the current sample of this stream */
- if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
- &sample_size, &dts, &pts, &duration, &keyframe)))
+ if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
+ &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
goto eos_stream;
GST_DEBUG_OBJECT (qtdemux,
- "pushing from stream %d, offset %" G_GUINT64_FORMAT
+ "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
- ", duration %" GST_TIME_FORMAT, index, offset, sample_size,
+ ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
+ if (G_UNLIKELY (empty)) {
+ /* empty segment, push a gap and move to the next one */
+ gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
+ stream->segment.position = pts + duration;
+ goto next;
+ }
+
/* hmm, empty sample, skip and move to next sample */
if (G_UNLIKELY (sample_size <= 0))
goto next;
media_time = QT_UINT32 (buffer + 20 + i * 12);
duration = QT_UINT32 (buffer + 16 + i * 12);
- /* -1 media time is an empty segment, just ignore it */
- if (media_time == G_MAXUINT32) {
- if (i == 0) {
- /* first empty segment specifies sample offset (if movie timescale) */
- stream->elst_offset =
- gst_util_uint64_scale (duration, GST_SECOND, qtdemux->timescale);
- }
- continue;
- }
-
segment = &stream->segments[count++];
/* time and duration expressed in global timescale */
segment->stop_time = stime;
segment->duration = stime - segment->time;
/* media_time expressed in stream timescale */
- segment->media_start =
- gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
- segment->media_stop = segment->media_start + segment->duration;
+ if (media_time != G_MAXUINT32) {
+ segment->media_start =
+ gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
+ segment->media_stop = segment->media_start + segment->duration;
+ } else {
+ segment->media_start = GST_CLOCK_TIME_NONE;
+ segment->media_stop = GST_CLOCK_TIME_NONE;
+ }
rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
if (rate_int <= 1) {
GST_TIME_ARGS (segment->duration),
GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
}
- GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
+ GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
stream->n_segments = count;
}
done: