theoraenc: implement upstream keyframe force
Implement handling of upstream keyframe forcing. Update the design documents too. Fixes #578656
This commit is contained in:
parent
d0c3682627
commit
c628641880
@ -48,7 +48,7 @@ Implementation:
|
|||||||
triggered the event.
|
triggered the event.
|
||||||
(G_TYPE_UINT64)"stream-time" : the stream position that triggered the
|
(G_TYPE_UINT64)"stream-time" : the stream position that triggered the
|
||||||
event.
|
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.
|
event was triggered.
|
||||||
.... : optional other data fields.
|
.... : optional other data fields.
|
||||||
|
|
||||||
@ -70,3 +70,18 @@ Implementation:
|
|||||||
3) The application receives the GstForceKeyUnit on a sink padprobe of the sink
|
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
|
and reconfigures the sink to make it perform new actions after receiving
|
||||||
the next buffer.
|
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;
|
GstClockTime expected_ts;
|
||||||
gboolean next_discont;
|
gboolean next_discont;
|
||||||
|
|
||||||
|
gboolean force_keyframe;
|
||||||
|
|
||||||
guint packetno;
|
guint packetno;
|
||||||
guint64 bytes_out;
|
guint64 bytes_out;
|
||||||
guint64 granulepos_offset;
|
guint64 granulepos_offset;
|
||||||
|
@ -184,6 +184,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
|||||||
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
|
GST_BOILERPLATE (GstTheoraEnc, gst_theora_enc, GstElement, GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
|
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 GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
|
||||||
static GstStateChangeReturn theora_enc_change_state (GstElement * element,
|
static GstStateChangeReturn theora_enc_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
@ -292,6 +293,7 @@ gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
|
|||||||
|
|
||||||
enc->srcpad =
|
enc->srcpad =
|
||||||
gst_pad_new_from_static_template (&theora_enc_src_factory, "src");
|
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_element_add_pad (GST_ELEMENT (enc), enc->srcpad);
|
||||||
|
|
||||||
gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
|
gst_segment_init (&enc->segment, GST_FORMAT_UNDEFINED);
|
||||||
@ -667,6 +669,41 @@ theora_enc_sink_event (GstPad * pad, GstEvent * event)
|
|||||||
return res;
|
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
|
static gboolean
|
||||||
theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
|
theora_enc_is_discontinuous (GstTheoraEnc * enc, GstClockTime timestamp,
|
||||||
GstClockTime duration)
|
GstClockTime duration)
|
||||||
@ -704,6 +741,7 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|||||||
ogg_packet op;
|
ogg_packet op;
|
||||||
GstClockTime timestamp, duration, running_time;
|
GstClockTime timestamp, duration, running_time;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
gboolean force_keyframe;
|
||||||
|
|
||||||
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
|
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
|
||||||
|
|
||||||
@ -716,9 +754,34 @@ theora_enc_chain (GstPad * pad, GstBuffer * buffer)
|
|||||||
*/
|
*/
|
||||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||||
duration = GST_BUFFER_DURATION (buffer);
|
duration = GST_BUFFER_DURATION (buffer);
|
||||||
|
|
||||||
running_time =
|
running_time =
|
||||||
gst_segment_to_running_time (&enc->segment, GST_FORMAT_TIME, timestamp);
|
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
|
/* make sure we copy the discont flag to the next outgoing buffer when it's
|
||||||
* set on the incomming buffer */
|
* set on the incomming buffer */
|
||||||
if (GST_BUFFER_IS_DISCONT (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_info_init (&enc->info);
|
||||||
theora_comment_init (&enc->comment);
|
theora_comment_init (&enc->comment);
|
||||||
enc->packetno = 0;
|
enc->packetno = 0;
|
||||||
|
enc->force_keyframe = FALSE;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user