vdpau: more work on h264 decoder
authorCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
Wed, 16 Jun 2010 21:12:43 +0000 (23:12 +0200)
committerCarl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
Wed, 23 Jun 2010 19:51:53 +0000 (21:51 +0200)
sys/vdpau/Makefile.am
sys/vdpau/basevideodecoder/gstbasevideodecoder.c
sys/vdpau/basevideodecoder/gstbasevideodecoder.h
sys/vdpau/h264/gsth264dpb.c [new file with mode: 0644]
sys/vdpau/h264/gsth264dpb.h [new file with mode: 0644]
sys/vdpau/h264/gsth264parser.c
sys/vdpau/h264/gsth264parser.h
sys/vdpau/h264/gstvdph264dec.c
sys/vdpau/h264/gstvdph264dec.h
sys/vdpau/h264/gstvdph264frame.h

index 79a58b6..5875caf 100644 (file)
@@ -12,6 +12,7 @@ libgstvdpau_la_SOURCES = \
        h264/gstnalreader.c \
        h264/gsth264parser.c \
        h264/gstvdph264frame.c \
+       h264/gsth264dpb.c \
        h264/gstvdph264dec.c
 
 libgstvdpau_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(X11_CFLAGS) $(VDPAU_CFLAGS)
@@ -34,4 +35,5 @@ noinst_HEADERS = \
        h264/gstnalreader.h \
        h264/gsth264parser.h \
        h264/gstvdph264frame.h \
+       h264/gsth264dpb.h \
        h264/gstvdph264dec.h
\ No newline at end of file
index 438ccb7..570d793 100644 (file)
@@ -124,8 +124,6 @@ gst_base_video_decoder_new_frame (GstBaseVideoDecoder * base_video_decoder)
 static void
 gst_base_video_decoder_reset (GstBaseVideoDecoder * base_video_decoder)
 {
-  GList *g;
-
   GST_DEBUG ("reset");
 
   base_video_decoder->discont = TRUE;
@@ -152,13 +150,6 @@ gst_base_video_decoder_reset (GstBaseVideoDecoder * base_video_decoder)
 
   base_video_decoder->have_src_caps = FALSE;
 
-  for (g = g_list_first (base_video_decoder->frames); g; g = g_list_next (g)) {
-    GstVideoFrame *frame = g->data;
-    gst_video_frame_unref (frame);
-  }
-  g_list_free (base_video_decoder->frames);
-  base_video_decoder->frames = NULL;
-
   GST_OBJECT_LOCK (base_video_decoder);
   base_video_decoder->earliest_time = GST_CLOCK_TIME_NONE;
   base_video_decoder->proportion = 0.5;
@@ -1022,9 +1013,6 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder,
   GST_DEBUG ("pushing frame %" GST_TIME_FORMAT,
       GST_TIME_ARGS (frame->presentation_timestamp));
 
-  base_video_decoder->frames =
-      g_list_remove (base_video_decoder->frames, frame);
-
   gst_base_video_decoder_set_src_caps (base_video_decoder);
 
   if (base_video_decoder->sink_clipping) {
@@ -1137,9 +1125,6 @@ gst_base_video_decoder_skip_frame (GstBaseVideoDecoder * base_video_decoder,
   GST_DEBUG ("skipping frame %" GST_TIME_FORMAT,
       GST_TIME_ARGS (frame->presentation_timestamp));
 
-  base_video_decoder->frames =
-      g_list_remove (base_video_decoder->frames, frame);
-
   gst_video_frame_unref (frame);
 }
 
@@ -1171,9 +1156,6 @@ gst_base_video_decoder_have_frame (GstBaseVideoDecoder * base_video_decoder,
   GST_DEBUG ("dts %" GST_TIME_FORMAT, GST_TIME_ARGS (frame->decode_timestamp));
   GST_DEBUG ("dist %d", frame->distance_from_sync);
 
-  base_video_decoder->frames = g_list_append (base_video_decoder->frames,
-      frame);
-
   running_time = gst_segment_to_running_time (&base_video_decoder->segment,
       GST_FORMAT_TIME, frame->presentation_timestamp);
 
@@ -1234,37 +1216,6 @@ gst_base_video_decoder_get_current_frame (GstBaseVideoDecoder *
   return base_video_decoder->current_frame;
 }
 
-
-GstVideoFrame *
-gst_base_video_decoder_get_oldest_frame (GstBaseVideoDecoder *
-    base_video_decoder)
-{
-  GList *g;
-
-  g = g_list_first (base_video_decoder->frames);
-
-  if (g == NULL)
-    return NULL;
-  return (GstVideoFrame *) (g->data);
-}
-
-GstVideoFrame *
-gst_base_video_decoder_get_frame (GstBaseVideoDecoder * base_video_decoder,
-    int frame_number)
-{
-  GList *g;
-
-  for (g = g_list_first (base_video_decoder->frames); g; g = g_list_next (g)) {
-    GstVideoFrame *frame = g->data;
-
-    if (frame->system_frame_number == frame_number) {
-      return frame;
-    }
-  }
-
-  return NULL;
-}
-
 void
 gst_base_video_decoder_update_src_caps (GstBaseVideoDecoder *
     base_video_decoder)
@@ -1295,7 +1246,6 @@ gst_base_video_decoder_get_property (GObject * object, guint property_id,
   }
 }
 
-/* GObject vmethod implementations */
 static void
 gst_base_video_decoder_set_property (GObject * object, guint property_id,
     const GValue * value, GParamSpec * pspec)
index 1a56465..51b28ab 100644 (file)
@@ -95,8 +95,6 @@ struct _GstBaseVideoDecoder
   GstPad *srcpad;
   GstAdapter *input_adapter;
 
-  GList *frames;
-
   gboolean have_sync;
   gboolean discont;
 
diff --git a/sys/vdpau/h264/gsth264dpb.c b/sys/vdpau/h264/gsth264dpb.c
new file mode 100644 (file)
index 0000000..85f3c30
--- /dev/null
@@ -0,0 +1,263 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>.
+   *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+   *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gsth264dpb.h"
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_NUM_REF_FRAMES
+};
+
+GST_DEBUG_CATEGORY_STATIC (h264dpb_debug);
+#define GST_CAT_DEFAULT h264dpb_debug
+
+#define DEBUG_INIT \
+  GST_DEBUG_CATEGORY_INIT (h264dpb_debug, "h264dpb", 0, \
+  "H264 DPB");
+
+G_DEFINE_TYPE_WITH_CODE (GstH264DPB, gst_h264_dpb, G_TYPE_OBJECT, DEBUG_INIT);
+
+void
+gst_h264_dpb_fill_reference_frames (GstH264DPB * dpb,
+    VdpReferenceFrameH264 reference_frames[16])
+{
+  GstVdpH264Frame **frames;
+  guint i;
+
+  frames = dpb->frames;
+  for (i = 0; i < dpb->n_frames; i++) {
+    GstVdpH264Frame *frame = frames[i];
+
+    reference_frames[i].surface =
+        GST_VDP_VIDEO_BUFFER (GST_VIDEO_FRAME_CAST (frame)->src_buffer)->
+        surface;
+
+    reference_frames[i].is_long_term = frame->is_long_term;
+    reference_frames[i].top_is_reference = frame->is_reference;
+    reference_frames[i].bottom_is_reference = frame->is_reference;
+    reference_frames[i].field_order_cnt[0] = frame->poc;
+    reference_frames[i].field_order_cnt[1] = frame->poc;
+    reference_frames[i].frame_idx = frame->frame_num;
+  }
+}
+
+static void
+gst_h264_dpb_output (GstH264DPB * dpb, guint idx)
+{
+  GstVdpH264Frame *frame = dpb->frames[idx];
+
+  gst_video_frame_ref (GST_VIDEO_FRAME_CAST (frame));
+  dpb->output (dpb, frame);
+
+  if (!frame->is_reference) {
+    GstVdpH264Frame **frames;
+    guint i;
+
+    gst_video_frame_unref (GST_VIDEO_FRAME_CAST (frame));
+    dpb->n_frames--;
+
+    frames = dpb->frames;
+    for (i = idx; i < dpb->n_frames; i++)
+      frames[i] = frames[i + 1];
+  }
+}
+
+static gboolean
+gst_h264_dpb_bump (GstH264DPB * dpb, guint poc)
+{
+  GstVdpH264Frame **frames;
+  guint i;
+  gint bump_idx;
+
+  frames = dpb->frames;
+  bump_idx = -1;
+  for (i = 0; i < dpb->n_frames; i++) {
+    if (frames[i]->output_needed) {
+      bump_idx = i;
+      break;
+    }
+  }
+
+  if (bump_idx != -1) {
+    for (i = bump_idx + 1; i < dpb->n_frames; i++) {
+      if (frames[i]->output_needed && (frames[i]->poc < frames[bump_idx]->poc)) {
+        bump_idx = i;
+      }
+    }
+
+    if (frames[bump_idx]->poc < poc) {
+      gst_h264_dpb_output (dpb, bump_idx);
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+gboolean
+gst_h264_dpb_add (GstH264DPB * dpb, GstVdpH264Frame * h264_frame)
+{
+  GstVdpH264Frame **frames;
+
+  GST_DEBUG ("add frame with poc: %d", h264_frame->poc);
+
+  frames = dpb->frames;
+
+  if (h264_frame->is_reference) {
+
+    while (dpb->n_frames == dpb->max_frames) {
+      if (!gst_h264_dpb_bump (dpb, G_MAXUINT)) {
+        GST_ERROR_OBJECT (dpb, "Couldn't make room in DPB");
+        return FALSE;
+      }
+    }
+    dpb->frames[dpb->n_frames++] = h264_frame;
+  }
+
+  else {
+    if (dpb->n_frames == dpb->max_frames) {
+      while (gst_h264_dpb_bump (dpb, h264_frame->poc));
+
+      dpb->output (dpb, h264_frame);
+    }
+
+    else
+      dpb->frames[dpb->n_frames++] = h264_frame;
+  }
+
+  return TRUE;
+}
+
+void
+gst_h264_dpb_flush (GstH264DPB * dpb, gboolean output)
+{
+  GstVideoFrame **frames;
+  guint i;
+
+  if (output)
+    while (gst_h264_dpb_bump (dpb, G_MAXUINT));
+
+  frames = (GstVideoFrame **) dpb->frames;
+  for (i = 0; i < dpb->n_frames; i++)
+    gst_video_frame_unref (frames[i]);
+
+  dpb->n_frames = 0;
+
+}
+
+void
+gst_h264_dpb_mark_sliding (GstH264DPB * dpb)
+{
+  GstVdpH264Frame **frames;
+  guint i;
+  gint mark_idx;
+
+  frames = dpb->frames;
+  for (i = 0; i < dpb->n_frames; i++) {
+    if (frames[i]->is_reference && !frames[i]->is_long_term) {
+      mark_idx = i;
+      break;
+    }
+  }
+
+  if (mark_idx != -1) {
+    for (i = mark_idx; i < dpb->n_frames; i++) {
+      if (frames[i]->is_reference && !frames[i]->is_long_term &&
+          frames[i]->frame_num < frames[mark_idx]->frame_num)
+        mark_idx = i;
+    }
+
+    frames[mark_idx]->is_reference = FALSE;
+  }
+}
+
+/* GObject vmethod implementations */
+static void
+gst_h264_dpb_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstH264DPB *dpb = GST_H264_DPB (object);
+
+  switch (property_id) {
+    case PROP_NUM_REF_FRAMES:
+      g_value_set_uint (value, dpb->max_frames);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_h264_dpb_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstH264DPB *dpb = GST_H264_DPB (object);
+
+  switch (property_id) {
+    case PROP_NUM_REF_FRAMES:
+    {
+      guint i;
+
+      dpb->max_frames = g_value_get_uint (value);
+      for (i = dpb->n_frames; i > dpb->max_frames; i--)
+        gst_h264_dpb_bump (dpb, G_MAXUINT);
+
+      break;
+    }
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_h264_dpb_finalize (GObject * object)
+{
+  /* TODO: Add deinitalization code here */
+
+  G_OBJECT_CLASS (gst_h264_dpb_parent_class)->finalize (object);
+}
+
+static void
+gst_h264_dpb_init (GstH264DPB * dpb)
+{
+  dpb->n_frames = 0;
+  dpb->max_frames = MAX_DPB_SIZE;
+}
+
+static void
+gst_h264_dpb_class_init (GstH264DPBClass * klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gst_h264_dpb_finalize;
+  object_class->set_property = gst_h264_dpb_set_property;
+  object_class->get_property = gst_h264_dpb_get_property;
+
+  g_object_class_install_property (object_class, PROP_NUM_REF_FRAMES,
+      g_param_spec_uint ("num-ref-frames", "Num Ref Frames",
+          "How many reference frames the DPB should hold ",
+          0, 16, 16, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+}
diff --git a/sys/vdpau/h264/gsth264dpb.h b/sys/vdpau/h264/gsth264dpb.h
new file mode 100644 (file)
index 0000000..ff5fe0f
--- /dev/null
@@ -0,0 +1,74 @@
+/* GStreamer
+ *
+ * Copyright (C) 2009 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_H264_DPB_H_
+#define _GST_H264_DPB_H_
+
+#include <glib-object.h>
+
+#include "../gstvdp/gstvdpvideobuffer.h"
+
+#include "gstvdph264frame.h"
+
+G_BEGIN_DECLS
+
+#define MAX_DPB_SIZE 16
+
+
+#define GST_TYPE_H264_DPB             (gst_h264_dpb_get_type ())
+#define GST_H264_DPB(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_H264_DPB, GstH264DPB))
+#define GST_H264_DPB_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_H264_DPB, GstH264DPBClass))
+#define GST_IS_H264_DPB(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_H264_DPB))
+#define GST_IS_H264_DPB_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_H264_DPB))
+#define GST_H264_DPB_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_H264_DPB, GstH264DPBClass))
+
+typedef struct _GstH264DPB GstH264DPB;
+typedef struct _GstH264DPBClass GstH264DPBClass;
+
+struct _GstH264DPB
+{
+  GObject parent_instance;
+
+  GstVdpH264Frame *frames[MAX_DPB_SIZE];  
+  guint n_frames;
+  
+  guint max_frames;
+
+  void (*output) (GstH264DPB *dpb, GstVdpH264Frame *h264_frame);
+};
+
+struct _GstH264DPBClass
+{
+  GObjectClass parent_class;
+};
+
+void
+gst_h264_dpb_fill_reference_frames (GstH264DPB *dpb, VdpReferenceFrameH264 reference_frames[16]);
+
+gboolean gst_h264_dpb_add (GstH264DPB *dpb, GstVdpH264Frame *h264_frame);
+void gst_h264_dpb_flush (GstH264DPB *dpb, gboolean output);
+
+void gst_h264_dpb_mark_sliding (GstH264DPB *dpb);
+
+GType gst_h264_dpb_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* _GST_H264_DPB_H_ */
index f082107..1614c2d 100644 (file)
@@ -374,6 +374,7 @@ gst_h264_parser_parse_sequence (GstH264Parser * parser, guint8 * data,
   seq->bit_depth_chroma_minus8 = 0;
   memset (seq->scaling_lists_4x4, 16, 96);
   memset (seq->scaling_lists_8x8, 16, 384);
+  seq->mb_adaptive_frame_field_flag = 0;
   seq->frame_crop_left_offset = 0;
   seq->frame_crop_right_offset = 0;
   seq->frame_crop_top_offset = 0;
@@ -417,7 +418,7 @@ gst_h264_parser_parse_sequence (GstH264Parser * parser, guint8 * data,
 
   READ_UE_ALLOWED (&reader, seq->log2_max_frame_num_minus4, 0, 12);
   /* calculate MaxFrameNum */
-  seq->MaxFrameNum = pow (2, seq->log2_max_frame_num_minus4 + 4);
+  seq->MaxFrameNum = 1 << (seq->log2_max_frame_num_minus4 + 4);
 
   READ_UE_ALLOWED (&reader, seq->pic_order_cnt_type, 0, 2);
   if (seq->pic_order_cnt_type == 0) {
@@ -753,40 +754,39 @@ gst_h264_slice_parse_dec_ref_pic_marking (GstH264Slice * slice,
 
   m = &slice->dec_ref_pic_marking;
 
-  if (slice->nal_unit.IdrPicFlag) {
+  if (slice->nal_unit.IdrPicFlag == 0) {
     READ_UINT8 (reader, m->no_output_of_prior_pics_flag, 1);
     READ_UINT8 (reader, m->long_term_reference_flag, 1);
   } else {
     READ_UINT8 (reader, m->adaptive_ref_pic_marking_mode_flag, 1);
     if (m->adaptive_ref_pic_marking_mode_flag) {
       guint8 memory_management_control_operation;
+      guint i = 0;
 
       do {
         READ_UE_ALLOWED (reader, memory_management_control_operation, 0, 6);
+        m->ref_pic_marking[i].memory_management_control_operation =
+            memory_management_control_operation;
+
         if (memory_management_control_operation == 1 ||
-            memory_management_control_operation == 3) {
-          guint32 difference_of_pic_nums_minus1;
+            memory_management_control_operation == 3)
+          READ_UE (reader, m->ref_pic_marking[i].difference_of_pic_nums_minus1);
 
-          READ_UE (reader, difference_of_pic_nums_minus1);
-        }
-        if (memory_management_control_operation == 2) {
-          guint32 long_term_pic_num;
+        if (memory_management_control_operation == 2)
+          READ_UE (reader, m->ref_pic_marking[i].long_term_pic_num);
 
-          READ_UE (reader, long_term_pic_num);
-        }
         if (memory_management_control_operation == 3 ||
-            memory_management_control_operation == 6) {
-          guint32 long_term_frame_idx;
+            memory_management_control_operation == 6)
+          READ_UE (reader, m->ref_pic_marking[i].long_term_frame_idx);
 
-          READ_UE (reader, long_term_frame_idx);
-        }
-        if (memory_management_control_operation == 4) {
-          guint32 max_long_term_frame_idx_plus1;
+        if (memory_management_control_operation == 4)
+          READ_UE (reader, m->ref_pic_marking[i].max_long_term_frame_idx_plus1);
 
-          READ_UE (reader, max_long_term_frame_idx_plus1);
-        }
+        i++;
       }
       while (memory_management_control_operation != 0);
+
+      m->n_ref_pic_marking = i;
     }
   }
 
index 868c0e8..2c18c05 100644 (file)
@@ -183,7 +183,6 @@ struct _GstH264Sequence
   guint32 pic_height_in_map_units_minus1;
   guint8 frame_mbs_only_flag;
 
-  /* if !frame_mbs_only_flag */
   guint8 mb_adaptive_frame_field_flag;
 
   guint8 direct_8x8_inference_flag;
@@ -256,6 +255,18 @@ struct _GstH264DecRefPicMarking
 
   /* else */
   guint8 adaptive_ref_pic_marking_mode_flag;
+
+  struct {
+    guint8 memory_management_control_operation;
+
+    union {
+      guint32 difference_of_pic_nums_minus1;
+      guint32 long_term_pic_num;
+      guint32 long_term_frame_idx;
+      guint32 max_long_term_frame_idx_plus1;
+    };
+  } ref_pic_marking[10];
+  guint8 n_ref_pic_marking;
 };
 
 struct _GstH264PredWeightTable
index 2ba6373..2229714 100644 (file)
@@ -72,6 +72,21 @@ GST_BOILERPLATE_FULL (GstVdpH264Dec, gst_vdp_h264_dec, GstBaseVideoDecoder,
   } \
 }
 
+static GstFlowReturn
+gst_vdp_h264_dec_alloc_buffer (GstVdpH264Dec * h264_dec,
+    GstVdpVideoBuffer ** outbuf)
+{
+  GstVdpVideoSrcPad *vdp_pad;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  vdp_pad = (GstVdpVideoSrcPad *) GST_BASE_VIDEO_DECODER_SRC_PAD (h264_dec);
+  ret = gst_vdp_video_src_pad_alloc_buffer (vdp_pad, outbuf);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  return GST_FLOW_OK;
+}
+
 static gboolean
 gst_vdp_h264_dec_set_sink_caps (GstBaseVideoDecoder * base_video_decoder,
     GstCaps * caps)
@@ -165,25 +180,354 @@ gst_vdp_h264_dec_shape_output (GstBaseVideoDecoder * base_video_decoder,
   return gst_vdp_video_src_pad_push (vdp_pad, GST_VDP_VIDEO_BUFFER (buf));
 }
 
+static void
+gst_vdp_h264_dec_output (GstH264DPB * dpb, GstVdpH264Frame * h264_frame)
+{
+  GST_DEBUG ("poc: %d", h264_frame->poc);
+
+  gst_video_frame_unref (GST_VIDEO_FRAME_CAST (h264_frame));
+}
+
+static guint
+gst_vdp_h264_dec_calculate_poc (GstVdpH264Dec * h264_dec, GstH264Slice * slice)
+{
+  GstH264Picture *pic;
+  GstH264Sequence *seq;
+
+  guint poc;
+
+  pic = slice->picture;
+  seq = pic->sequence;
+
+  if (seq->pic_order_cnt_type == 0) {
+    guint32 max_poc_cnt_lsb = 1 << (seq->log2_max_pic_order_cnt_lsb_minus4 + 4);
+
+    if ((slice->pic_order_cnt_lsb < h264_dec->prev_poc_lsb) &&
+        ((h264_dec->prev_poc_lsb - slice->pic_order_cnt_lsb) >=
+            (max_poc_cnt_lsb / 2)))
+      h264_dec->poc_msb = h264_dec->poc_msb + max_poc_cnt_lsb;
+
+    else if ((slice->pic_order_cnt_lsb > h264_dec->prev_poc_lsb) &&
+        ((slice->pic_order_cnt_lsb - h264_dec->prev_poc_lsb) >
+            (max_poc_cnt_lsb / 2)))
+      h264_dec->poc_msb = h264_dec->poc_msb - max_poc_cnt_lsb;
+
+    poc = h264_dec->poc_msb + slice->pic_order_cnt_lsb;
+
+    h264_dec->prev_poc_lsb = slice->pic_order_cnt_lsb;
+  }
+
+  return poc;
+}
+
+static void
+gst_vdp_h264_dec_init_frame_info (GstVdpH264Dec * h264_dec,
+    GstVdpH264Frame * h264_frame)
+{
+  GstH264Slice *slice;
+
+  slice = &h264_frame->slice_hdr;
+
+  h264_frame->poc = gst_vdp_h264_dec_calculate_poc (h264_dec, slice);
+
+  h264_frame->is_long_term = FALSE;
+
+  /* is reference */
+  if (slice->nal_unit.ref_idc == 0)
+    h264_frame->is_reference = FALSE;
+  else if (slice->nal_unit.IdrPicFlag) {
+    h264_frame->is_reference = TRUE;
+    h264_frame->is_long_term =
+        slice->dec_ref_pic_marking.long_term_reference_flag;
+  } else {
+    if (slice->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag)
+      GST_ERROR ("FIXME: implement adaptive ref pic marking");
+    else
+      h264_frame->is_reference = TRUE;
+  }
+
+}
+
+static gboolean
+gst_vdp_h264_dec_idr (GstVdpH264Dec * h264_dec, GstVdpH264Frame * h264_frame)
+{
+  GstH264Slice *slice;
+  GstH264Sequence *seq;
+
+  h264_dec->poc_msb = 0;
+  h264_dec->prev_poc_lsb = 0;
+
+  slice = &h264_frame->slice_hdr;
+  if (slice->dec_ref_pic_marking.no_output_of_prior_pics_flag)
+    gst_h264_dpb_flush (h264_dec->dpb, FALSE);
+  else
+    gst_h264_dpb_flush (h264_dec->dpb, TRUE);
+
+
+  seq = slice->picture->sequence;
+  if (seq != h264_dec->sequence) {
+    GstVdpDevice *device;
+
+    gst_base_video_decoder_update_src_caps (GST_BASE_VIDEO_DECODER (h264_dec));
+
+    device = gst_vdp_video_src_pad_get_device
+        (GST_VDP_VIDEO_SRC_PAD (GST_BASE_VIDEO_DECODER_SRC_PAD (h264_dec)));
+
+    if (device) {
+      GstVideoState *state;
+      VdpDecoderProfile profile;
+      VdpStatus status;
+
+      if (h264_dec->decoder != VDP_INVALID_HANDLE) {
+        device->vdp_decoder_destroy (h264_dec->decoder);
+        h264_dec->decoder = VDP_INVALID_HANDLE;
+      }
+
+      state =
+          gst_base_video_decoder_get_state (GST_BASE_VIDEO_DECODER (h264_dec));
+
+      switch (seq->profile_idc) {
+        case 66:
+          profile = VDP_DECODER_PROFILE_H264_BASELINE;
+          break;
+
+        case 77:
+          profile = VDP_DECODER_PROFILE_H264_MAIN;
+          break;
+
+        case 100:
+          profile = VDP_DECODER_PROFILE_H264_HIGH;
+          break;
+
+        default:
+          return FALSE;
+      }
+
+      status = device->vdp_decoder_create (device->device, profile,
+          state->width, state->height, seq->num_ref_frames, &h264_dec->decoder);
+      if (status != VDP_STATUS_OK) {
+        GST_ELEMENT_ERROR (h264_dec, RESOURCE, READ,
+            ("Could not create vdpau decoder"),
+            ("Error returned from vdpau was: %s",
+                device->vdp_get_error_string (status)));
+
+        return FALSE;
+      }
+    } else
+      return FALSE;
+
+    g_object_set (h264_dec->dpb, "num-ref-frames", seq->num_ref_frames, NULL);
+
+    h264_dec->sequence = seq;
+  }
+
+  return TRUE;
+}
+
+static VdpPictureInfoH264
+gst_vdp_h264_dec_fill_info (GstVdpH264Dec * h264_dec,
+    GstVdpH264Frame * h264_frame)
+{
+  GstH264Slice *slice;
+  GstH264Picture *pic;
+  GstH264Sequence *seq;
+  VdpPictureInfoH264 info;
+
+  slice = &h264_frame->slice_hdr;
+  pic = slice->picture;
+  seq = pic->sequence;
+
+  info.slice_count = h264_frame->slices->len;
+
+  /* FIXME: we only handle frames for now */
+  info.field_order_cnt[0] = h264_frame->poc;
+  info.field_order_cnt[1] = h264_frame->poc;
+
+  info.is_reference = h264_frame->is_reference;
+
+  info.field_pic_flag = slice->field_pic_flag;
+  info.bottom_field_flag = slice->bottom_field_flag;
+
+  info.num_ref_frames = seq->num_ref_frames;
+  info.frame_mbs_only_flag = seq->frame_mbs_only_flag;
+  info.mb_adaptive_frame_field_flag = seq->mb_adaptive_frame_field_flag;
+  info.log2_max_frame_num_minus4 = seq->log2_max_frame_num_minus4;
+  info.pic_order_cnt_type = seq->pic_order_cnt_type;
+  info.log2_max_pic_order_cnt_lsb_minus4 =
+      seq->log2_max_pic_order_cnt_lsb_minus4;
+  info.delta_pic_order_always_zero_flag = seq->delta_pic_order_always_zero_flag;
+  info.direct_8x8_inference_flag = seq->direct_8x8_inference_flag;
+
+
+  info.constrained_intra_pred_flag = pic->constrained_intra_pred_flag;
+  info.weighted_pred_flag = pic->weighted_pred_flag;
+  info.weighted_bipred_idc = pic->weighted_bipred_idc;
+  info.transform_8x8_mode_flag = pic->transform_8x8_mode_flag;
+  info.chroma_qp_index_offset = pic->chroma_qp_index_offset;
+  info.second_chroma_qp_index_offset = pic->second_chroma_qp_index_offset;
+  info.pic_init_qp_minus26 = pic->pic_init_qp_minus26;
+  info.num_ref_idx_l0_active_minus1 = pic->num_ref_idx_l0_active_minus1;
+  info.num_ref_idx_l1_active_minus1 = pic->num_ref_idx_l1_active_minus1;
+  info.entropy_coding_mode_flag = pic->entropy_coding_mode_flag;
+  info.pic_order_present_flag = pic->pic_order_present_flag;
+  info.deblocking_filter_control_present_flag =
+      pic->deblocking_filter_control_present_flag;
+  info.redundant_pic_cnt_present_flag = pic->redundant_pic_cnt_present_flag;
+
+  memcpy (&info.scaling_lists_4x4, &pic->scaling_lists_4x4, 96);
+  memcpy (&info.scaling_lists_8x8, &pic->scaling_lists_8x8, 128);
+
+  gst_h264_dpb_fill_reference_frames (h264_dec->dpb, info.referenceFrames);
+
+  return info;
+}
+
+static VdpBitstreamBuffer *
+gst_vdp_h264_dec_create_bitstream_buffers (GstVdpH264Dec * h264_dec,
+    GstVdpH264Frame * h264_frame, guint * n_bufs)
+{
+  VdpBitstreamBuffer *bufs;
+
+  if (h264_dec->packetized) {
+    guint i;
+
+    bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len * 2);
+    *n_bufs = h264_frame->slices->len * 2;
+
+    for (i = 0; i < h264_frame->slices->len; i++) {
+      static const guint8 start_code[] = { 0x00, 0x00, 0x01 };
+      guint idx;
+      GstBuffer *buf;
+
+      idx = i * 2;
+      bufs[idx].bitstream = start_code;
+      bufs[idx].bitstream_bytes = 3;
+      bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
+
+      idx = idx + 1;
+      buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i));
+      bufs[idx].bitstream = GST_BUFFER_DATA (buf) + h264_dec->nal_length_size;
+      bufs[idx].bitstream_bytes = GST_BUFFER_SIZE (buf) -
+          h264_dec->nal_length_size;
+      bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
+    }
+  }
+
+  else {
+    guint i;
+
+    bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len * 2);
+    *n_bufs = h264_frame->slices->len * 2;
+
+    for (i = 0; i < h264_frame->slices->len; i++) {
+      GstBuffer *buf;
+
+      buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i));
+      bufs[i].bitstream = GST_BUFFER_DATA (buf);
+      bufs[i].bitstream_bytes = GST_BUFFER_SIZE (buf);
+      bufs[i].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
+    }
+  }
+
+  return bufs;
+}
+
 static GstFlowReturn
 gst_vdp_h264_dec_handle_frame (GstBaseVideoDecoder * base_video_decoder,
     GstVideoFrame * frame, GstClockTimeDiff deadline)
 {
+  GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+
   GstVdpH264Frame *h264_frame;
+  GstH264Slice *slice;
+  GstH264Picture *pic;
+  GstH264Sequence *seq;
+
+  GstFlowReturn ret;
+  GstVdpVideoBuffer *outbuf;
+  VdpPictureInfoH264 info;
+  GstVdpDevice *device;
+  VdpVideoSurface surface;
+  VdpBitstreamBuffer *bufs;
+  guint n_bufs;
+  VdpStatus status;
 
   GST_DEBUG ("handle_frame");
 
   h264_frame = (GstVdpH264Frame *) frame;
 
-  GST_DEBUG ("frame_num: %d", h264_frame->slice_hdr.frame_num);
-  GST_DEBUG ("pic_order_cnt_type: %d",
-      h264_frame->slice_hdr.picture->sequence->pic_order_cnt_type);
-  GST_DEBUG ("pic_order_cnt_lsb: %d", h264_frame->slice_hdr.pic_order_cnt_lsb);
-  GST_DEBUG ("delta_pic_order_cnt_bottom: %d",
-      h264_frame->slice_hdr.delta_pic_order_cnt_bottom);
+  slice = &h264_frame->slice_hdr;
+  pic = slice->picture;
+  seq = pic->sequence;
+
+
+  if (slice->nal_unit.IdrPicFlag) {
+    if (gst_vdp_h264_dec_idr (h264_dec, h264_frame))
+      h264_dec->got_idr = TRUE;
+    else {
+      gst_base_video_decoder_skip_frame (base_video_decoder, frame);
+      return GST_FLOW_OK;
+    }
+  }
+
+  /* check if we've got a IDR frame yet */
+  if (!h264_dec->got_idr) {
+    gst_base_video_decoder_skip_frame (base_video_decoder, frame);
+    return GST_FLOW_OK;
+  }
+
+  gst_vdp_h264_dec_init_frame_info (h264_dec, h264_frame);
+
+
+
+  /* decoding */
+  if ((ret = gst_vdp_h264_dec_alloc_buffer (h264_dec, &outbuf) != GST_FLOW_OK))
+    goto alloc_error;
+
+  device = GST_VDP_VIDEO_BUFFER (outbuf)->device;
+  surface = GST_VDP_VIDEO_BUFFER (outbuf)->surface;
+
+  info = gst_vdp_h264_dec_fill_info (h264_dec, h264_frame);
+  bufs = gst_vdp_h264_dec_create_bitstream_buffers (h264_dec, h264_frame,
+      &n_bufs);
+
+  status = device->vdp_decoder_render (h264_dec->decoder, surface,
+      (VdpPictureInfo *) & info, n_bufs, bufs);
+
+  g_free (bufs);
+  if (status != VDP_STATUS_OK)
+    goto decode_error;
+
+  frame->src_buffer = GST_BUFFER_CAST (outbuf);
+
+
+
+  /* DPB handling */
+  if (slice->nal_unit.ref_idc != 0 && !slice->nal_unit.IdrPicFlag) {
+    if (slice->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag)
+      GST_ERROR ("FIXME: implement adaptive ref pic marking");
+    else
+      gst_h264_dpb_mark_sliding (h264_dec->dpb);
+  }
+  gst_h264_dpb_add (h264_dec->dpb, h264_frame);
 
-  gst_base_video_decoder_skip_frame (base_video_decoder, frame);
   return GST_FLOW_OK;
+
+alloc_error:
+  GST_ERROR_OBJECT (h264_dec, "Could not allocate output buffer");
+  gst_base_video_decoder_skip_frame (base_video_decoder, frame);
+  return ret;
+
+decode_error:
+  GST_ELEMENT_ERROR (h264_dec, RESOURCE, READ,
+      ("Could not decode"),
+      ("Error returned from vdpau was: %s",
+          device->vdp_get_error_string (status)));
+
+  gst_buffer_unref (GST_BUFFER_CAST (outbuf));
+  gst_base_video_decoder_skip_frame (base_video_decoder, frame);
+
+  return GST_FLOW_ERROR;
 }
 
 static gint
@@ -445,6 +789,11 @@ gst_vdp_h264_dec_create_srcpad (GstBaseVideoDecoder * base_video_decoder,
 static gboolean
 gst_vdp_h264_dec_flush (GstBaseVideoDecoder * base_video_decoder)
 {
+  GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
+
+  h264_dec->got_idr = FALSE;
+  gst_h264_dpb_flush (h264_dec->dpb, FALSE);
+
   return TRUE;
 }
 
@@ -455,8 +804,15 @@ gst_vdp_h264_dec_start (GstBaseVideoDecoder * base_video_decoder)
 
   h264_dec->packetized = FALSE;
   h264_dec->nal_length_size = SYNC_CODE_SIZE;
+
+  h264_dec->got_idr = FALSE;
+  h264_dec->sequence = NULL;
+
   h264_dec->parser = g_object_new (GST_TYPE_H264_PARSER, NULL);
 
+  h264_dec->dpb = g_object_new (GST_TYPE_H264_DPB, NULL);
+  h264_dec->dpb->output = gst_vdp_h264_dec_output;
+
   return TRUE;
 }
 
@@ -465,7 +821,21 @@ gst_vdp_h264_dec_stop (GstBaseVideoDecoder * base_video_decoder)
 {
   GstVdpH264Dec *h264_dec = GST_VDP_H264_DEC (base_video_decoder);
 
+  GstVdpVideoSrcPad *vdp_pad;
+  GstVdpDevice *device;
+
   g_object_unref (h264_dec->parser);
+  g_object_unref (h264_dec->dpb);
+
+  vdp_pad =
+      GST_VDP_VIDEO_SRC_PAD (GST_BASE_VIDEO_DECODER_SRC_PAD
+      (base_video_decoder));
+
+  if ((device = gst_vdp_video_src_pad_get_device (vdp_pad))) {
+
+    if (h264_dec->decoder != VDP_INVALID_HANDLE)
+      device->vdp_decoder_destroy (h264_dec->decoder);
+  }
 
   return TRUE;
 }
index 6f48156..01bb52b 100644 (file)
@@ -26,6 +26,7 @@
 #include "../basevideodecoder/gstbasevideodecoder.h"
 
 #include "gsth264parser.h"
+#include "gsth264dpb.h"
 
 G_BEGIN_DECLS
 
@@ -44,10 +45,18 @@ typedef struct _GstVdpH264DecClass GstVdpH264DecClass;
 struct _GstVdpH264Dec {
   GstBaseVideoDecoder base_video_decoder;
 
-  GstBuffer *codec_data;
   gboolean packetized;
   guint8 nal_length_size;
+
   GstH264Parser *parser;
+  GstH264DPB *dpb;
+
+  GstH264Sequence *sequence;
+  gboolean got_idr;
+  VdpDecoder decoder;
+  
+  guint poc_msb;
+  guint prev_poc_lsb;
 };
 
 struct _GstVdpH264DecClass {
index 0409ddd..adbb150 100644 (file)
@@ -42,8 +42,13 @@ struct _GstVdpH264Frame
   GstVideoFrame video_frame;
 
   GstH264Slice slice_hdr;
-  
   GPtrArray *slices;
+
+  guint poc;
+  guint16 frame_num;
+  gboolean is_reference;
+  gboolean is_long_term;
+  gboolean output_needed;
 };
 
 struct _GstVdpH264FrameClass