From f40c93efb0adcee5f82aec208d83f1b3e7b74e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 23 Nov 2011 20:03:32 +0000 Subject: [PATCH] basevideodecoder: add API to drop a frame and post a QoS message on the bus https://bugzilla.gnome.org/show_bug.cgi?id=640017 API: gst_base_video_decoder_drop_frame() --- omx/gstbasevideodecoder.c | 132 ++++++++++++++++++++++++++++++-------- omx/gstbasevideodecoder.h | 7 +- 2 files changed, 113 insertions(+), 26 deletions(-) diff --git a/omx/gstbasevideodecoder.c b/omx/gstbasevideodecoder.c index 80cb7b9fd7..24bf16fbeb 100644 --- a/omx/gstbasevideodecoder.c +++ b/omx/gstbasevideodecoder.c @@ -969,6 +969,9 @@ gst_base_video_decoder_reset (GstBaseVideoDecoder * base_video_decoder, base_video_decoder->current_frame = NULL; } + base_video_decoder->dropped = 0; + base_video_decoder->processed = 0; + GST_BASE_VIDEO_CODEC (base_video_decoder)->system_frame_number = 0; base_video_decoder->base_picture_number = 0; @@ -1365,30 +1368,12 @@ gst_base_video_decoder_new_frame (GstBaseVideoDecoder * base_video_decoder) return frame; } -/** - * gst_base_video_decoder_finish_frame: - * @base_video_decoder: a #GstBaseVideoDecoder - * @frame: a decoded #GstVideoFrame - * - * @frame should have a valid decoded data buffer, whose metadata fields - * are then appropriately set according to frame data and pushed downstream. - * If no output data is provided, @frame is considered skipped. - * In any case, the frame is considered finished and released. - * - * Returns: a #GstFlowReturn resulting from sending data downstream - */ -GstFlowReturn -gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, - GstVideoFrame * frame) +static void +gst_base_video_decoder_prepare_finish_frame (GstBaseVideoDecoder * + base_video_decoder, GstVideoFrame * frame) { - GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; - GstBuffer *src_buffer; - GstFlowReturn ret = GST_FLOW_OK; GList *l, *events = NULL; - GST_LOG_OBJECT (base_video_decoder, "finish frame"); - GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); - #ifndef GST_DISABLE_GST_DEBUG GST_LOG_OBJECT (base_video_decoder, "n %d in %d out %d", g_list_length (GST_BASE_VIDEO_CODEC (base_video_decoder)->frames), @@ -1474,8 +1459,106 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, } } base_video_decoder->last_timestamp = frame->presentation_timestamp; +} - /* no buffer data means this frame is skipped/dropped */ +static void +gst_base_video_decoder_do_finish_frame (GstBaseVideoDecoder * dec, + GstVideoFrame * frame) +{ + GST_BASE_VIDEO_CODEC (dec)->frames = + g_list_remove (GST_BASE_VIDEO_CODEC (dec)->frames, frame); + + if (frame->src_buffer) + gst_buffer_unref (frame->src_buffer); + + gst_base_video_codec_free_frame (frame); +} + +/** + * gst_base_video_decoder_drop_frame: + * @dec: a #GstBaseVideoDecoder + * @frame: the #GstVideoFrame to drop + * + * Similar to gst_base_video_decoder_finish_frame(), but drops @frame in any + * case and posts a QoS message with the frame's details on the bus. + * In any case, the frame is considered finished and released. + * + * Returns: a #GstFlowReturn, usually GST_FLOW_OK. + * + * Since: 0.10.23 + */ +GstFlowReturn +gst_base_video_decoder_drop_frame (GstBaseVideoDecoder * dec, + GstVideoFrame * frame) +{ + GstClockTime stream_time, jitter, earliest_time, qostime, timestamp; + GstSegment *segment; + GstMessage *qos_msg; + gdouble proportion; + + GST_LOG_OBJECT (dec, "drop frame"); + + GST_BASE_VIDEO_CODEC_STREAM_LOCK (dec); + + gst_base_video_decoder_prepare_finish_frame (dec, frame); + + GST_DEBUG_OBJECT (dec, "dropping frame %" GST_TIME_FORMAT, + GST_TIME_ARGS (frame->presentation_timestamp)); + + dec->dropped++; + + /* post QoS message */ + timestamp = frame->presentation_timestamp; + proportion = GST_BASE_VIDEO_CODEC (dec)->proportion; + segment = &GST_BASE_VIDEO_CODEC (dec)->segment; + stream_time = + gst_segment_to_stream_time (segment, GST_FORMAT_TIME, timestamp); + qostime = gst_segment_to_running_time (segment, GST_FORMAT_TIME, timestamp); + earliest_time = GST_BASE_VIDEO_CODEC (dec)->earliest_time; + jitter = GST_CLOCK_DIFF (qostime, earliest_time); + qos_msg = gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, + qostime, stream_time, timestamp, GST_CLOCK_TIME_NONE); + gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000); + gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, + dec->processed, dec->dropped); + gst_element_post_message (GST_ELEMENT_CAST (dec), qos_msg); + + /* now free the frame */ + gst_base_video_decoder_do_finish_frame (dec, frame); + + GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (dec); + + return GST_FLOW_OK; +} + +/** + * gst_base_video_decoder_finish_frame: + * @base_video_decoder: a #GstBaseVideoDecoder + * @frame: a decoded #GstVideoFrame + * + * @frame should have a valid decoded data buffer, whose metadata fields + * are then appropriately set according to frame data and pushed downstream. + * If no output data is provided, @frame is considered skipped. + * In any case, the frame is considered finished and released. + * + * Returns: a #GstFlowReturn resulting from sending data downstream + */ +GstFlowReturn +gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, + GstVideoFrame * frame) +{ + GstVideoState *state = &GST_BASE_VIDEO_CODEC (base_video_decoder)->state; + GstBuffer *src_buffer; + GstFlowReturn ret = GST_FLOW_OK; + + GST_LOG_OBJECT (base_video_decoder, "finish frame"); + GST_BASE_VIDEO_CODEC_STREAM_LOCK (base_video_decoder); + + gst_base_video_decoder_prepare_finish_frame (base_video_decoder, frame); + + base_video_decoder->processed++; + + /* no buffer data means this frame is skipped */ if (!frame->src_buffer) { GST_DEBUG_OBJECT (base_video_decoder, "skipping frame %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->presentation_timestamp)); @@ -1584,9 +1667,8 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder, } done: - GST_BASE_VIDEO_CODEC (base_video_decoder)->frames = - g_list_remove (GST_BASE_VIDEO_CODEC (base_video_decoder)->frames, frame); - gst_base_video_codec_free_frame (frame); + + gst_base_video_decoder_do_finish_frame (base_video_decoder, frame); GST_BASE_VIDEO_CODEC_STREAM_UNLOCK (base_video_decoder); diff --git a/omx/gstbasevideodecoder.h b/omx/gstbasevideodecoder.h index 64d43d5b74..226dc3812a 100644 --- a/omx/gstbasevideodecoder.h +++ b/omx/gstbasevideodecoder.h @@ -182,6 +182,10 @@ struct _GstBaseVideoDecoder int reorder_depth; int distance_from_sync; + /* qos messages: frames dropped/processed */ + guint dropped; + guint processed; + /* FIXME before moving to base */ void *padding[GST_PADDING_LARGE]; }; @@ -267,7 +271,8 @@ GstClockTimeDiff gst_base_video_decoder_get_max_decode_time ( GstVideoFrame *frame); GstFlowReturn gst_base_video_decoder_finish_frame (GstBaseVideoDecoder *base_video_decoder, GstVideoFrame *frame); - +GstFlowReturn gst_base_video_decoder_drop_frame (GstBaseVideoDecoder *dec, + GstVideoFrame *frame); GType gst_base_video_decoder_get_type (void); G_END_DECLS