diff --git a/src/gstducatividdec.c b/src/gstducatividdec.c
index 4bdd40b852a533caecee86b7dc1fd51e0ebe546f..ab3147dd4fb54cea58833c8dfefad6c4adf38278 100644 (file)
--- a/src/gstducatividdec.c
+++ b/src/gstducatividdec.c
}
}
+static GstFlowReturn
+gst_ducati_viddec_push_earliest (GstDucatiVidDec * self)
+{
+ guint64 earliest_order = G_MAXUINT64;
+ guint earliest_index = 0, i;
+ GstBuffer *buf;
+
+ if (self->backlog_nframes == 0)
+ return GST_FLOW_OK;
+
+ /* work out which frame has the earliest poc */
+ for (i = 0; i < self->backlog_nframes; i++) {
+ guint64 order = GST_BUFFER_OFFSET_END (self->backlog_frames[i]);
+ if (earliest_order == G_MAXUINT64 || order < earliest_order) {
+ earliest_order = order;
+ earliest_index = i;
+ }
+ }
+
+ /* send it, giving away the ref */
+ buf = self->backlog_frames[earliest_index];
+ self->backlog_frames[earliest_index] =
+ self->backlog_frames[--self->backlog_nframes];
+ GST_DEBUG_OBJECT (self, "Actually pushing backlog buffer %" GST_PTR_FORMAT,
+ buf);
+ return gst_pad_push (self->srcpad, buf);
+}
+
static void
gst_ducati_viddec_on_flush (GstDucatiVidDec * self, gboolean eos)
{
+ /* push everything on the backlog, ignoring errors */
+ while (self->backlog_nframes > 0) {
+ gst_ducati_viddec_push_earliest (self);
+ }
}
static gint
static GstBuffer *
gst_ducati_viddec_push_input (GstDucatiVidDec * self, GstBuffer * buf)
{
+ /* If we're about to push a keyframe, then we can flush all the frames
+ we currently have queued. For formats such as H264, this is actually
+ necessary as picture order count is local to each IDR + set of non
+ IDR frames, so will restart at 0 when next IDR frames comes in. For
+ other formats, it is not necessary, but avoids buffering frames that
+ do not need to be. */
+ if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT)) {
+ GST_DEBUG_OBJECT (self, "Got keyframe, pushing %u frames",
+ self->backlog_nframes);
+ while (self->backlog_nframes > 0) {
+ gst_ducati_viddec_push_earliest (self);
+ }
+ }
+
if (G_UNLIKELY (self->first_in_buffer) && self->codec_data) {
push_input (self, GST_BUFFER_DATA (self->codec_data),
GST_BUFFER_SIZE (self->codec_data));
static GstFlowReturn
gst_ducati_viddec_push_output (GstDucatiVidDec * self, GstBuffer * buf)
{
- return gst_pad_push (self->srcpad, buf);
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ /* add the frame to the list, the array will own the ref */
+ GST_DEBUG_OBJECT (self, "Adding buffer %" GST_PTR_FORMAT " to backlog", buf);
+ self->backlog_frames[self->backlog_nframes++] = buf;
+
+ /* push till we have no more than the max needed, or error */
+ while (self->backlog_nframes > self->backlog_maxframes) {
+ ret = gst_ducati_viddec_push_earliest (self);
+ if (ret != GST_FLOW_OK)
+ break;
+ }
+
+ return ret;
}
static gint
GST_INFO_OBJECT (self, "set caps done %d, %" GST_PTR_FORMAT, ret, outcaps);
+ /* default to no reordering */
+ self->backlog_maxframes = 0;
+
out:
if (outcaps)
gst_caps_unref (outcaps);
self->device = NULL;
self->input_bo = NULL;
+ self->backlog_maxframes = 0;
+ self->backlog_nframes = 0;
+
self->passed_in_bufs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) gst_buffer_unref);
}