Set granulepos and timestamp correctly for streams not starting at 0, taking into account the initial delay

Original commit message from CVS:
Set granulepos and timestamp correctly for streams not starting at 0, taking into account the initial delay
This commit is contained in:
Tim-Philipp Müller 2005-01-31 19:23:08 +00:00
parent 6f43a65dc6
commit 0df042ef00
4 changed files with 97 additions and 6 deletions

View file

@ -1,3 +1,14 @@
2005-01-31 Tim-Philipp Müller <tim at centricular dot net>
* ext/theora/theoraenc.c: (theora_buffer_from_packet),
(theora_enc_chain), (theora_enc_change_state):
* ext/vorbis/vorbisenc.c: (gst_vorbisenc_init),
(gst_vorbisenc_buffer_from_packet), (gst_vorbisenc_chain),
(gst_vorbisenc_change_state):
* ext/vorbis/vorbisenc.h:
Set granulepos and timestamp correctly for streams not
starting at 0, taking into account the initial delay.
2005-01-31 Tim-Philipp Müller <tim at centricular dot net>
* gst/mpegstream/gstdvddemux.c:

View file

@ -103,7 +103,7 @@ struct _GstTheoraEnc
guint packetno;
guint64 bytes_out;
guint64 next_ts;
guint64 initial_delay;
};
struct _GstTheoraEncClass
@ -361,13 +361,24 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
GstClockTime timestamp, GstClockTime duration)
{
GstBuffer *buf;
guint64 granulepos_delta, timestamp_delta;
/* if duration is 0, it's a header packet and should
* have granulepos 0 (so no delta regardless of delay) */
if (duration == 0) {
granulepos_delta = 0;
timestamp_delta = 0;
} else {
granulepos_delta = enc->initial_delay * enc->fps / GST_SECOND;
timestamp_delta = enc->initial_delay;
}
buf = gst_pad_alloc_buffer (enc->srcpad,
GST_BUFFER_OFFSET_NONE, packet->bytes);
memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
GST_BUFFER_OFFSET (buf) = enc->bytes_out;
GST_BUFFER_OFFSET_END (buf) = packet->granulepos;
GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_OFFSET_END (buf) = packet->granulepos + granulepos_delta;
GST_BUFFER_TIMESTAMP (buf) = timestamp + timestamp_delta;
GST_BUFFER_DURATION (buf) = duration;
/* the second most significant bit of the first data byte is cleared
@ -382,6 +393,11 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet,
enc->packetno++;
GST_DEBUG ("encoded buffer of %d bytes. granulepos = %" G_GINT64_FORMAT
" + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buf),
packet->granulepos, granulepos_delta,
packet->granulepos + granulepos_delta);
return buf;
}
@ -450,6 +466,26 @@ theora_enc_chain (GstPad * pad, GstData * data)
enc = GST_THEORA_ENC (gst_pad_get_parent (pad));
if (GST_IS_EVENT (data)) {
switch (GST_EVENT_TYPE (data)) {
case GST_EVENT_DISCONTINUOUS:
{
guint64 val;
if (gst_event_discont_get_value (GST_EVENT (data), GST_FORMAT_TIME,
&val)) {
/* theora does not support discontinuities in the middle of
* a stream so we can't just increase the granulepos to reflect
* the new position, or can we? would that still be according
* to spec? */
if (enc->bytes_out == 0) {
enc->initial_delay = val;
GST_DEBUG ("initial delay = %" G_GUINT64_FORMAT, val);
} else {
GST_DEBUG ("mid stream discont: val = %" G_GUINT64_FORMAT, val);
}
}
gst_pad_event_default (pad, GST_EVENT (data));
return;
}
case GST_EVENT_EOS:
/* push last packet with eos flag */
while (theora_encode_packetout (&enc->state, 1, &op)) {
@ -669,6 +705,7 @@ theora_enc_change_state (GstElement * element)
theora_info_init (&enc->info);
theora_comment_init (&enc->comment);
enc->packetno = 0;
enc->initial_delay = 0;
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;

View file

@ -483,6 +483,8 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc)
vorbisenc->tags = gst_tag_list_new ();
vorbisenc->initial_delay = 0;
/* we're chained and we can deal with events */
GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
}
@ -716,16 +718,32 @@ static GstBuffer *
gst_vorbisenc_buffer_from_packet (VorbisEnc * vorbisenc, ogg_packet * packet)
{
GstBuffer *outbuf;
guint64 granulepos_delta, timestamp_delta;
/* header packets always need to have granulepos 0,
* regardless of the initial delay */
if (packet->granulepos == 0) {
granulepos_delta = 0;
timestamp_delta = 0;
} else {
granulepos_delta =
vorbisenc->initial_delay * vorbisenc->frequency / GST_SECOND;
timestamp_delta = vorbisenc->initial_delay;
}
outbuf = gst_buffer_new_and_alloc (packet->bytes);
memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos;
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos + granulepos_delta;
GST_BUFFER_TIMESTAMP (outbuf) =
vorbis_granule_time_copy (&vorbisenc->vd,
packet->granulepos) * GST_SECOND;
packet->granulepos) * GST_SECOND + timestamp_delta;
GST_DEBUG ("encoded buffer of %d bytes. granulepos = %" G_GINT64_FORMAT
" + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
packet->granulepos, granulepos_delta,
packet->granulepos + granulepos_delta);
GST_DEBUG ("encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf));
return outbuf;
}
@ -816,6 +834,24 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data)
}
gst_pad_event_default (pad, event);
return;
case GST_EVENT_DISCONTINUOUS:
{
guint64 val;
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &val)) {
/* vorbis does not support discontinuities in the middle of
* a stream so we can't just increase the granulepos to reflect
* the new position, or can we? would that still be according
* to spec? */
if (vorbisenc->samples_in == 0) {
vorbisenc->initial_delay = val;
GST_DEBUG ("initial delay = %" G_GUINT64_FORMAT, val);
} else {
GST_DEBUG ("mid stream discont: val = %" G_GUINT64_FORMAT, val);
}
}
}
/* fall through */
default:
gst_pad_event_default (pad, event);
return;
@ -1045,6 +1081,11 @@ gst_vorbisenc_change_state (GstElement * element)
case GST_STATE_PAUSED_TO_READY:
vorbisenc->setup = FALSE;
vorbisenc->header_sent = FALSE;
vorbisenc->initial_delay = 0;
vorbisenc->samples_in = 0;
vorbisenc->bytes_out = 0;
vorbisenc->channels = -1;
vorbisenc->frequency = -1;
gst_tag_list_free (vorbisenc->tags);
vorbisenc->tags = gst_tag_list_new ();
break;

View file

@ -77,6 +77,8 @@ struct _VorbisEnc {
gboolean setup;
gboolean header_sent;
gchar *last_message;
guint64 initial_delay; /* for streams not starting at timestamp/sample 0 */
};
struct _VorbisEncClass {