vtenc: Only drain the encoder in ::finish(), not on every frame

Otherwise quality and bitrate will be bad.
This commit is contained in:
Sebastian Dröge 2014-09-17 17:08:57 +03:00
parent 0390398e39
commit c6f17d6013
2 changed files with 46 additions and 22 deletions

View file

@ -62,6 +62,7 @@ static gboolean gst_vtenc_set_format (GstVideoEncoder * enc,
GstVideoCodecState * input_state); GstVideoCodecState * input_state);
static GstFlowReturn gst_vtenc_handle_frame (GstVideoEncoder * enc, static GstFlowReturn gst_vtenc_handle_frame (GstVideoEncoder * enc,
GstVideoCodecFrame * frame); GstVideoCodecFrame * frame);
static GstFlowReturn gst_vtenc_finish (GstVideoEncoder * enc);
static void gst_vtenc_clear_cached_caps_downstream (GstVTEnc * self); static void gst_vtenc_clear_cached_caps_downstream (GstVTEnc * self);
@ -164,6 +165,7 @@ gst_vtenc_class_init (GstVTEncClass * klass)
gstvideoencoder_class->stop = gst_vtenc_stop; gstvideoencoder_class->stop = gst_vtenc_stop;
gstvideoencoder_class->set_format = gst_vtenc_set_format; gstvideoencoder_class->set_format = gst_vtenc_set_format;
gstvideoencoder_class->handle_frame = gst_vtenc_handle_frame; gstvideoencoder_class->handle_frame = gst_vtenc_handle_frame;
gstvideoencoder_class->finish = gst_vtenc_finish;
g_object_class_install_property (gobject_class, PROP_BITRATE, g_object_class_install_property (gobject_class, PROP_BITRATE,
g_param_spec_uint ("bitrate", "Bitrate", g_param_spec_uint ("bitrate", "Bitrate",
@ -248,7 +250,7 @@ gst_vtenc_start (GstVideoEncoder * enc)
{ {
GstVTEnc *self = GST_VTENC_CAST (enc); GstVTEnc *self = GST_VTENC_CAST (enc);
self->cur_outframes = g_ptr_array_new (); self->cur_outframes = g_async_queue_new ();
return TRUE; return TRUE;
} }
@ -278,7 +280,7 @@ gst_vtenc_stop (GstVideoEncoder * enc)
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
g_ptr_array_free (self->cur_outframes, TRUE); g_async_queue_unref (self->cur_outframes);
self->cur_outframes = NULL; self->cur_outframes = NULL;
return TRUE; return TRUE;
@ -410,6 +412,32 @@ not_negotiated:
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
static GstFlowReturn
gst_vtenc_finish (GstVideoEncoder * enc)
{
GstVTEnc *self = GST_VTENC_CAST (enc);
GstFlowReturn ret = GST_FLOW_OK;
OSStatus vt_status;
vt_status =
VTCompressionSessionCompleteFrames (self->session,
kCMTimePositiveInfinity);
if (vt_status != noErr) {
GST_WARNING_OBJECT (self, "VTCompressionSessionCompleteFrames returned %d",
(int) vt_status);
}
while (g_async_queue_length (self->cur_outframes) > 0) {
GstVideoCodecFrame *outframe = g_async_queue_try_pop (self->cur_outframes);
ret =
gst_video_encoder_finish_frame (GST_VIDEO_ENCODER_CAST (self),
outframe);
}
return ret;
}
static VTCompressionSessionRef static VTCompressionSessionRef
gst_vtenc_create_session (GstVTEnc * self) gst_vtenc_create_session (GstVTEnc * self)
{ {
@ -718,39 +746,35 @@ gst_vtenc_encode_frame (GstVTEnc * self, GstVideoCodecFrame * frame)
pbuf, ts, duration, self->options, pbuf, ts, duration, self->options,
GINT_TO_POINTER (frame->system_frame_number), NULL); GINT_TO_POINTER (frame->system_frame_number), NULL);
if (vt_status != 0) { if (vt_status != noErr) {
GST_WARNING_OBJECT (self, "VTCompressionSessionEncodeFrame returned %d", GST_WARNING_OBJECT (self, "VTCompressionSessionEncodeFrame returned %d",
(int) vt_status); (int) vt_status);
} }
vt_status =
VTCompressionSessionCompleteFrames (self->session, kCMTimeInvalid);
if (vt_status != 0) {
GST_WARNING_OBJECT (self, "VTCompressionSessionCompleteFrames returned %d",
(int) vt_status);
}
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);
gst_video_codec_frame_unref (frame); gst_video_codec_frame_unref (frame);
CVPixelBufferRelease (pbuf); CVPixelBufferRelease (pbuf);
if (self->cur_outframes->len > 0) { i = 0;
GstVideoCodecFrame *outframe = g_ptr_array_index (self->cur_outframes, while (g_async_queue_length (self->cur_outframes) > 0) {
0); GstVideoCodecFrame *outframe = g_async_queue_try_pop (self->cur_outframes);
meta = gst_buffer_get_core_media_meta (outframe->output_buffer);
if (!gst_vtenc_negotiate_downstream (self, meta->sample_buf))
ret = GST_FLOW_NOT_NEGOTIATED;
}
for (i = 0; i != self->cur_outframes->len; i++) { /* Try to renegotiate once */
GstVideoCodecFrame *outframe = g_ptr_array_index (self->cur_outframes, i); if (i == 0) {
meta = gst_buffer_get_core_media_meta (outframe->output_buffer);
if (!gst_vtenc_negotiate_downstream (self, meta->sample_buf)) {
ret = GST_FLOW_NOT_NEGOTIATED;
gst_video_codec_frame_unref (outframe);
break;
}
}
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++;
} }
g_ptr_array_set_size (self->cur_outframes, 0);
return ret; return ret;
@ -798,7 +822,7 @@ 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); frame->output_buffer = gst_core_media_buffer_new (sampleBuffer, FALSE);
g_ptr_array_add (self->cur_outframes, frame); g_async_queue_push (self->cur_outframes, frame);
beach: beach:
return; return;

View file

@ -71,7 +71,7 @@ struct _GstVTEnc
VTCompressionSessionRef session; VTCompressionSessionRef session;
CFMutableDictionaryRef options; CFMutableDictionaryRef options;
GPtrArray * cur_outframes; GAsyncQueue * cur_outframes;
gboolean expect_keyframe; gboolean expect_keyframe;
}; };