Commit c6286418 authored by Olivier Crete's avatar Olivier Crete Committed by Wim Taymans

theoraenc: implement upstream keyframe force

Implement handling of upstream keyframe forcing.
Update the design documents too.
Fixes #578656
parent d0c36826
......@@ -48,7 +48,7 @@ Implementation:
triggered the event.
(G_TYPE_UINT64)"stream-time" : the stream position that triggered the
event.
(G_TYPE_UINT64)"running_time" : the running time of the stream when the
(G_TYPE_UINT64)"running-time" : the running time of the stream when the
event was triggered.
.... : optional other data fields.
......@@ -70,3 +70,18 @@ Implementation:
3) The application receives the GstForceKeyUnit on a sink padprobe of the sink
and reconfigures the sink to make it perform new actions after receiving
the next buffer.
Upstream
--------
When using RTP packets can get lost or receivers can be added at any time,
they may request a new key frame.
An downstream element sends an upstream "GstForceKeyUnit" event up the
pipeline.
When an element produces some kind of key unit in output, but has
no such concept in its input (like an encoder that takes raw frames),
it consumes the event (doesn't pass it upstream), and instead sends
a downstream GstForceKeyUnit event and a new keyframe.
......@@ -99,6 +99,8 @@ struct _GstTheoraEnc
GstClockTime expected_ts;
gboolean next_discont;
gboolean force_keyframe;
guint packetno;
guint64 bytes_out;
guint64 granulepos_offset;
......
......@@ -184,6 +184,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn theora_enc_change_state (GstElement * element,
GstStateChange transition);
......@@ -292,6 +293,7 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
enc->srcpad =
gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
gst_pad_set_event_function (enc->srcpad, theora_enc_src_event);
gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
......@@ -667,6 +669,41 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event)
return res;
}
static gboolean
theora_enc_src_event (GstPad * pad, GstEvent * event)
{
GstTheoraEnc *enc;
gboolean res = TRUE;
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_CUSTOM_UPSTREAM:
{
const GstStructure *s;
s = gst_event_get_structure (event);
if (gst_structure_has_name (s, "GstForceKeyUnit")) {
GST_OBJECT_LOCK (enc);
enc->force_keyframe = TRUE;
GST_OBJECT_UNLOCK (enc);
/* consume the event */
res = TRUE;
gst_event_unref (event);
} else {
res = gst_pad_push_event (enc->sinkpad, event);
}
break;
}
default:
res = gst_pad_push_event (enc->sinkpad, event);
break;
}
return res;
}
static gboolean
theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
GstClockTime duration)
......@@ -704,6 +741,7 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
ogg_packet op;
GstClockTime timestamp, duration, running_time;
GstFlowReturn ret;
gboolean force_keyframe;
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
......@@ -716,9 +754,34 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
*/
timestamp = GST_BUFFER_TIMESTAMP (buffer);
duration = GST_BUFFER_DURATION (buffer);
running_time =
gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
/* see if we need to schedule a keyframe */
GST_OBJECT_LOCK (enc);
force_keyframe = enc->force_keyframe;
enc->force_keyframe = FALSE;
GST_OBJECT_UNLOCK (enc);
if (force_keyframe) {
GstClockTime stream_time;
GstStructure *s;
stream_time = gst_segment_to_stream_time (&enc->segment,
GST_FORMAT_TIME, timestamp);
s = gst_structure_new ("GstForceKeyUnit",
"timestamp", G_TYPE_UINT64, timestamp,
"stream-time", G_TYPE_UINT64, stream_time,
"running-time", G_TYPE_UINT64, running_time, NULL);
theora_enc_force_keyframe (enc);
gst_pad_push_event (enc->srcpad,
gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s));
}
/* 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)) {
......@@ -1044,6 +1107,7 @@ theora_enc_change_state (GstElement * element, GstStateChange transition)
theora_info_init (&enc->info);
theora_comment_init (&enc->comment);
enc->packetno = 0;
enc->force_keyframe = FALSE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment