From: Alessandro Decina Date: Tue, 17 Nov 2015 00:19:57 +0000 (+1100) Subject: applemedia: vtdec: improve handing of decode errors/frame drops X-Git-Tag: 1.19.3~507^2~7578 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8f14882b446baf86b30af76249cc063b1c29dfe3;p=platform%2Fupstream%2Fgstreamer.git applemedia: vtdec: improve handing of decode errors/frame drops Improve decode error handling by avoiding calling into GstVideoDecoder from the VT decode callback. This removes contention on the GST_VIDEO_DECODER_STREAM_LOCK which used to make the decode callback slow enough for VT to start dropping lots of frames once the first frame was dropped. --- diff --git a/sys/applemedia/vtdec.c b/sys/applemedia/vtdec.c index d24c571..36137c8 100644 --- a/sys/applemedia/vtdec.c +++ b/sys/applemedia/vtdec.c @@ -48,6 +48,13 @@ GST_DEBUG_CATEGORY_STATIC (gst_vtdec_debug_category); #define GST_CAT_DEFAULT gst_vtdec_debug_category +enum +{ + /* leave some headroom for new GstVideoCodecFrameFlags flags */ + VTDEC_FRAME_FLAG_SKIP = (1 << 10), + VTDEC_FRAME_FLAG_DROP = (1 << 11), +}; + static void gst_vtdec_finalize (GObject * object); static gboolean gst_vtdec_start (GstVideoDecoder * decoder); @@ -706,8 +713,11 @@ sort_frames_by_pts (gconstpointer f1, gconstpointer f2, gpointer user_data) frame1 = (GstVideoCodecFrame *) f1; frame2 = (GstVideoCodecFrame *) f2; - pts1 = GST_BUFFER_PTS (frame1->output_buffer); - pts2 = GST_BUFFER_PTS (frame2->output_buffer); + pts1 = pts2 = GST_CLOCK_TIME_NONE; + if (frame1->output_buffer) + pts1 = GST_BUFFER_PTS (frame1->output_buffer); + if (frame2->output_buffer) + pts2 = GST_BUFFER_PTS (frame2->output_buffer); if (!GST_CLOCK_TIME_IS_VALID (pts1) || !GST_CLOCK_TIME_IS_VALID (pts2)) return 0; @@ -727,58 +737,47 @@ gst_vtdec_session_output_callback (void *decompression_output_ref_con, { GstVtdec *vtdec = (GstVtdec *) decompression_output_ref_con; GstVideoCodecFrame *frame = (GstVideoCodecFrame *) source_frame_ref_con; - GstBuffer *buf; GstVideoCodecState *state; GST_LOG_OBJECT (vtdec, "got output frame %p %d and VT buffer %p", frame, frame->decode_frame_number, image_buffer); + frame->output_buffer = NULL; + if (status != noErr) { GST_ERROR_OBJECT (vtdec, "Error decoding frame %d", (int) status); - goto drop; } - if (image_buffer == NULL) { - if (info_flags & kVTDecodeInfo_FrameDropped) - GST_DEBUG_OBJECT (vtdec, "Frame dropped by video toolbox"); - else + if (image_buffer) { + GstBuffer *buf = NULL; + + /* FIXME: use gst_video_decoder_allocate_output_buffer */ + state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (vtdec)); + if (state == NULL) { + GST_WARNING_OBJECT (vtdec, "Output state not configured, release buffer"); + frame->flags &= VTDEC_FRAME_FLAG_SKIP; + } else { + buf = + gst_core_video_buffer_new (image_buffer, &state->info, + vtdec->texture_cache == NULL); + gst_video_codec_state_unref (state); + GST_BUFFER_PTS (buf) = pts.value; + GST_BUFFER_DURATION (buf) = duration.value; + frame->output_buffer = buf; + } + } else { + if (info_flags & kVTDecodeInfo_FrameDropped) { + GST_DEBUG_OBJECT (vtdec, "Frame dropped by video toolbox %p %d", + frame, frame->decode_frame_number); + frame->flags &= VTDEC_FRAME_FLAG_DROP; + } else { GST_DEBUG_OBJECT (vtdec, "Decoded frame is NULL"); - goto drop; + frame->flags &= VTDEC_FRAME_FLAG_SKIP; + } } - /* FIXME: use gst_video_decoder_allocate_output_buffer */ - state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (vtdec)); - if (state == NULL) { - GST_WARNING_OBJECT (vtdec, "Output state not configured, release buffer"); - /* release as this usually means that the baseclass isn't ready to do - * the QoS that _drop requires and will lead to an assertion with the - * segment.format being undefined */ - goto release; - } - buf = - gst_core_video_buffer_new (image_buffer, &state->info, - vtdec->texture_cache == NULL); - gst_video_codec_state_unref (state); - - GST_BUFFER_PTS (buf) = pts.value; - GST_BUFFER_DURATION (buf) = duration.value; - frame->output_buffer = buf; g_async_queue_push_sorted (vtdec->reorder_queue, frame, sort_frames_by_pts, NULL); - - return; - -drop: - GST_WARNING_OBJECT (vtdec, "Frame dropped %p %d", frame, - frame->decode_frame_number); - gst_video_decoder_drop_frame (GST_VIDEO_DECODER (vtdec), frame); - return; - -release: - GST_WARNING_OBJECT (vtdec, "Frame released %p %d", frame, - frame->decode_frame_number); - gst_video_decoder_release_frame (GST_VIDEO_DECODER (vtdec), frame); - return; } static GstFlowReturn @@ -806,7 +805,7 @@ gst_vtdec_push_frames_if_needed (GstVtdec * vtdec, gboolean drain, while ((g_async_queue_length (vtdec->reorder_queue) >= vtdec->reorder_queue_length) || drain || flush) { frame = (GstVideoCodecFrame *) g_async_queue_try_pop (vtdec->reorder_queue); - if (frame && vtdec->texture_cache != NULL) { + if (frame && frame->output_buffer && vtdec->texture_cache != NULL) { frame->output_buffer = gst_core_video_texture_cache_get_gl_buffer (vtdec->texture_cache, frame->output_buffer); @@ -818,7 +817,9 @@ gst_vtdec_push_frames_if_needed (GstVtdec * vtdec, gboolean drain, * example) or we're draining/flushing */ if (frame) { - if (flush) + if (flush || frame->flags & VTDEC_FRAME_FLAG_SKIP) + gst_video_decoder_release_frame (decoder, frame); + else if (frame->flags & VTDEC_FRAME_FLAG_DROP) gst_video_decoder_drop_frame (decoder, frame); else ret = gst_video_decoder_finish_frame (decoder, frame);