mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
videoencoder: Handle all matching force-keyunit events at once
Previously we only handled one event at a time, which could lead to the following two suboptimal situations: - frame 0 at 20ms, frame 1 at 40ms and two force-keyunit events at 10ms and 15ms. We would create a new keyframe for both of the frames. - 100 force-keyunit events with running-time NONE would cause all following 100 frames to be made into a keyframe. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/684>
This commit is contained in:
parent
9b1f1f431a
commit
401d56a6a7
1 changed files with 55 additions and 33 deletions
|
@ -1527,43 +1527,55 @@ gst_video_encoder_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
|
||||||
|
|
||||||
GST_OBJECT_LOCK (encoder);
|
GST_OBJECT_LOCK (encoder);
|
||||||
if (priv->force_key_unit.head) {
|
if (priv->force_key_unit.head) {
|
||||||
ForcedKeyUnitEvent *fevt = NULL;
|
|
||||||
GstClockTime running_time;
|
GstClockTime running_time;
|
||||||
GList *l;
|
GList *l;
|
||||||
|
GQueue matching_fevt = G_QUEUE_INIT;
|
||||||
|
|
||||||
running_time =
|
running_time =
|
||||||
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
||||||
cstart);
|
cstart);
|
||||||
|
|
||||||
for (l = priv->force_key_unit.head; l; l = l->next) {
|
for (l = priv->force_key_unit.head; l; l = l->next) {
|
||||||
ForcedKeyUnitEvent *tmp = l->data;
|
ForcedKeyUnitEvent *fevt = l->data;
|
||||||
|
|
||||||
/* Skip pending keyunits */
|
/* Skip pending keyunits */
|
||||||
if (tmp->pending)
|
if (fevt->pending)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Simple case, keyunit ASAP */
|
/* Simple case, keyunit ASAP */
|
||||||
if (tmp->running_time == GST_CLOCK_TIME_NONE) {
|
if (fevt->running_time == GST_CLOCK_TIME_NONE) {
|
||||||
fevt = tmp;
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Event for before this frame */
|
/* Event for before this frame */
|
||||||
if (tmp->running_time <= running_time) {
|
if (fevt->running_time <= running_time) {
|
||||||
fevt = tmp;
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Otherwise all following events are in the future */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fevt) {
|
if (matching_fevt.length > 0) {
|
||||||
fevt->frame_id = frame->system_frame_number;
|
ForcedKeyUnitEvent *fevt;
|
||||||
|
gboolean all_headers = FALSE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (encoder,
|
GST_DEBUG_OBJECT (encoder,
|
||||||
"Forcing a key unit at running time %" GST_TIME_FORMAT,
|
"Forcing a key unit at running time %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (running_time));
|
GST_TIME_ARGS (running_time));
|
||||||
|
|
||||||
|
while ((fevt = g_queue_pop_head (&matching_fevt))) {
|
||||||
|
fevt->pending = TRUE;
|
||||||
|
fevt->frame_id = frame->system_frame_number;
|
||||||
|
if (fevt->all_headers)
|
||||||
|
all_headers = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame);
|
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame);
|
||||||
if (fevt->all_headers)
|
if (all_headers)
|
||||||
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME_HEADERS (frame);
|
GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME_HEADERS (frame);
|
||||||
fevt->pending = TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GST_OBJECT_UNLOCK (encoder);
|
GST_OBJECT_UNLOCK (encoder);
|
||||||
|
@ -2267,48 +2279,58 @@ gst_video_encoder_send_key_unit_unlocked (GstVideoEncoder * encoder,
|
||||||
GstVideoEncoderPrivate *priv = encoder->priv;
|
GstVideoEncoderPrivate *priv = encoder->priv;
|
||||||
GstClockTime stream_time, running_time;
|
GstClockTime stream_time, running_time;
|
||||||
GstEvent *ev;
|
GstEvent *ev;
|
||||||
ForcedKeyUnitEvent *fevt = NULL;
|
GList *l;
|
||||||
GList *l, *fevt_link = NULL;
|
GQueue matching_fevt = G_QUEUE_INIT;
|
||||||
|
ForcedKeyUnitEvent *fevt;
|
||||||
|
|
||||||
running_time =
|
running_time =
|
||||||
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
|
||||||
frame->pts);
|
frame->pts);
|
||||||
|
|
||||||
GST_OBJECT_LOCK (encoder);
|
GST_OBJECT_LOCK (encoder);
|
||||||
for (l = priv->force_key_unit.head; l; l = l->next) {
|
for (l = priv->force_key_unit.head; l;) {
|
||||||
ForcedKeyUnitEvent *tmp = l->data;
|
fevt = l->data;
|
||||||
|
|
||||||
/* Skip non-pending keyunits */
|
/* Skip non-pending keyunits */
|
||||||
if (!tmp->pending)
|
if (!fevt->pending) {
|
||||||
|
l = l->next;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Exact match using the frame id */
|
/* Exact match using the frame id */
|
||||||
if (frame->system_frame_number == tmp->frame_id) {
|
if (frame->system_frame_number == fevt->frame_id) {
|
||||||
fevt_link = l;
|
GList *next = l->next;
|
||||||
fevt = tmp;
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
break;
|
g_queue_delete_link (&priv->force_key_unit, l);
|
||||||
|
l = next;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Simple case, keyunit ASAP */
|
/* Simple case, keyunit ASAP */
|
||||||
if (tmp->running_time == GST_CLOCK_TIME_NONE) {
|
if (fevt->running_time == GST_CLOCK_TIME_NONE) {
|
||||||
fevt_link = l;
|
GList *next = l->next;
|
||||||
fevt = tmp;
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
break;
|
g_queue_delete_link (&priv->force_key_unit, l);
|
||||||
|
l = next;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Event for before this frame */
|
/* Event for before this frame */
|
||||||
if (tmp->running_time <= running_time) {
|
if (fevt->running_time <= running_time) {
|
||||||
fevt_link = l;
|
GList *next = l->next;
|
||||||
fevt = tmp;
|
g_queue_push_tail (&matching_fevt, fevt);
|
||||||
break;
|
g_queue_delete_link (&priv->force_key_unit, l);
|
||||||
|
l = next;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Otherwise all following events are in the future */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fevt_link)
|
|
||||||
g_queue_delete_link (&priv->force_key_unit, fevt_link);
|
|
||||||
GST_OBJECT_UNLOCK (encoder);
|
GST_OBJECT_UNLOCK (encoder);
|
||||||
|
|
||||||
if (fevt) {
|
while ((fevt = g_queue_pop_head (&matching_fevt))) {
|
||||||
stream_time =
|
stream_time =
|
||||||
gst_segment_to_stream_time (&encoder->output_segment, GST_FORMAT_TIME,
|
gst_segment_to_stream_time (&encoder->output_segment, GST_FORMAT_TIME,
|
||||||
frame->pts);
|
frame->pts);
|
||||||
|
|
Loading…
Reference in a new issue