mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
oggdemux: fix wrong first granule
The code was using the first nonnegative granulepos to seed the granule tracking, which appeared to work since headers have zero granulepos. However, this does not work for files with a hole at start, which are common in live streaming. The correct behavior is to look for the first granule, and subtract the duration of all the packets finishing on this page. The function which does this relies on the fact that the ogg_stream structure can be duplicated by shallow copy, in order to pull the packets from the first page(s) on the copy without affecting the original stream state.
This commit is contained in:
parent
3cd2eb5847
commit
ca136e3648
1 changed files with 65 additions and 1 deletions
|
@ -936,9 +936,11 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
|
||||||
|
|
||||||
granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
|
granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
|
||||||
packet->granulepos);
|
packet->granulepos);
|
||||||
if (granule >= 0) {
|
if (granule > 0) {
|
||||||
GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule);
|
GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule);
|
||||||
pad->current_granule = granule;
|
pad->current_granule = granule;
|
||||||
|
} else if (granule == 0) {
|
||||||
|
/* headers */
|
||||||
} else if (granule != -1) {
|
} else if (granule != -1) {
|
||||||
GST_ERROR_OBJECT (ogg,
|
GST_ERROR_OBJECT (ogg,
|
||||||
"granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
|
"granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT,
|
||||||
|
@ -1203,6 +1205,62 @@ could_not_submit:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_ogg_demux_setup_first_granule (GstOggDemux * ogg, GstOggPad * pad,
|
||||||
|
ogg_page * page)
|
||||||
|
{
|
||||||
|
/* When we submit a page, we check if we have started tracking granules.
|
||||||
|
* If not, we calculate the granule corresponding to the first packet
|
||||||
|
* on the page. */
|
||||||
|
if (pad->current_granule == -1) {
|
||||||
|
ogg_int64_t granpos = ogg_page_granulepos (page);
|
||||||
|
if (granpos > 0) {
|
||||||
|
ogg_int64_t granule =
|
||||||
|
gst_ogg_stream_granulepos_to_granule (&pad->map, granpos), duration;
|
||||||
|
int packets = ogg_page_packets (page), n;
|
||||||
|
GST_DEBUG_OBJECT (pad,
|
||||||
|
"This page completes %d packets, granule %" G_GINT64_FORMAT, packets,
|
||||||
|
granule);
|
||||||
|
if (packets > 0) {
|
||||||
|
ogg_stream_state os;
|
||||||
|
ogg_packet op;
|
||||||
|
int last_size = pad->map.last_size;
|
||||||
|
|
||||||
|
memcpy (&os, &pad->map.stream, sizeof (os));
|
||||||
|
for (n = 0; n < packets; ++n) {
|
||||||
|
int ret = ogg_stream_packetout (&os, &op);
|
||||||
|
if (ret < 0) {
|
||||||
|
GST_WARNING_OBJECT (pad, "Failed to read packets off first page");
|
||||||
|
granule = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret == 0) {
|
||||||
|
GST_WARNING_OBJECT (pad,
|
||||||
|
"Short read getting %d packets off first page", packets);
|
||||||
|
granule = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
duration = gst_ogg_stream_get_packet_duration (&pad->map, &op);
|
||||||
|
GST_DEBUG_OBJECT (pad, "Packet %d has duration %" G_GINT64_FORMAT, n,
|
||||||
|
duration);
|
||||||
|
granule -= duration;
|
||||||
|
}
|
||||||
|
pad->map.last_size = last_size;
|
||||||
|
if (granule >= 0) {
|
||||||
|
pad->current_granule = granule;
|
||||||
|
GST_INFO_OBJECT (pad, "Starting with first granule %" G_GINT64_FORMAT,
|
||||||
|
granule);
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (pad, "Extrapolated first granule is negative");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (pad,
|
||||||
|
"Ogg page finishing no packets, but a valid granule");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_ogg_demux_setup_bisection_bounds (GstOggDemux * ogg)
|
gst_ogg_demux_setup_bisection_bounds (GstOggDemux * ogg)
|
||||||
{
|
{
|
||||||
|
@ -1537,6 +1595,8 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page)
|
||||||
GST_PUSH_UNLOCK (ogg);
|
GST_PUSH_UNLOCK (ogg);
|
||||||
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
||||||
goto choked;
|
goto choked;
|
||||||
|
if (pad->current_granule == -1)
|
||||||
|
gst_ogg_demux_setup_first_granule (ogg, pad, page);
|
||||||
return GST_FLOW_SKIP_PUSH;
|
return GST_FLOW_SKIP_PUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1556,6 +1616,8 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page)
|
||||||
"Not enough timing info collected for sync, waiting for more");
|
"Not enough timing info collected for sync, waiting for more");
|
||||||
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
||||||
goto choked;
|
goto choked;
|
||||||
|
if (pad->current_granule == -1)
|
||||||
|
gst_ogg_demux_setup_first_granule (ogg, pad, page);
|
||||||
return GST_FLOW_SKIP_PUSH;
|
return GST_FLOW_SKIP_PUSH;
|
||||||
}
|
}
|
||||||
ogg->push_last_seek_time = sync_time;
|
ogg->push_last_seek_time = sync_time;
|
||||||
|
@ -1803,6 +1865,8 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page)
|
||||||
|
|
||||||
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
if (ogg_stream_pagein (&pad->map.stream, page) != 0)
|
||||||
goto choked;
|
goto choked;
|
||||||
|
if (pad->current_granule == -1)
|
||||||
|
gst_ogg_demux_setup_first_granule (ogg, pad, page);
|
||||||
|
|
||||||
/* flush all packets in the stream layer, this might not give a packet if
|
/* flush all packets in the stream layer, this might not give a packet if
|
||||||
* the page had no packets finishing on the page (npackets == 0). */
|
* the page had no packets finishing on the page (npackets == 0). */
|
||||||
|
|
Loading…
Reference in a new issue