mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-25 03:01:03 +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);
|
||||
pad->map.queued = NULL;
|
||||
|
||||
g_free (pad->map.index);
|
||||
pad->map.index = NULL;
|
||||
|
||||
/* clear continued pages */
|
||||
g_list_foreach (pad->continued, (GFunc) gst_ogg_page_free, NULL);
|
||||
g_list_free (pad->continued);
|
||||
|
@ -701,20 +704,35 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
|
|||
|
||||
if (pad->map.is_skeleton) {
|
||||
guint32 serialno;
|
||||
GstOggPad *fisbone_pad;
|
||||
GstOggPad *skel_pad;
|
||||
GstOggSkeleton type;
|
||||
|
||||
/* try to parse the serialno first */
|
||||
if (gst_ogg_map_parse_fisbone (&pad->map, packet->packet, packet->bytes,
|
||||
&serialno)) {
|
||||
fisbone_pad = gst_ogg_chain_get_stream (pad->chain, serialno);
|
||||
if (fisbone_pad) {
|
||||
/* parse the remainder of the fisbone in the pad with the serialno */
|
||||
gst_ogg_map_add_fisbone (&fisbone_pad->map, packet->packet,
|
||||
packet->bytes, &fisbone_pad->start_time);
|
||||
&serialno, &type)) {
|
||||
|
||||
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 */
|
||||
gst_ogg_map_add_fisbone (&skel_pad->map, packet->packet,
|
||||
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 {
|
||||
GST_WARNING_OBJECT (pad->ogg,
|
||||
"found skeleton fisbone for an unknown stream %" G_GUINT32_FORMAT,
|
||||
serialno);
|
||||
"found skeleton fisbone for an unknown stream %08lx", 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
|
||||
*/
|
||||
|
@ -1892,7 +1949,7 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
|
|||
gint64 begin, end;
|
||||
gint64 begintime, endtime;
|
||||
gint64 target, keytarget;
|
||||
gint64 best;
|
||||
gint64 best, best_time;
|
||||
gint64 total;
|
||||
gint64 result = 0;
|
||||
GstFlowReturn ret;
|
||||
|
@ -1919,6 +1976,22 @@ gst_ogg_demux_do_seek (GstOggDemux * ogg, GstSegment * segment,
|
|||
endtime = begintime + chain->total_time;
|
||||
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,
|
||||
&best))
|
||||
goto seek_error;
|
||||
|
|
|
@ -725,24 +725,34 @@ setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
|
|||
|
||||
gboolean
|
||||
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) {
|
||||
GST_WARNING ("small fisbone packet of size %d, ignoring", size);
|
||||
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);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pad->have_fisbone) {
|
||||
GST_DEBUG ("already have fisbone, ignoring second one");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (serialno)
|
||||
*serialno = GST_READ_UINT32_LE (data + 12);
|
||||
*serialno = GST_READ_UINT32_LE (data + serial_offset);
|
||||
|
||||
if (type)
|
||||
*type = stype;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -754,6 +764,10 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
|||
GstClockTime start_time;
|
||||
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 */
|
||||
data += 8 + 4 + 4 + 4;
|
||||
|
@ -783,6 +797,107 @@ gst_ogg_map_add_fisbone (GstOggStream * pad,
|
|||
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?
|
||||
* ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
|
||||
* ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
|
||||
|
|
|
@ -28,6 +28,16 @@
|
|||
|
||||
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;
|
||||
|
||||
struct _GstOggStream
|
||||
|
@ -57,7 +67,7 @@ struct _GstOggStream
|
|||
gint bitrate;
|
||||
|
||||
GstCaps *caps;
|
||||
|
||||
|
||||
/* vorbis stuff */
|
||||
int nln_increments[4];
|
||||
int nsn_increment;
|
||||
|
@ -74,7 +84,10 @@ struct _GstOggStream
|
|||
/* fishead stuff */
|
||||
gint64 prestime;
|
||||
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);
|
||||
|
||||
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,
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue