mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-23 17:14:23 +00:00
vtenc: always enqueue frames, even on error
Even when we fail to encode frame, we should still enqueue it so it could be passed into handle_frame (with output_buffer == NULL). Otherwise, we risk GstVideoEncoder's queue of frames growing unbounded. Note: We're slightly changing the renegotiation code to accommodate for frames without output buffers, but this commit takes no ownership over the way negotiation is being done. https://bugzilla.gnome.org/show_bug.cgi?id=750669
This commit is contained in:
parent
79f57e62dc
commit
29c79d7595
1 changed files with 37 additions and 24 deletions
|
@ -1052,7 +1052,7 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstVideoCodecFrame * frame)
|
||||||
GstVideoCodecFrame *outframe;
|
GstVideoCodecFrame *outframe;
|
||||||
OSStatus vt_status;
|
OSStatus vt_status;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
guint i;
|
gboolean renegotiated;
|
||||||
CFDictionaryRef frame_props = NULL;
|
CFDictionaryRef frame_props = NULL;
|
||||||
|
|
||||||
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
|
if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
|
||||||
|
@ -1210,24 +1210,31 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstVideoCodecFrame * frame)
|
||||||
|
|
||||||
CVPixelBufferRelease (pbuf);
|
CVPixelBufferRelease (pbuf);
|
||||||
|
|
||||||
i = 0;
|
renegotiated = FALSE;
|
||||||
while ((outframe = g_async_queue_try_pop (self->cur_outframes))) {
|
while ((outframe = g_async_queue_try_pop (self->cur_outframes))) {
|
||||||
/* Try to renegotiate once */
|
if (outframe->output_buffer) {
|
||||||
if (i == 0) {
|
if (!renegotiated) {
|
||||||
meta = gst_buffer_get_core_media_meta (outframe->output_buffer);
|
meta = gst_buffer_get_core_media_meta (outframe->output_buffer);
|
||||||
if (!gst_vtenc_negotiate_downstream (self, meta->sample_buf)) {
|
/* Try to renegotiate once */
|
||||||
ret = GST_FLOW_NOT_NEGOTIATED;
|
if (meta) {
|
||||||
gst_video_codec_frame_unref (outframe);
|
if (gst_vtenc_negotiate_downstream (self, meta->sample_buf)) {
|
||||||
break;
|
renegotiated = TRUE;
|
||||||
|
} else {
|
||||||
|
ret = GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
gst_video_codec_frame_unref (outframe);
|
||||||
|
/* the rest of the frames will be pop'd and unref'd later */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_vtenc_update_latency (self);
|
gst_vtenc_update_latency (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* releases frame, even if it has no output buffer (i.e. failed to encode) */
|
||||||
ret =
|
ret =
|
||||||
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER_CAST (self),
|
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER_CAST (self),
|
||||||
outframe);
|
outframe);
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1249,9 +1256,24 @@ gst_vtenc_enqueue_buffer (void *outputCallbackRefCon,
|
||||||
gboolean is_keyframe;
|
gboolean is_keyframe;
|
||||||
GstVideoCodecFrame *frame;
|
GstVideoCodecFrame *frame;
|
||||||
|
|
||||||
|
frame =
|
||||||
|
gst_video_encoder_get_frame (GST_VIDEO_ENCODER_CAST (self),
|
||||||
|
GPOINTER_TO_INT (sourceFrameRefCon));
|
||||||
|
|
||||||
if (status != noErr) {
|
if (status != noErr) {
|
||||||
GST_ELEMENT_ERROR (self, LIBRARY, ENCODE, (NULL), ("Failed to encode: %d",
|
if (frame) {
|
||||||
(int) status));
|
GST_ELEMENT_ERROR (self, LIBRARY, ENCODE, (NULL),
|
||||||
|
("Failed to encode frame %d: %d", frame->system_frame_number,
|
||||||
|
(int) status));
|
||||||
|
} else {
|
||||||
|
GST_ELEMENT_ERROR (self, LIBRARY, ENCODE, (NULL),
|
||||||
|
("Failed to encode (frame unknown): %d", (int) status));
|
||||||
|
}
|
||||||
|
goto beach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!frame) {
|
||||||
|
GST_WARNING_OBJECT (self, "No corresponding frame found!");
|
||||||
goto beach;
|
goto beach;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,15 +1283,6 @@ gst_vtenc_enqueue_buffer (void *outputCallbackRefCon,
|
||||||
|
|
||||||
is_keyframe = gst_vtenc_buffer_is_keyframe (self, sampleBuffer);
|
is_keyframe = gst_vtenc_buffer_is_keyframe (self, sampleBuffer);
|
||||||
|
|
||||||
frame =
|
|
||||||
gst_video_encoder_get_frame (GST_VIDEO_ENCODER_CAST (self),
|
|
||||||
GPOINTER_TO_INT (sourceFrameRefCon));
|
|
||||||
|
|
||||||
if (!frame) {
|
|
||||||
GST_WARNING_OBJECT (self, "No corresponding frame found!");
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_keyframe) {
|
if (is_keyframe) {
|
||||||
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
|
GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
|
||||||
gst_vtenc_clear_cached_caps_downstream (self);
|
gst_vtenc_clear_cached_caps_downstream (self);
|
||||||
|
@ -1279,10 +1292,10 @@ gst_vtenc_enqueue_buffer (void *outputCallbackRefCon,
|
||||||
* to enable the use of the video meta API on the core media buffer */
|
* to enable the use of the video meta API on the core media buffer */
|
||||||
frame->output_buffer = gst_core_media_buffer_new (sampleBuffer, FALSE, TRUE);
|
frame->output_buffer = gst_core_media_buffer_new (sampleBuffer, FALSE, TRUE);
|
||||||
|
|
||||||
g_async_queue_push (self->cur_outframes, frame);
|
|
||||||
|
|
||||||
beach:
|
beach:
|
||||||
return;
|
/* needed anyway so the frame will be released */
|
||||||
|
if (frame)
|
||||||
|
g_async_queue_push (self->cur_outframes, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
Loading…
Reference in a new issue