mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 11:11:08 +00:00
oggdemux: more index parsing work
This commit is contained in:
parent
97319a6276
commit
ff4479f00a
3 changed files with 226 additions and 21 deletions
|
@ -180,6 +180,9 @@ gst_ogg_pad_dispose (GObject * object)
|
||||||
g_list_free (pad->map.queued);
|
g_list_free (pad->map.queued);
|
||||||
pad->map.queued = NULL;
|
pad->map.queued = NULL;
|
||||||
|
|
||||||
|
g_free (pad->map.index);
|
||||||
|
pad->map.index = NULL;
|
||||||
|
|
||||||
/* clear continued pages */
|
/* clear continued pages */
|
||||||
g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
|
g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
|
||||||
g_list_free (pad->continued);
|
g_list_free (pad->continued);
|
||||||
|
@ -701,20 +704,35 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
|
||||||
|
|
||||||
if (pad->map.is_skeleton) {
|
if (pad->map.is_skeleton) {
|
||||||
guint32 serialno;
|
guint32 serialno;
|
||||||
GstOggPad *fisbone_pad;
|
GstOggPad *skel_pad;
|
||||||
|
GstOggSkeleton type;
|
||||||
|
|
||||||
/* try to parse the serialno first */
|
/* try to parse the serialno first */
|
||||||
if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
|
if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
|
||||||
&serialno)) {
|
&serialno, &type)) {
|
||||||
fisbone_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
|
|
||||||
if (fisbone_pad) {
|
GST_WARNING_OBJECT (pad->ogg,
|
||||||
|
"got skeleton packet for stream %08lx", serialno);
|
||||||
|
|
||||||
|
skel_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
|
||||||
|
if (skel_pad) {
|
||||||
|
switch (type) {
|
||||||
|
case GST_OGG_SKELETON_FISBONE:
|
||||||
/* parse the remainder of the fisbone in the pad with the serialno */
|
/* parse the remainder of the fisbone in the pad with the serialno */
|
||||||
gst_ogg_map_add_fisbone (&fisbone_pad->map, packet->packet,
|
gst_ogg_map_add_fisbone (&skel_pad->map, packet->packet,
|
||||||
packet->bytes, &fisbone_pad->start_time);
|
packet->bytes, &skel_pad->start_time);
|
||||||
|
break;
|
||||||
|
case GST_OGG_SKELETON_INDEX:
|
||||||
|
gst_ogg_map_add_index (&skel_pad->map, packet->packet,
|
||||||
|
packet->bytes);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (pad->ogg,
|
GST_WARNING_OBJECT (pad->ogg,
|
||||||
"found skeleton fisbone for an unknown stream %" G_GUINT32_FORMAT,
|
"found skeleton fisbone for an unknown stream %08lx", serialno);
|
||||||
serialno);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1880,6 +1898,45 @@ seek_error:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
do_index_search (GstOggDemux * ogg, GstOggChain * chain, gint64 begin,
|
||||||
|
gint64 end, gint64 begintime, gint64 endtime, gint64 target,
|
||||||
|
gint64 * p_offset, gint64 * p_timestamp)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
guint64 timestamp, offset;
|
||||||
|
guint64 r_timestamp, r_offset;
|
||||||
|
gboolean result = FALSE;
|
||||||
|
|
||||||
|
target -= begintime;
|
||||||
|
|
||||||
|
r_offset = -1;
|
||||||
|
r_timestamp = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < chain->streams->len; i++) {
|
||||||
|
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||||
|
|
||||||
|
timestamp = target;
|
||||||
|
if (gst_ogg_map_search_index (&pad->map, TRUE, ×tamp, &offset)) {
|
||||||
|
GST_INFO ("found %" G_GUINT64_FORMAT " at offset %" G_GUINT64_FORMAT,
|
||||||
|
timestamp, offset);
|
||||||
|
|
||||||
|
if (r_offset == -1 || offset < r_offset) {
|
||||||
|
r_offset = offset;
|
||||||
|
r_timestamp = timestamp;
|
||||||
|
}
|
||||||
|
result |= TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_timestamp)
|
||||||
|
*p_timestamp = r_timestamp;
|
||||||
|
if (p_offset)
|
||||||
|
*p_offset = r_offset;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do seek to time @position, return FALSE or chain and TRUE
|
* do seek to time @position, return FALSE or chain and TRUE
|
||||||
*/
|
*/
|
||||||
|
@ -1892,7 +1949,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
|
||||||
gint64 begin, end;
|
gint64 begin, end;
|
||||||
gint64 begintime, endtime;
|
gint64 begintime, endtime;
|
||||||
gint64 target, keytarget;
|
gint64 target, keytarget;
|
||||||
gint64 best;
|
gint64 best, best_time;
|
||||||
gint64 total;
|
gint64 total;
|
||||||
gint64 result = 0;
|
gint64 result = 0;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
@ -1919,6 +1976,22 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
|
||||||
endtime = begintime + chain->total_time;
|
endtime = begintime + chain->total_time;
|
||||||
target = position - total + begintime;
|
target = position - total + begintime;
|
||||||
|
|
||||||
|
if (do_index_search (ogg, chain, begin, end, begintime, endtime, target,
|
||||||
|
&best, &best_time)) {
|
||||||
|
/* the index gave some result */
|
||||||
|
GST_DEBUG_OBJECT (ogg,
|
||||||
|
"found offset %" G_GINT64_FORMAT " with time %" G_GUINT64_FORMAT, best,
|
||||||
|
best_time);
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
keytarget = best_time + begintime;
|
||||||
|
best += begin;
|
||||||
|
|
||||||
|
gst_ogg_demux_seek (ogg, best);
|
||||||
|
goto done;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
|
if (!do_binary_search (ogg, chain, begin, end, begintime, endtime, target,
|
||||||
&best))
|
&best))
|
||||||
goto seek_error;
|
goto seek_error;
|
||||||
|
|
|
@ -725,24 +725,34 @@ setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
||||||
guint32 * serialno)
|
guint32 * serialno, GstOggSkeleton * type)
|
||||||
{
|
{
|
||||||
|
GstOggSkeleton stype;
|
||||||
|
guint serial_offset;
|
||||||
|
|
||||||
if (size < SKELETON_FISBONE_MIN_SIZE) {
|
if (size < SKELETON_FISBONE_MIN_SIZE) {
|
||||||
GST_WARNING ("small fisbone packet of size %d, ignoring", size);
|
GST_WARNING ("small fisbone packet of size %d, ignoring", size);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (memcmp (data, "fisbone\0", 8) != 0) {
|
|
||||||
|
if (memcmp (data, "fisbone\0", 8) == 0) {
|
||||||
|
GST_INFO ("got fisbone packet");
|
||||||
|
stype = GST_OGG_SKELETON_FISBONE;
|
||||||
|
serial_offset = 12;
|
||||||
|
} else if (memcmp (data, "index\0", 6) == 0) {
|
||||||
|
GST_INFO ("got index packet");
|
||||||
|
stype = GST_OGG_SKELETON_INDEX;
|
||||||
|
serial_offset = 6;
|
||||||
|
} else {
|
||||||
GST_WARNING ("unknown skeleton packet %10.10s", data);
|
GST_WARNING ("unknown skeleton packet %10.10s", data);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pad->have_fisbone) {
|
|
||||||
GST_DEBUG ("already have fisbone, ignoring second one");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serialno)
|
if (serialno)
|
||||||
*serialno = GST_READ_UINT32_LE (data + 12);
|
*serialno = GST_READ_UINT32_LE (data + serial_offset);
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
*type = stype;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -754,6 +764,10 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
||||||
GstClockTime start_time;
|
GstClockTime start_time;
|
||||||
gint64 start_granule;
|
gint64 start_granule;
|
||||||
|
|
||||||
|
if (pad->have_fisbone) {
|
||||||
|
GST_DEBUG ("already have fisbone, ignoring second one");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* skip "fisbone\0" + headers offset + serialno + num headers */
|
/* skip "fisbone\0" + headers offset + serialno + num headers */
|
||||||
data += 8 + 4 + 4 + 4;
|
data += 8 + 4 + 4 + 4;
|
||||||
|
@ -783,6 +797,107 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static guint64
|
||||||
|
read_vlc (const guint8 ** data, guint * size)
|
||||||
|
{
|
||||||
|
gint shift = 0;
|
||||||
|
guint64 result = 0;
|
||||||
|
gint64 byte;
|
||||||
|
|
||||||
|
do {
|
||||||
|
byte = **data;
|
||||||
|
result |= ((byte & 0x7f) << shift);
|
||||||
|
shift += 7;
|
||||||
|
(*data)++;
|
||||||
|
} while ((byte & 0x80) != 0x80);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_ogg_map_add_index (GstOggStream * pad, const guint8 * data, guint size)
|
||||||
|
{
|
||||||
|
guint64 n_keypoints;
|
||||||
|
guint i;
|
||||||
|
guint64 offset, timestamp;
|
||||||
|
|
||||||
|
/* skip "index\0" + serialno */
|
||||||
|
data += 6 + 4;
|
||||||
|
size -= 6 + 4;
|
||||||
|
|
||||||
|
if (pad->index) {
|
||||||
|
GST_DEBUG ("already have index, ignoring second one");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
n_keypoints = GST_READ_UINT64_LE (data);
|
||||||
|
pad->kp_denom = GST_READ_UINT64_LE (data + 8);
|
||||||
|
data += 16;
|
||||||
|
size -= 16;
|
||||||
|
|
||||||
|
GST_INFO ("skeleton index has %" G_GUINT64_FORMAT " keypoints, denom: %"
|
||||||
|
G_GINT64_FORMAT, n_keypoints, pad->kp_denom);
|
||||||
|
|
||||||
|
pad->index = g_try_new (GstOggIndex, n_keypoints);
|
||||||
|
if (!pad->index)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pad->n_index = n_keypoints;
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
timestamp = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < n_keypoints; i++) {
|
||||||
|
offset += read_vlc (&data, &size);
|
||||||
|
timestamp += read_vlc (&data, &size);
|
||||||
|
|
||||||
|
pad->index[i].offset = offset;
|
||||||
|
pad->index[i].timestamp = timestamp;
|
||||||
|
|
||||||
|
GST_INFO ("offset %" G_GUINT64_FORMAT " time %" G_GUINT64_FORMAT, offset,
|
||||||
|
timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_ogg_map_search_index (GstOggStream * pad, gboolean before,
|
||||||
|
guint64 * timestamp, guint64 * offset)
|
||||||
|
{
|
||||||
|
guint64 n_index;
|
||||||
|
guint i, best;
|
||||||
|
guint64 ts;
|
||||||
|
|
||||||
|
n_index = pad->n_index;
|
||||||
|
if (n_index == 0 || pad->index == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ts = gst_util_uint64_scale (*timestamp, pad->kp_denom, GST_SECOND);
|
||||||
|
GST_INFO ("timestamp %" G_GUINT64_FORMAT, ts);
|
||||||
|
|
||||||
|
best = -1;
|
||||||
|
for (i = 0; i < n_index; i++) {
|
||||||
|
if (pad->index[i].timestamp <= ts)
|
||||||
|
best = i;
|
||||||
|
else if (pad->index[i].timestamp > ts)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (best == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
GST_INFO ("found at index %u", best);
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
*offset = pad->index[best].offset;
|
||||||
|
if (timestamp)
|
||||||
|
*timestamp =
|
||||||
|
gst_util_uint64_scale (pad->index[best].timestamp, GST_SECOND,
|
||||||
|
pad->kp_denom);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do we need these for something?
|
/* Do we need these for something?
|
||||||
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
||||||
* ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
|
* ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
|
||||||
|
|
|
@ -28,6 +28,16 @@
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GST_OGG_SKELETON_FISBONE,
|
||||||
|
GST_OGG_SKELETON_INDEX,
|
||||||
|
} GstOggSkeleton;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint64 offset;
|
||||||
|
guint64 timestamp;
|
||||||
|
} GstOggIndex;
|
||||||
|
|
||||||
typedef struct _GstOggStream GstOggStream;
|
typedef struct _GstOggStream GstOggStream;
|
||||||
|
|
||||||
struct _GstOggStream
|
struct _GstOggStream
|
||||||
|
@ -74,7 +84,10 @@ struct _GstOggStream
|
||||||
/* fishead stuff */
|
/* fishead stuff */
|
||||||
gint64 prestime;
|
gint64 prestime;
|
||||||
gint64 basetime;
|
gint64 basetime;
|
||||||
|
/* index */
|
||||||
|
guint n_index;
|
||||||
|
GstOggIndex *index;
|
||||||
|
guint64 kp_denom;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,9 +108,13 @@ gboolean gst_ogg_stream_packet_is_header (GstOggStream *pad, ogg_packet *packet)
|
||||||
gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
|
gint64 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet *packet);
|
||||||
|
|
||||||
gboolean gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
gboolean gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
||||||
guint32 * serialno);
|
guint32 * serialno, GstOggSkeleton *type);
|
||||||
gboolean gst_ogg_map_add_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
gboolean gst_ogg_map_add_fisbone (GstOggStream * pad, const guint8 * data, guint size,
|
||||||
GstClockTime * p_start_time);
|
GstClockTime * p_start_time);
|
||||||
|
gboolean gst_ogg_map_add_index (GstOggStream * pad, const guint8 * data, guint size);
|
||||||
|
gboolean gst_ogg_map_search_index (GstOggStream * pad, gboolean before, guint64 *timestamp, guint64 *offset);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
Loading…
Reference in a new issue