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->last_stop_end = GST_CLOCK_TIME_NONE;
|
||||||
demux->seek_block = 0;
|
demux->seek_block = 0;
|
||||||
|
demux->seek_block_is_offset = FALSE;
|
||||||
demux->stream_start_time = GST_CLOCK_TIME_NONE;
|
demux->stream_start_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->to_time = GST_CLOCK_TIME_NONE;
|
demux->to_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_offset = 0;
|
demux->cluster_offset = 0;
|
||||||
|
demux->cluster_prefix = 0;
|
||||||
demux->cluster_prevsize = 0;
|
demux->cluster_prevsize = 0;
|
||||||
demux->seen_cluster_prevsize = FALSE;
|
demux->seen_cluster_prevsize = FALSE;
|
||||||
demux->next_cluster_offset = 0;
|
demux->next_cluster_offset = 0;
|
||||||
@ -2256,16 +2258,19 @@ gst_matroska_demux_move_to_entry (GstMatroskaDemux * demux,
|
|||||||
demux->next_cluster_offset = 0;
|
demux->next_cluster_offset = 0;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (demux,
|
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,
|
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 */
|
/* update the time */
|
||||||
gst_matroska_read_common_reset_streams (&demux->common, entry->time, TRUE);
|
gst_matroska_read_common_reset_streams (&demux->common, entry->time, TRUE);
|
||||||
gst_flow_combiner_reset (demux->flowcombiner);
|
gst_flow_combiner_reset (demux->flowcombiner);
|
||||||
demux->common.segment.position = entry->time;
|
demux->common.segment.position = entry->time;
|
||||||
demux->seek_block = entry->block;
|
demux->seek_block = entry->relative ? entry->offset : entry->block;
|
||||||
demux->seek_first = TRUE;
|
demux->seek_block_is_offset = entry->relative;
|
||||||
|
demux->seek_first = !entry->relative;
|
||||||
demux->last_stop_end = GST_CLOCK_TIME_NONE;
|
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
|
static GstFlowReturn
|
||||||
gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
|
gst_matroska_demux_parse_contents_seekentry (GstMatroskaDemux * demux,
|
||||||
GstEbmlRead * ebml)
|
GstEbmlRead * ebml)
|
||||||
@ -5995,9 +6022,12 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
|||||||
}
|
}
|
||||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_offset = demux->common.offset;
|
demux->cluster_offset = demux->common.offset;
|
||||||
|
demux->cluster_prefix = needed;
|
||||||
demux->cluster_prevsize = 0;
|
demux->cluster_prevsize = 0;
|
||||||
if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) {
|
if (G_UNLIKELY (!demux->seek_first && !demux->seek_block_is_offset
|
||||||
GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
|
&& demux->seek_block)) {
|
||||||
|
GST_DEBUG_OBJECT (demux,
|
||||||
|
"seek target block %" G_GUINT64_FORMAT
|
||||||
" not found in Cluster, trying next Cluster's first block instead",
|
" not found in Cluster, trying next Cluster's first block instead",
|
||||||
demux->seek_block);
|
demux->seek_block);
|
||||||
demux->seek_block = 0;
|
demux->seek_block = 0;
|
||||||
@ -6043,7 +6073,9 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_MATROSKA_ID_BLOCKGROUP:
|
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;
|
goto skip;
|
||||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||||
DEBUG_ELEMENT_START (demux, &ebml, "BlockGroup");
|
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);
|
DEBUG_ELEMENT_STOP (demux, &ebml, "BlockGroup", ret);
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_SIMPLEBLOCK:
|
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;
|
goto skip;
|
||||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||||
DEBUG_ELEMENT_START (demux, &ebml, "SimpleBlock");
|
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->common.segment.position = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_offset = 0;
|
demux->cluster_offset = 0;
|
||||||
|
demux->cluster_prefix = 0;
|
||||||
demux->cluster_prevsize = 0;
|
demux->cluster_prevsize = 0;
|
||||||
demux->need_segment = TRUE;
|
demux->need_segment = TRUE;
|
||||||
demux->segment_seqnum = gst_event_get_seqnum (event);
|
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->common.segment.duration = dur;
|
||||||
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
demux->cluster_time = GST_CLOCK_TIME_NONE;
|
||||||
demux->cluster_offset = 0;
|
demux->cluster_offset = 0;
|
||||||
|
demux->cluster_prefix = 0;
|
||||||
demux->cluster_prevsize = 0;
|
demux->cluster_prevsize = 0;
|
||||||
GST_OBJECT_UNLOCK (demux);
|
GST_OBJECT_UNLOCK (demux);
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ typedef struct _GstMatroskaDemux {
|
|||||||
gboolean streaming;
|
gboolean streaming;
|
||||||
guint64 seek_block;
|
guint64 seek_block;
|
||||||
gboolean seek_first;
|
gboolean seek_first;
|
||||||
|
gboolean seek_block_is_offset;
|
||||||
|
|
||||||
/* did we parse cues/tracks/segmentinfo already? */
|
/* did we parse cues/tracks/segmentinfo already? */
|
||||||
GList *seek_parsed;
|
GList *seek_parsed;
|
||||||
@ -87,6 +88,7 @@ typedef struct _GstMatroskaDemux {
|
|||||||
/* some state saving */
|
/* some state saving */
|
||||||
GstClockTime cluster_time;
|
GstClockTime cluster_time;
|
||||||
guint64 cluster_offset;
|
guint64 cluster_offset;
|
||||||
|
guint cluster_prefix;
|
||||||
guint64 cluster_prevsize; /* 0 if unknown */
|
guint64 cluster_prevsize; /* 0 if unknown */
|
||||||
guint64 first_cluster_offset;
|
guint64 first_cluster_offset;
|
||||||
guint64 next_cluster_offset;
|
guint64 next_cluster_offset;
|
||||||
|
@ -216,6 +216,7 @@
|
|||||||
#define GST_MATROSKA_ID_CUETRACK 0xF7
|
#define GST_MATROSKA_ID_CUETRACK 0xF7
|
||||||
#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1
|
#define GST_MATROSKA_ID_CUECLUSTERPOSITION 0xF1
|
||||||
#define GST_MATROSKA_ID_CUEBLOCKNUMBER 0x5378
|
#define GST_MATROSKA_ID_CUEBLOCKNUMBER 0x5378
|
||||||
|
#define GST_MATROSKA_ID_CUERELATIVEPOSITION 0xF0
|
||||||
/* semi-draft */
|
/* semi-draft */
|
||||||
#define GST_MATROSKA_ID_CUECODECSTATE 0xEA
|
#define GST_MATROSKA_ID_CUECODECSTATE 0xEA
|
||||||
/* semi-draft */
|
/* semi-draft */
|
||||||
@ -687,8 +688,12 @@ typedef struct _GstMatroskaTrackSubtitleContext {
|
|||||||
typedef struct _GstMatroskaIndex {
|
typedef struct _GstMatroskaIndex {
|
||||||
guint64 pos; /* of the corresponding *cluster*! */
|
guint64 pos; /* of the corresponding *cluster*! */
|
||||||
GstClockTime time; /* in nanoseconds */
|
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' */
|
guint16 track; /* reference to 'num' */
|
||||||
|
gboolean relative; /* whether we're using relative offset or block number */
|
||||||
} GstMatroskaIndex;
|
} GstMatroskaIndex;
|
||||||
|
|
||||||
typedef struct _Wavpack4Header {
|
typedef struct _Wavpack4Header {
|
||||||
|
@ -1639,6 +1639,7 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
|||||||
idx.track = 0;
|
idx.track = 0;
|
||||||
idx.time = GST_CLOCK_TIME_NONE;
|
idx.time = GST_CLOCK_TIME_NONE;
|
||||||
idx.block = 1;
|
idx.block = 1;
|
||||||
|
idx.relative = FALSE;
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
|
DEBUG_ELEMENT_START (common, ebml, "CueTrackPositions");
|
||||||
|
|
||||||
@ -1702,6 +1703,9 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (idx.relative)
|
||||||
|
break;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (common->sinkpad, "CueBlockNumber: %" G_GUINT64_FORMAT,
|
GST_DEBUG_OBJECT (common->sinkpad, "CueBlockNumber: %" G_GUINT64_FORMAT,
|
||||||
num);
|
num);
|
||||||
idx.block = num;
|
idx.block = num;
|
||||||
@ -1714,6 +1718,27 @@ gst_matroska_read_common_parse_index_cuetrack (GstMatroskaReadCommon * common,
|
|||||||
break;
|
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:
|
default:
|
||||||
ret = gst_matroska_read_common_parse_skip (common, ebml,
|
ret = gst_matroska_read_common_parse_skip (common, ebml,
|
||||||
"CueTrackPositions", id);
|
"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,
|
/* (e.g.) lavf typically creates entries without a block number,
|
||||||
* which is bogus and leads to contradictory information */
|
* which is bogus and leads to contradictory information */
|
||||||
if (common->index->len) {
|
if (common->index->len && !idx.relative) {
|
||||||
GstMatroskaIndex *last_idx;
|
GstMatroskaIndex *last_idx;
|
||||||
|
|
||||||
last_idx = &g_array_index (common->index, GstMatroskaIndex,
|
last_idx = &g_array_index (common->index, GstMatroskaIndex,
|
||||||
@ -1818,8 +1843,10 @@ gst_matroska_read_common_parse_index_pointentry (GstMatroskaReadCommon *
|
|||||||
|
|
||||||
idx->time = time;
|
idx->time = time;
|
||||||
GST_DEBUG_OBJECT (common->sinkpad, "Index entry: pos=%" G_GUINT64_FORMAT
|
GST_DEBUG_OBJECT (common->sinkpad, "Index entry: pos=%" G_GUINT64_FORMAT
|
||||||
", time=%" GST_TIME_FORMAT ", track=%u, block=%u", idx->pos,
|
", time=%" GST_TIME_FORMAT ", track=%u, %s=%u", idx->pos,
|
||||||
GST_TIME_ARGS (idx->time), (guint) idx->track, (guint) idx->block);
|
GST_TIME_ARGS (idx->time), (guint) idx->track,
|
||||||
|
idx->relative ? "offset" : "block",
|
||||||
|
(guint) (idx->relative ? idx->offset : idx->block));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user