matroskademux: Add support for relative position cues
Cueing data can contain the block number within a cluster and/or a relative offset into the cluster. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5535>
This commit is contained in:
parent
3578b23ba2
commit
6e9667b65c
@ -339,10 +339,12 @@ gst_matroska_demux_reset (GstElement * element)
|
||||
|
||||
demux->last_stop_end = GST_CLOCK_TIME_NONE;
|
||||
demux->seek_block = 0;
|
||||
demux->seek_block_is_offset = FALSE;
|
||||
demux->stream_start_time = GST_CLOCK_TIME_NONE;
|
||||
demux->to_time = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_offset = 0;
|
||||
demux->cluster_prefix = 0;
|
||||
demux->cluster_prevsize = 0;
|
||||
demux->seen_cluster_prevsize = FALSE;
|
||||
demux->next_cluster_offset = 0;
|
||||
@ -2256,16 +2258,19 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
|
||||
demux->next_cluster_offset = 0;
|
||||
|
||||
GST_DEBUG_OBJECT (demux,
|
||||
"Seeked to offset %" G_GUINT64_FORMAT ", block %d, " "time %"
|
||||
"Seeked to offset %" G_GUINT64_FORMAT ", %s %d, " "time %"
|
||||
GST_TIME_FORMAT, entry->pos + demux->common.ebml_segment_start,
|
||||
entry->block, GST_TIME_ARGS (entry->time));
|
||||
entry->relative ? "relative offset" : "block",
|
||||
entry->relative ? entry->offset : entry->block,
|
||||
GST_TIME_ARGS (entry->time));
|
||||
|
||||
/* update the time */
|
||||
gst_matroska_read_common_reset_streams (&demux->common, entry->time, TRUE);
|
||||
gst_flow_combiner_reset (demux->flowcombiner);
|
||||
demux->common.segment.position = entry->time;
|
||||
demux->seek_block = entry->block;
|
||||
demux->seek_first = TRUE;
|
||||
demux->seek_block = entry->relative ? entry->offset : entry->block;
|
||||
demux->seek_block_is_offset = entry->relative;
|
||||
demux->seek_first = !entry->relative;
|
||||
demux->last_stop_end = GST_CLOCK_TIME_NONE;
|
||||
}
|
||||
|
||||
@ -5402,6 +5407,28 @@ gst_matroska_demux_seek_block (GstMatroskaDemux * demux)
|
||||
}
|
||||
}
|
||||
|
||||
/* returns TRUE if we've seeked and should exit */
|
||||
static inline gboolean
|
||||
gst_matroska_demux_seek_offset (GstMatroskaDemux * demux)
|
||||
{
|
||||
guint64 next_off;
|
||||
|
||||
if (G_LIKELY (!demux->seek_block_is_offset))
|
||||
return FALSE;
|
||||
|
||||
next_off = demux->cluster_offset + demux->cluster_prefix + demux->seek_block;
|
||||
demux->seek_block = 0;
|
||||
demux->seek_block_is_offset = FALSE;
|
||||
|
||||
if (next_off > demux->common.offset && next_off < demux->next_cluster_offset) {
|
||||
GST_DEBUG_OBJECT (demux, "seeking to %" G_GUINT64_FORMAT, next_off);
|
||||
demux->common.offset = next_off;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
|
||||
GstEbmlRead * ebml)
|
||||
@ -5995,9 +6022,12 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
||||
}
|
||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_offset = demux->common.offset;
|
||||
demux->cluster_prefix = needed;
|
||||
demux->cluster_prevsize = 0;
|
||||
if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) {
|
||||
GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
|
||||
if (G_UNLIKELY (!demux->seek_first && !demux->seek_block_is_offset
|
||||
&& demux->seek_block)) {
|
||||
GST_DEBUG_OBJECT (demux,
|
||||
"seek target block %" G_GUINT64_FORMAT
|
||||
" not found in Cluster, trying next Cluster's first block instead",
|
||||
demux->seek_block);
|
||||
demux->seek_block = 0;
|
||||
@ -6043,7 +6073,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
||||
break;
|
||||
}
|
||||
case GST_MATROSKA_ID_BLOCKGROUP:
|
||||
if (!gst_matroska_demux_seek_block (demux))
|
||||
if (gst_matroska_demux_seek_offset (demux))
|
||||
break;
|
||||
else if (!gst_matroska_demux_seek_block (demux))
|
||||
goto skip;
|
||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||
DEBUG_ELEMENT_START (demux, &ebml, "BlockGroup");
|
||||
@ -6054,7 +6086,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
||||
DEBUG_ELEMENT_STOP (demux, &ebml, "BlockGroup", ret);
|
||||
break;
|
||||
case GST_MATROSKA_ID_SIMPLEBLOCK:
|
||||
if (!gst_matroska_demux_seek_block (demux))
|
||||
if (gst_matroska_demux_seek_offset (demux))
|
||||
break;
|
||||
else if (!gst_matroska_demux_seek_block (demux))
|
||||
goto skip;
|
||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||
DEBUG_ELEMENT_START (demux, &ebml, "SimpleBlock");
|
||||
@ -6528,6 +6562,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstObject * parent,
|
||||
demux->common.segment.position = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_offset = 0;
|
||||
demux->cluster_prefix = 0;
|
||||
demux->cluster_prevsize = 0;
|
||||
demux->need_segment = TRUE;
|
||||
demux->segment_seqnum = gst_event_get_seqnum (event);
|
||||
@ -6581,6 +6616,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstObject * parent,
|
||||
demux->common.segment.duration = dur;
|
||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||
demux->cluster_offset = 0;
|
||||
demux->cluster_prefix = 0;
|
||||
demux->cluster_prevsize = 0;
|
||||
GST_OBJECT_UNLOCK (demux);
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ typedef struct _GstMatroskaDemux {
|
||||
gboolean streaming;
|
||||
guint64 seek_block;
|
||||
gboolean seek_first;
|
||||
gboolean seek_block_is_offset;
|
||||
|
||||
/* did we parse cues/tracks/segmentinfo already? */
|
||||
GList *seek_parsed;
|
||||
@ -87,6 +88,7 @@ typedef struct _GstMatroskaDemux {
|
||||
/* some state saving */
|
||||
GstClockTime cluster_time;
|
||||
guint64 cluster_offset;
|
||||
guint cluster_prefix;
|
||||
guint64 cluster_prevsize; /* 0 if unknown */
|
||||
guint64 first_cluster_offset;
|
||||
guint64 next_cluster_offset;
|
||||
|
@ -216,6 +216,7 @@
|
||||
#define GST_MATROSKA_ID_CUETRACK 0xF7
|
||||
#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1
|
||||
#define GST_MATROSKA_ID_CUEBLOCKNUMBER 0x5378
|
||||
#define GST_MATROSKA_ID_CUERELATIVEPOSITION 0xF0
|
||||
/* semi-draft */
|
||||
#define GST_MATROSKA_ID_CUECODECSTATE 0xEA
|
||||
/* semi-draft */
|
||||
@ -687,8 +688,12 @@ typedef struct _GstMatroskaTrackSubtitleContext {
|
||||
typedef struct _GstMatroskaIndex {
|
||||
guint64 pos; /* of the corresponding *cluster*! */
|
||||
GstClockTime time; /* in nanoseconds */
|
||||
guint32 block; /* number of the block in the cluster */
|
||||
union {
|
||||
guint32 block; /* number of the block in the cluster */
|
||||
guint32 offset; /* relative offset from start of cluster */
|
||||
};
|
||||
guint16 track; /* reference to 'num' */
|
||||
gboolean relative; /* whether we're using relative offset or block number */
|
||||
} GstMatroskaIndex;
|
||||
|
||||
typedef struct _Wavpack4Header {
|
||||
|
@ -1639,6 +1639,7 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
||||
idx.track = 0;
|
||||
idx.time = GST_CLOCK_TIME_NONE;
|
||||
idx.block = 1;
|
||||
idx.relative = FALSE;
|
||||
|
||||
DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
|
||||
|
||||
@ -1702,6 +1703,9 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx.relative)
|
||||
break;
|
||||
|
||||
GST_DEBUG_OBJECT (common->sinkpad, "CueBlockNumber: %" G_GUINT64_FORMAT,
|
||||
num);
|
||||
idx.block = num;
|
||||
@ -1714,6 +1718,27 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
||||
break;
|
||||
}
|
||||
|
||||
/* byte offset from start of cluster */
|
||||
case GST_MATROSKA_ID_CUERELATIVEPOSITION:
|
||||
{
|
||||
guint64 num;
|
||||
|
||||
if ((ret = gst_ebml_read_uint (ebml, &id, &num)) != GST_FLOW_OK)
|
||||
break;
|
||||
|
||||
GST_DEBUG_OBJECT (common->sinkpad,
|
||||
"CueRelativePosition: %" G_GUINT64_FORMAT, num);
|
||||
|
||||
/* mild sanity check, disregard strange cases ... */
|
||||
if (num > G_MAXUINT32) {
|
||||
GST_DEBUG_OBJECT (common->sinkpad, "... looks suspicious, ignoring");
|
||||
} else {
|
||||
idx.offset = num;
|
||||
idx.relative = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = gst_matroska_read_common_parse_skip (common, ebml,
|
||||
"CueTrackPositions", id);
|
||||
@ -1730,7 +1755,7 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
||||
|
||||
/* (e.g.) lavf typically creates entries without a block number,
|
||||
* which is bogus and leads to contradictory information */
|
||||
if (common->index->len) {
|
||||
if (common->index->len && !idx.relative) {
|
||||
GstMatroskaIndex *last_idx;
|
||||
|
||||
last_idx = &g_array_index (common->index, GstMatroskaIndex,
|
||||
@ -1818,8 +1843,10 @@ gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
|
||||
|
||||
idx->time = time;
|
||||
GST_DEBUG_OBJECT (common->sinkpad, "Index entry: pos=%" G_GUINT64_FORMAT
|
||||
", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
|
||||
GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
|
||||
", time=%" GST_TIME_FORMAT ", track=%u, %s=%u", idx->pos,
|
||||
GST_TIME_ARGS (idx->time), (guint) idx->track,
|
||||
idx->relative ? "offset" : "block",
|
||||
(guint) (idx->relative ? idx->offset : idx->block));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user