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()
This commit is contained in:
Tim-Philipp Müller 2011-11-23 20:03:32 +00:00
parent cdcc39455c
commit a039499bf1
2 changed files with 113 additions and 26 deletions

View file

@ -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);

View file

@ -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