diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index cb8c2f7ef9..348657576b 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -556,8 +556,15 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, out_offset_end = -1; } else { if (packet->granulepos != -1) { - pad->current_granule = gst_ogg_stream_granulepos_to_granule (&pad->map, + gint64 granule = gst_ogg_stream_granulepos_to_granule (&pad->map, packet->granulepos); + if (granule < 0) { + GST_ERROR_OBJECT (ogg, + "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT, + packet->granulepos, granule); + return GST_FLOW_ERROR; + } + pad->current_granule = granule; pad->keyframe_granule = gst_ogg_stream_granulepos_to_key_granule (&pad->map, packet->granulepos); @@ -866,6 +873,11 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) if (granule != -1) { GST_DEBUG_OBJECT (ogg, "%p has granulepos %" G_GINT64_FORMAT, pad, granule); pad->current_granule = granule; + } else if (granule != -1) { + GST_ERROR_OBJECT (ogg, + "granulepos %" G_GINT64_FORMAT " yielded granule %" G_GINT64_FORMAT, + packet->granulepos, granule); + return GST_FLOW_ERROR; } /* restart header packet count when seeing a b_o_s page; @@ -903,6 +915,12 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet) granule = gst_ogg_stream_granulepos_to_granule (&pad->map, packet->granulepos); + if (granule < 0) { + GST_ERROR_OBJECT (ogg, + "granulepos %" G_GINT64_FORMAT " yielded granule %" + G_GINT64_FORMAT, packet->granulepos, granule); + return GST_FLOW_ERROR; + } if (granule > pad->map.accumulated_granule) start_granule = granule - pad->map.accumulated_granule; diff --git a/ext/ogg/gstoggstream.c b/ext/ogg/gstoggstream.c index 2190b27067..768d8cdee5 100644 --- a/ext/ogg/gstoggstream.c +++ b/ext/ogg/gstoggstream.c @@ -1873,6 +1873,7 @@ setup_opus_mapper (GstOggStream * pad, ogg_packet * packet) pad->granulerate_d = 1; pad->granuleshift = 0; pad->n_header_packets = 2; + pad->first_granpos = -1; /* pre-skip is in samples at 48000 Hz, which matches granule one for one */ pad->granule_offset = -GST_READ_UINT16_LE (packet->packet + 10); @@ -1890,6 +1891,29 @@ is_header_opus (GstOggStream * pad, ogg_packet * packet) return packet->bytes >= 8 && !memcmp (packet->packet, "Opus", 4); } +static gint64 +granulepos_to_granule_opus (GstOggStream * pad, gint64 granulepos) +{ + if (granulepos == -1) + return -1; + + /* We must reject some particular cases for the first granpos */ + + if (pad->first_granpos < 0 || granulepos < pad->first_granpos) + pad->first_granpos = granulepos; + + if (pad->first_granpos == granulepos) { + if (granulepos < -pad->granule_offset) { + GST_ERROR ("Invalid Opus stream: first granulepos (%" G_GINT64_FORMAT + ") less than preskip (%" G_GINT64_FORMAT ")", granulepos, + -pad->granule_offset); + return -1; + } + } + + return granulepos; +} + static gint64 packet_duration_opus (GstOggStream * pad, ogg_packet * packet) { @@ -2147,7 +2171,7 @@ const GstOggMap mappers[] = { "OpusHead", 8, 0, "audio/x-opus", setup_opus_mapper, - granulepos_to_granule_default, + granulepos_to_granule_opus, granule_to_granulepos_default, NULL, NULL, diff --git a/ext/ogg/gstoggstream.h b/ext/ogg/gstoggstream.h index b7353a6fcd..f32f89bc8a 100644 --- a/ext/ogg/gstoggstream.h +++ b/ext/ogg/gstoggstream.h @@ -93,6 +93,8 @@ struct _GstOggStream gboolean theora_has_zero_keyoffset; /* VP8 stuff */ gboolean is_vp8; + /* opus stuff */ + gint64 first_granpos; /* OGM stuff */ gboolean is_ogm; gboolean is_ogm_text;