From f93fcafe6489f70a8ae5d3f379ed8c2b8ed12018 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 25 Nov 2008 15:14:30 +0000 Subject: [PATCH] ext/theora/: Parse segment events. Original commit message from CVS: * ext/theora/gsttheoraenc.h: * ext/theora/theoraenc.c: (gst_theora_enc_init), (theora_buffer_from_packet), (theora_push_packet), (theora_enc_sink_event), (theora_enc_is_discontinuous), (theora_enc_chain): Parse segment events. Pass incomming buffer timestamps to outgoing buffers. Use the running_time to construct the granulepos. Fixes #562163. --- ChangeLog | 12 ++++++ ext/theora/gsttheoraenc.h | 2 + ext/theora/theoraenc.c | 108 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 94 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2839b5f..096c49b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2008-11-25 Wim Taymans + * ext/theora/gsttheoraenc.h: + * ext/theora/theoraenc.c: (gst_theora_enc_init), + (theora_buffer_from_packet), (theora_push_packet), + (theora_enc_sink_event), (theora_enc_is_discontinuous), + (theora_enc_chain): + Parse segment events. + Pass incomming buffer timestamps to outgoing buffers. + Use the running_time to construct the granulepos. + Fixes #562163. + +2008-11-25 Wim Taymans + * gst/playback/gstplaybin2.c: (activate_group): Fix buffer-duration property. diff --git a/ext/theora/gsttheoraenc.h b/ext/theora/gsttheoraenc.h index 6a04da7..1cc4308 100644 --- a/ext/theora/gsttheoraenc.h +++ b/ext/theora/gsttheoraenc.h @@ -67,6 +67,8 @@ struct _GstTheoraEnc GstPad *sinkpad; GstPad *srcpad; + GstSegment segment; + ogg_stream_state to; theora_state state; diff --git a/ext/theora/theoraenc.c b/ext/theora/theoraenc.c index 7292cae..21d9d76 100644 --- a/ext/theora/theoraenc.c +++ b/ext/theora/theoraenc.c @@ -286,6 +286,8 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class) gst_pad_new_from_static_template (&theora_enc_src_factory, "src"); gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad); + gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED); + enc->center = THEORA_DEF_CENTER; enc->border = THEORA_DEF_BORDER; @@ -430,7 +432,8 @@ granulepos_add (guint64 granulepos, guint64 addend, gint shift) /* prepare a buffer for transmission by passing data through libtheora */ static GstFlowReturn theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet, - GstClockTime timestamp, GstClockTime duration, GstBuffer ** buffer) + GstClockTime timestamp, GstClockTime running_time, + GstClockTime duration, GstBuffer ** buffer) { GstBuffer *buf; GstFlowReturn ret = GST_FLOW_OK; @@ -452,7 +455,7 @@ theora_buffer_from_packet (GstTheoraEnc * enc, ogg_packet * packet, GST_BUFFER_OFFSET (buf) = granulepos_to_timestamp (enc, GST_BUFFER_OFFSET_END (buf)); - GST_BUFFER_TIMESTAMP (buf) = timestamp + enc->timestamp_offset; + GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_DURATION (buf) = duration; if (enc->next_discont) { @@ -489,12 +492,14 @@ theora_push_buffer (GstTheoraEnc * enc, GstBuffer * buffer) static GstFlowReturn theora_push_packet (GstTheoraEnc * enc, ogg_packet * packet, - GstClockTime timestamp, GstClockTime duration) + GstClockTime timestamp, GstClockTime running_time, GstClockTime duration) { GstBuffer *buf; GstFlowReturn ret; - ret = theora_buffer_from_packet (enc, packet, timestamp, duration, &buf); + ret = + theora_buffer_from_packet (enc, packet, timestamp, running_time, duration, + &buf); if (ret == GST_FLOW_OK) ret = theora_push_buffer (enc, buf); @@ -581,19 +586,40 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event) enc = GST_THEORA_ENC (GST_PAD_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + gboolean update; + gdouble rate, applied_rate; + GstFormat format; + gint64 start, stop, time; + + gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, + &format, &start, &stop, &time); + + gst_segment_set_newsegment_full (&enc->segment, update, rate, + applied_rate, format, start, stop, time); + + res = gst_pad_push_event (enc->srcpad, event); + break; + } case GST_EVENT_EOS: if (enc->initialised) { - /* push last packet with eos flag */ + /* push last packet with eos flag, should not be called */ while (theora_encode_packetout (&enc->state, 1, &op)) { GstClockTime next_time = theora_enc_get_ogg_packet_end_time (enc, &op); - theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts); + theora_push_packet (enc, &op, GST_CLOCK_TIME_NONE, enc->next_ts, + next_time - enc->next_ts); enc->next_ts = next_time; } } res = gst_pad_push_event (enc->srcpad, event); break; + case GST_EVENT_FLUSH_STOP: + gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED); + res = gst_pad_push_event (enc->srcpad, event); + break; case GST_EVENT_CUSTOM_DOWNSTREAM: { const GstStructure *s; @@ -624,9 +650,9 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event) } static gboolean -theora_enc_is_discontinuous (GstTheoraEnc * enc, GstBuffer * buffer) +theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp, + GstClockTime duration) { - GstClockTime ts = GST_BUFFER_TIMESTAMP (buffer); GstClockTimeDiff max_diff; gboolean ret = FALSE; @@ -634,18 +660,19 @@ theora_enc_is_discontinuous (GstTheoraEnc * enc, GstBuffer * buffer) max_diff = (enc->info.fps_denominator * GST_SECOND * 3) / (enc->info.fps_numerator * 4); - if (ts != GST_CLOCK_TIME_NONE && enc->expected_ts != GST_CLOCK_TIME_NONE) { - if ((GstClockTimeDiff) (ts - enc->expected_ts) > max_diff) { + if (timestamp != GST_CLOCK_TIME_NONE + && enc->expected_ts != GST_CLOCK_TIME_NONE) { + if ((GstClockTimeDiff) (timestamp - enc->expected_ts) > max_diff) { GST_DEBUG_OBJECT (enc, "Incoming TS %" GST_TIME_FORMAT " exceeds expected value %" GST_TIME_FORMAT " by too much, marking discontinuity", - GST_TIME_ARGS (ts), GST_TIME_ARGS (enc->expected_ts)); + GST_TIME_ARGS (timestamp), GST_TIME_ARGS (enc->expected_ts)); ret = TRUE; } } - if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) - enc->expected_ts = ts + GST_BUFFER_DURATION (buffer); + if (GST_CLOCK_TIME_IS_VALID (duration)) + enc->expected_ts = timestamp + duration; else enc->expected_ts = GST_CLOCK_TIME_NONE; @@ -657,12 +684,28 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) { GstTheoraEnc *enc; ogg_packet op; - GstClockTime in_time; + GstClockTime timestamp, duration, running_time; GstFlowReturn ret; enc = GST_THEORA_ENC (GST_PAD_PARENT (pad)); - in_time = GST_BUFFER_TIMESTAMP (buffer); + /* we keep track of two timelines. + * - The timestamps from the incomming buffers, which we copy to the outgoing + * encoded buffers as-is. We need to do this as we simply forward the + * newsegment events. + * - The running_time of the buffers, which we use to construct the granulepos + * in the packets. + */ + timestamp = GST_BUFFER_TIMESTAMP (buffer); + duration = GST_BUFFER_DURATION (buffer); + running_time = + gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp); + + /* make sure we copy the discont flag to the next outgoing buffer when it's + * set on the incomming buffer */ + if (GST_BUFFER_IS_DISCONT (buffer)) { + enc->next_discont = TRUE; + } if (enc->packetno == 0) { /* no packets written yet, setup headers */ @@ -684,8 +727,9 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) if (theora_encode_header (&enc->state, &op) != 0) goto encoder_disabled; - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf1); + ret = + theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, + GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf1); if (ret != GST_FLOW_OK) { goto header_buffer_alloc; } @@ -697,8 +741,9 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) if (theora_encode_comment (&enc->comment, &op) != 0) goto encoder_disabled; - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf2); + ret = + theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, + GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf2); /* Theora expects us to put this packet buffer into an ogg page, * in which case it becomes the ogg library's responsibility to * free it. Since we're copying and outputting a gst_buffer, @@ -714,8 +759,9 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) if (theora_encode_tables (&enc->state, &op) != 0) goto encoder_disabled; - ret = theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, - GST_CLOCK_TIME_NONE, &buf3); + ret = + theora_buffer_from_packet (enc, &op, GST_CLOCK_TIME_NONE, + GST_CLOCK_TIME_NONE, GST_CLOCK_TIME_NONE, &buf3); if (ret != GST_FLOW_OK) { gst_buffer_unref (buf1); gst_buffer_unref (buf2); @@ -749,8 +795,9 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) } enc->granulepos_offset = - gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d); - enc->timestamp_offset = in_time; + gst_util_uint64_scale (running_time, enc->fps_n, + GST_SECOND * enc->fps_d); + enc->timestamp_offset = running_time; enc->next_ts = 0; } @@ -903,11 +950,12 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) buffer = newbuf; } - if (theora_enc_is_discontinuous (enc, buffer)) { + if (theora_enc_is_discontinuous (enc, running_time, duration)) { theora_enc_reset (enc); enc->granulepos_offset = - gst_util_uint64_scale (in_time, enc->fps_n, GST_SECOND * enc->fps_d); - enc->timestamp_offset = in_time; + gst_util_uint64_scale (running_time, enc->fps_n, + GST_SECOND * enc->fps_d); + enc->timestamp_offset = running_time; enc->next_ts = 0; enc->next_discont = TRUE; } @@ -916,10 +964,14 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer) ret = GST_FLOW_OK; while (theora_encode_packetout (&enc->state, 0, &op)) { - GstClockTime next_time = theora_enc_get_ogg_packet_end_time (enc, &op); + GstClockTime next_time; + + next_time = theora_enc_get_ogg_packet_end_time (enc, &op); ret = - theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts); + theora_push_packet (enc, &op, timestamp, enc->next_ts, + next_time - enc->next_ts); + enc->next_ts = next_time; if (ret != GST_FLOW_OK) goto data_push; -- 2.7.4