mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
oggdemux: Fix vorbis parsing
Add a granule to granulepos conversion function. Fix the duration function for vorbis. Handle timestamps on header packets differently and be more careful about calculating OFFSET and OFFSET_END. After this change, timestamps for vorbis don't exactly match up with the timestamps that vorbisparse outputs, but it's unclear if vorbisparse is actually correct and it would add a lot more code to make oggdemux match vorbisparse. Fixes #602790.
This commit is contained in:
parent
1273909419
commit
78aad52cbf
4 changed files with 114 additions and 31 deletions
|
@ -479,14 +479,34 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet)
|
|||
|
||||
duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
|
||||
|
||||
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
pad->current_granule);
|
||||
pad->current_granule += duration;
|
||||
GST_BUFFER_DURATION (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
pad->current_granule) - GST_BUFFER_TIMESTAMP (buf);
|
||||
if (packet->b_o_s) {
|
||||
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
|
||||
GST_BUFFER_DURATION (buf) = GST_CLOCK_TIME_NONE;
|
||||
GST_BUFFER_OFFSET (buf) = 0;
|
||||
GST_BUFFER_OFFSET_END (buf) = -1;
|
||||
} else {
|
||||
GST_BUFFER_TIMESTAMP (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
pad->current_granule);
|
||||
GST_BUFFER_DURATION (buf) = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
pad->current_granule + duration) - GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
GST_BUFFER_OFFSET (buf) = -1;
|
||||
GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
|
||||
pad->current_granule += duration;
|
||||
if (packet->granulepos != -1) {
|
||||
gint64 granule;
|
||||
granule = gst_ogg_stream_granulepos_to_granule (&pad->map,
|
||||
packet->granulepos);
|
||||
if (granule != pad->current_granule) {
|
||||
GST_WARNING ("calculated granule didn't match actual (%lld != %lld)",
|
||||
pad->current_granule, granule);
|
||||
}
|
||||
pad->current_granule = granule;
|
||||
}
|
||||
GST_BUFFER_OFFSET_END (buf) =
|
||||
gst_ogg_stream_granule_to_granulepos (&pad->map, pad->current_granule,
|
||||
pad->current_granule);
|
||||
GST_BUFFER_OFFSET (buf) =
|
||||
gst_ogg_stream_granule_to_time (&pad->map, pad->current_granule);
|
||||
}
|
||||
|
||||
/* Mark discont on the buffer */
|
||||
if (pad->discont) {
|
||||
|
@ -586,7 +606,11 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
|
|||
pad->current_granule = granule;
|
||||
}
|
||||
|
||||
if (!gst_ogg_stream_packet_is_header (&pad->map, packet)) {
|
||||
/* Overload the value of b_o_s in ogg_packet with a flag whether or
|
||||
* not this is a header packet. Maybe some day this could be cleaned
|
||||
* up. */
|
||||
packet->b_o_s = gst_ogg_stream_packet_is_header (&pad->map, packet);
|
||||
if (!packet->b_o_s) {
|
||||
if (pad->start_time == GST_CLOCK_TIME_NONE) {
|
||||
gint64 duration = gst_ogg_stream_get_packet_duration (&pad->map, packet);
|
||||
if (duration != -1) {
|
||||
|
@ -602,6 +626,10 @@ gst_ogg_pad_submit_packet (GstOggPad * pad, ogg_packet * packet)
|
|||
|
||||
pad->start_time = gst_ogg_stream_granule_to_time (&pad->map,
|
||||
start_granule);
|
||||
GST_DEBUG ("start time %" G_GINT64_FORMAT, pad->start_time);
|
||||
} else {
|
||||
packet->granulepos = gst_ogg_stream_granule_to_granulepos (&pad->map,
|
||||
pad->map.accumulated_granule, pad->map.accumulated_granule);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -848,6 +876,7 @@ gst_ogg_chain_mark_discont (GstOggChain * chain)
|
|||
GstOggPad *pad = g_array_index (chain->streams, GstOggPad *, i);
|
||||
|
||||
pad->discont = TRUE;
|
||||
pad->map.last_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -880,6 +909,7 @@ gst_ogg_chain_new_stream (GstOggChain * chain, glong serialno)
|
|||
|
||||
GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
|
||||
ret->discont = TRUE;
|
||||
ret->map.last_size = 0;
|
||||
|
||||
ret->chain = chain;
|
||||
ret->ogg = chain->ogg;
|
||||
|
@ -1420,6 +1450,7 @@ gst_ogg_demux_activate_chain (GstOggDemux * ogg, GstOggChain * chain,
|
|||
|
||||
/* mark discont */
|
||||
pad->discont = TRUE;
|
||||
pad->map.last_size = 0;
|
||||
pad->last_ret = GST_FLOW_OK;
|
||||
|
||||
pad->is_sparse =
|
||||
|
|
|
@ -39,6 +39,8 @@ typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
|
|||
gint64 granulepos);
|
||||
typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
|
||||
gint64 granulepos);
|
||||
typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad,
|
||||
gint64 granule, gint64 keyframe_granule);
|
||||
|
||||
/* returns TRUE if the granulepos denotes a key frame */
|
||||
typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad,
|
||||
|
@ -63,6 +65,7 @@ struct _GstOggMap
|
|||
const gchar *media_type;
|
||||
GstOggMapSetupFunc setup_func;
|
||||
GstOggMapToGranuleFunc granulepos_to_granule_func;
|
||||
GstOggMapToGranuleposFunc granule_to_granulepos_func;
|
||||
GstOggMapIsKeyFrameFunc is_key_frame_func;
|
||||
GstOggMapIsHeaderPacketFunc is_header_func;
|
||||
GstOggMapPacketDurationFunc packet_duration_func;
|
||||
|
@ -126,13 +129,30 @@ gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
|
|||
}
|
||||
|
||||
if (mappers[pad->map].granulepos_to_granule_func == NULL) {
|
||||
GST_WARNING ("Failed to convert granulepos to time");
|
||||
return GST_CLOCK_TIME_NONE;
|
||||
GST_WARNING ("Failed to convert granulepos to granule");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
|
||||
}
|
||||
|
||||
gint64
|
||||
gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
|
||||
gint64 keyframe_granule)
|
||||
{
|
||||
if (granule == -1 || granule == 0) {
|
||||
return granule;
|
||||
}
|
||||
|
||||
if (mappers[pad->map].granule_to_granulepos_func == NULL) {
|
||||
GST_WARNING ("Failed to convert granule to granulepos");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mappers[pad->map].granule_to_granulepos_func (pad, granule,
|
||||
keyframe_granule);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_ogg_stream_packet_granulepos_is_key_frame (GstOggStream * pad,
|
||||
gint64 granulepos)
|
||||
|
@ -196,6 +216,20 @@ granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
|
|||
}
|
||||
}
|
||||
|
||||
static gint64
|
||||
granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
|
||||
gint64 keyframe_granule)
|
||||
{
|
||||
gint64 keyoffset;
|
||||
|
||||
if (pad->granuleshift != 0) {
|
||||
keyoffset = granule - keyframe_granule;
|
||||
return (keyframe_granule << pad->granuleshift) | keyoffset;
|
||||
} else {
|
||||
return granule;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_header_unknown (GstOggStream * pad, ogg_packet * packet)
|
||||
{
|
||||
|
@ -357,6 +391,15 @@ granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
|
|||
return dt + 4;
|
||||
}
|
||||
|
||||
static gint64
|
||||
granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
|
||||
gint64 keyframe_granule)
|
||||
{
|
||||
/* This conversion requires knowing more details about the Dirac
|
||||
* stream. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* vorbis */
|
||||
|
||||
|
@ -373,6 +416,7 @@ setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
|
|||
pad->granulerate_n = GST_READ_UINT32_LE (data);
|
||||
pad->granulerate_d = 1;
|
||||
pad->granuleshift = 0;
|
||||
pad->last_size = 0;
|
||||
GST_LOG ("sample rate: %" G_GUINT64_FORMAT, pad->granulerate_n);
|
||||
|
||||
pad->n_header_packets = 3;
|
||||
|
@ -408,28 +452,20 @@ packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
|
|||
int size;
|
||||
int duration;
|
||||
|
||||
mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
|
||||
size = pad->vorbis_mode_sizes[mode];
|
||||
if (packet->packet[0] & 1)
|
||||
return 0;
|
||||
|
||||
if (size) {
|
||||
switch ((packet->packet[0] >> (1 + pad->vorbis_log2_num_modes)) & 3) {
|
||||
case 0:
|
||||
case 3:
|
||||
duration = pad->long_size / 2;
|
||||
break;
|
||||
case 1:
|
||||
duration = (pad->long_size + pad->short_size) / 4;
|
||||
break;
|
||||
case 2:
|
||||
duration = (3 * pad->long_size - pad->short_size) / 4;
|
||||
break;
|
||||
default:
|
||||
duration = -1;
|
||||
break;
|
||||
}
|
||||
mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
|
||||
size = pad->vorbis_mode_sizes[mode] ? pad->long_size : pad->short_size;
|
||||
|
||||
if (pad->last_size == 0) {
|
||||
duration = 0;
|
||||
} else {
|
||||
duration = pad->short_size / 2;
|
||||
duration = pad->last_size / 4 + size / 4;
|
||||
}
|
||||
pad->last_size = size;
|
||||
|
||||
GST_DEBUG ("duration %d", (int) duration);
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
@ -898,6 +934,7 @@ static const GstOggMap mappers[] = {
|
|||
"video/x-theora",
|
||||
setup_theora_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_theora,
|
||||
is_header_theora,
|
||||
packet_duration_constant
|
||||
|
@ -907,6 +944,7 @@ static const GstOggMap mappers[] = {
|
|||
"audio/x-vorbis",
|
||||
setup_vorbis_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_vorbis,
|
||||
packet_duration_vorbis
|
||||
|
@ -916,6 +954,7 @@ static const GstOggMap mappers[] = {
|
|||
"audio/x-speex",
|
||||
setup_speex_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_count,
|
||||
packet_duration_constant
|
||||
|
@ -926,6 +965,7 @@ static const GstOggMap mappers[] = {
|
|||
setup_pcm_mapper,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
is_header_count,
|
||||
NULL
|
||||
},
|
||||
|
@ -935,6 +975,7 @@ static const GstOggMap mappers[] = {
|
|||
setup_cmml_mapper,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
is_header_count,
|
||||
NULL
|
||||
},
|
||||
|
@ -943,6 +984,7 @@ static const GstOggMap mappers[] = {
|
|||
"application/x-annodex",
|
||||
setup_fishead_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_count,
|
||||
NULL
|
||||
|
@ -953,6 +995,7 @@ static const GstOggMap mappers[] = {
|
|||
setup_fishead_mapper,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
is_header_true,
|
||||
NULL
|
||||
},
|
||||
|
@ -961,6 +1004,7 @@ static const GstOggMap mappers[] = {
|
|||
"audio/x-flac",
|
||||
setup_fLaC_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_count,
|
||||
NULL
|
||||
|
@ -970,6 +1014,7 @@ static const GstOggMap mappers[] = {
|
|||
"audio/x-flac",
|
||||
setup_flac_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_count,
|
||||
packet_duration_flac
|
||||
|
@ -981,12 +1026,14 @@ static const GstOggMap mappers[] = {
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
},
|
||||
{
|
||||
"CELT ", 8, 0,
|
||||
"audio/x-celt",
|
||||
setup_celt_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_count,
|
||||
packet_duration_constant
|
||||
|
@ -997,6 +1044,7 @@ static const GstOggMap mappers[] = {
|
|||
setup_kate_mapper,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
is_header_count,
|
||||
NULL
|
||||
},
|
||||
|
@ -1005,6 +1053,7 @@ static const GstOggMap mappers[] = {
|
|||
"video/x-dirac",
|
||||
setup_dirac_mapper,
|
||||
granulepos_to_granule_dirac,
|
||||
granule_to_granulepos_dirac,
|
||||
is_keyframe_dirac,
|
||||
is_header_count,
|
||||
packet_duration_constant
|
||||
|
@ -1014,6 +1063,7 @@ static const GstOggMap mappers[] = {
|
|||
"application/x-ogm-audio",
|
||||
setup_ogmaudio_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
|
@ -1023,6 +1073,7 @@ static const GstOggMap mappers[] = {
|
|||
"application/x-ogm-video",
|
||||
setup_ogmvideo_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
NULL,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
|
@ -1032,6 +1083,7 @@ static const GstOggMap mappers[] = {
|
|||
"application/x-ogm-text",
|
||||
setup_ogmtext_mapper,
|
||||
granulepos_to_granule_default,
|
||||
granule_to_granulepos_default,
|
||||
is_keyframe_true,
|
||||
is_header_unknown,
|
||||
NULL
|
||||
|
|
|
@ -62,6 +62,7 @@ struct _GstOggStream
|
|||
int long_size;
|
||||
int vorbis_log2_num_modes;
|
||||
int vorbis_mode_sizes[256];
|
||||
int last_size;
|
||||
};
|
||||
|
||||
|
||||
|
@ -72,6 +73,7 @@ GstClockTime gst_ogg_stream_get_start_time_for_granulepos (GstOggStream *pad,
|
|||
gint64 granulepos);
|
||||
GstClockTime gst_ogg_stream_granule_to_time (GstOggStream *pad, gint64 granule);
|
||||
gint64 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos);
|
||||
gint64 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule, gint64 keyframe_granule);
|
||||
GstClockTime gst_ogg_stream_get_packet_start_time (GstOggStream *pad,
|
||||
ogg_packet *packet);
|
||||
gboolean gst_ogg_stream_granulepos_is_key_frame (GstOggStream *pad,
|
||||
|
|
|
@ -94,8 +94,6 @@ parse_vorbis_header_packet (GstOggStream * pad, ogg_packet * packet)
|
|||
pad->short_size = short_size;
|
||||
pad->long_size = long_size;
|
||||
pad->nsn_increment = short_size >> 1;
|
||||
|
||||
pad->accumulated_granule = -long_size / 2;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue