GstVideoCodecState *output_state;
- const GstH264SPS *last_sps;
- const GstH264PPS *last_pps;
-
GstCudaContext *context;
GstNvDecoder *decoder;
CUVIDPICPARAMS params;
guint bitdepth;
guint chroma_format_idc;
gint max_dpb_size;
+
+ gboolean interlaced;
+
+ GArray *ref_list;
};
struct _GstNvH264DecClass
#define gst_nv_h264_dec_parent_class parent_class
G_DEFINE_TYPE (GstNvH264Dec, gst_nv_h264_dec, GST_TYPE_H264_DECODER);
+static void gst_nv_h264_decoder_dispose (GObject * object);
static void gst_nv_h264_decoder_finalize (GObject * object);
static void gst_nv_h264_dec_set_context (GstElement * element,
GstContext * context);
const GstH264SPS * sps, gint max_dpb_size);
static gboolean gst_nv_h264_dec_new_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture);
+static gboolean gst_nv_h264_dec_new_field_picture (GstH264Decoder *
+ decoder, const GstH264Picture * first_field, GstH264Picture * second_field);
static GstFlowReturn gst_nv_h264_dec_output_picture (GstH264Decoder *
decoder, GstVideoCodecFrame * frame, GstH264Picture * picture);
static gboolean gst_nv_h264_dec_start_picture (GstH264Decoder * decoder,
* Since: 1.18
*/
+ object_class->dispose = gst_nv_h264_decoder_dispose;
object_class->finalize = gst_nv_h264_decoder_finalize;
element_class->set_context = GST_DEBUG_FUNCPTR (gst_nv_h264_dec_set_context);
GST_DEBUG_FUNCPTR (gst_nv_h264_dec_new_sequence);
h264decoder_class->new_picture =
GST_DEBUG_FUNCPTR (gst_nv_h264_dec_new_picture);
+ h264decoder_class->new_field_picture =
+ GST_DEBUG_FUNCPTR (gst_nv_h264_dec_new_field_picture);
h264decoder_class->output_picture =
GST_DEBUG_FUNCPTR (gst_nv_h264_dec_output_picture);
h264decoder_class->start_picture =
static void
gst_nv_h264_dec_init (GstNvH264Dec * self)
{
+ self->ref_list = g_array_sized_new (FALSE, TRUE,
+ sizeof (GstH264Picture *), 16);
+ g_array_set_clear_func (self->ref_list,
+ (GDestroyNotify) gst_h264_picture_clear);
+}
+
+static void
+gst_nv_h264_decoder_dispose (GObject * object)
+{
+ GstNvH264Dec *self = GST_NV_H264_DEC (object);
+
+ g_clear_pointer (&self->ref_list, g_array_unref);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
self->bitdepth = 0;
self->chroma_format_idc = 0;
self->max_dpb_size = 0;
+ self->interlaced = FALSE;
}
static gboolean
GstNvH264Dec *self = GST_NV_H264_DEC (decoder);
gint crop_width, crop_height;
gboolean modified = FALSE;
+ gboolean interlaced;
GST_LOG_OBJECT (self, "new sequence");
modified = TRUE;
}
+ interlaced = !sps->frame_mbs_only_flag;
+ if (self->interlaced != interlaced) {
+ GST_INFO_OBJECT (self, "interlaced sequence changed");
+ self->interlaced = interlaced;
+ modified = TRUE;
+ }
+
if (self->max_dpb_size < max_dpb_size) {
GST_INFO_OBJECT (self, "Requires larger DPB size (%d -> %d)",
self->max_dpb_size, max_dpb_size);
}
gst_video_info_set_format (&info, out_format, self->width, self->height);
+ if (self->interlaced)
+ GST_VIDEO_INFO_INTERLACE_MODE (&info) = GST_VIDEO_INTERLACE_MODE_MIXED;
self->max_dpb_size = max_dpb_size;
/* FIXME: add support cudaVideoCodec_H264_SVC and cudaVideoCodec_H264_MVC */
return FALSE;
}
- self->last_sps = NULL;
- self->last_pps = NULL;
memset (&self->params, 0, sizeof (CUVIDPICPARAMS));
}
return TRUE;
}
+static gboolean
+gst_nv_h264_dec_new_field_picture (GstH264Decoder * decoder,
+ const GstH264Picture * first_field, GstH264Picture * second_field)
+{
+ GstNvDecoderFrame *nv_frame;
+
+ nv_frame = (GstNvDecoderFrame *)
+ gst_h264_picture_get_user_data ((GstH264Picture *) first_field);
+ if (!nv_frame) {
+ GST_ERROR_OBJECT (decoder,
+ "No decoder frame in the first picture %p", first_field);
+ return FALSE;
+ }
+
+ gst_h264_picture_set_user_data (second_field,
+ gst_nv_decoder_frame_ref (nv_frame),
+ (GDestroyNotify) gst_nv_decoder_frame_unref);
+
+ return TRUE;
+}
+
static GstFlowReturn
gst_nv_h264_dec_output_picture (GstH264Decoder * decoder,
GstVideoCodecFrame * frame, GstH264Picture * picture)
goto error;
}
+ if (picture->buffer_flags != 0) {
+ gboolean interlaced =
+ (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_INTERLACED) != 0;
+ gboolean tff = (picture->buffer_flags & GST_VIDEO_BUFFER_FLAG_TFF) != 0;
+
+ GST_TRACE_OBJECT (self,
+ "apply buffer flags 0x%x (interlaced %d, top-field-first %d)",
+ picture->buffer_flags, interlaced, tff);
+ GST_BUFFER_FLAG_SET (frame->output_buffer, picture->buffer_flags);
+ }
+
gst_h264_picture_unref (picture);
return gst_video_decoder_finish_frame (vdec, frame);
error:
- gst_video_decoder_drop_frame (vdec, frame);
gst_h264_picture_unref (picture);
+ gst_video_decoder_release_frame (vdec, frame);
return GST_FLOW_ERROR;
}
const GstH264SPS * sps, gboolean field_pic, CUVIDH264PICPARAMS * params)
{
params->residual_colour_transform_flag = sps->separate_colour_plane_flag;
- params->MbaffFrameFlag = sps->mb_adaptive_frame_field_flag && field_pic;
+ params->MbaffFrameFlag = sps->mb_adaptive_frame_field_flag && !field_pic;
#define COPY_FIELD(f) \
(params)->f = (sps)->f
self->params.pSliceDataOffsets = NULL;
}
+static void
+gst_nv_h264_dec_fill_dpb (GstNvH264Dec * self, GstH264Picture * ref,
+ CUVIDH264DPBENTRY * dpb)
+{
+ GstNvDecoderFrame *frame;
+
+ dpb->not_existing = ref->nonexisting;
+ dpb->PicIdx = -1;
+
+ frame = gst_nv_h264_dec_get_decoder_frame_from_picture (self, ref);
+ if (!frame) {
+ dpb->not_existing = 1;
+ } else if (!dpb->not_existing) {
+ dpb->PicIdx = frame->index;
+ }
+
+ if (dpb->not_existing)
+ return;
+
+ if (GST_H264_PICTURE_IS_LONG_TERM_REF (ref)) {
+ dpb->FrameIdx = ref->long_term_frame_idx;
+ dpb->is_long_term = 1;
+ } else {
+ dpb->FrameIdx = ref->frame_num;
+ dpb->is_long_term = 0;
+ }
+
+ switch (ref->field) {
+ case GST_H264_PICTURE_FIELD_FRAME:
+ dpb->FieldOrderCnt[0] = ref->top_field_order_cnt;
+ dpb->FieldOrderCnt[1] = ref->bottom_field_order_cnt;
+ dpb->used_for_reference = 0x3;
+ break;
+ case GST_H264_PICTURE_FIELD_TOP_FIELD:
+ dpb->FieldOrderCnt[0] = ref->top_field_order_cnt;
+ dpb->used_for_reference = 0x1;
+ if (ref->other_field) {
+ dpb->FieldOrderCnt[1] = ref->other_field->bottom_field_order_cnt;
+ dpb->used_for_reference |= 0x2;
+ } else {
+ dpb->FieldOrderCnt[1] = 0;
+ }
+ break;
+ case GST_H264_PICTURE_FIELD_BOTTOM_FIELD:
+ dpb->FieldOrderCnt[1] = ref->bottom_field_order_cnt;
+ dpb->used_for_reference = 0x2;
+ if (ref->other_field) {
+ dpb->FieldOrderCnt[0] = ref->other_field->bottom_field_order_cnt;
+ dpb->used_for_reference |= 0x1;
+ } else {
+ dpb->FieldOrderCnt[0] = 0;
+ }
+ break;
+ default:
+ dpb->FieldOrderCnt[0] = 0;
+ dpb->FieldOrderCnt[1] = 0;
+ dpb->used_for_reference = 0;
+ break;
+ }
+}
+
static gboolean
gst_nv_h264_dec_start_picture (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb)
const GstH264SPS *sps;
const GstH264PPS *pps;
GstNvDecoderFrame *frame;
- GArray *dpb_array;
- gint i;
+ GArray *ref_list = self->ref_list;
+ guint i, ref_frame_idx;
g_return_val_if_fail (slice_header->pps != NULL, FALSE);
g_return_val_if_fail (slice_header->pps->sequence != NULL, FALSE);
/* FIXME: update sps/pps related params only when it's required */
params->PicWidthInMbs = sps->pic_width_in_mbs_minus1 + 1;
- params->FrameHeightInMbs = sps->pic_height_in_map_units_minus1 + 1;
+ if (!sps->frame_mbs_only_flag) {
+ params->FrameHeightInMbs = (sps->pic_height_in_map_units_minus1 + 1) << 1;
+ } else {
+ params->FrameHeightInMbs = sps->pic_height_in_map_units_minus1 + 1;
+ }
params->CurrPicIdx = frame->index;
- /* TODO: verifiy interlaced */
- params->field_pic_flag = picture->field != GST_H264_PICTURE_FIELD_FRAME;
+ params->field_pic_flag = slice_header->field_pic_flag;
params->bottom_field_flag =
picture->field == GST_H264_PICTURE_FIELD_BOTTOM_FIELD;
- /* TODO: set second_field here */
- params->second_field = 0;
+ params->second_field = picture->second_field;
+
+ if (picture->field == GST_H264_PICTURE_FIELD_TOP_FIELD) {
+ h264_params->CurrFieldOrderCnt[0] = picture->top_field_order_cnt;
+ h264_params->CurrFieldOrderCnt[1] = 0;
+ } else if (picture->field == GST_H264_PICTURE_FIELD_BOTTOM_FIELD) {
+ h264_params->CurrFieldOrderCnt[0] = 0;
+ h264_params->CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
+ } else {
+ h264_params->CurrFieldOrderCnt[0] = picture->top_field_order_cnt;
+ h264_params->CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
+ }
/* nBitstreamDataLen, pBitstreamData, nNumSlices and pSliceDataOffsets
* will be set later */
h264_params->frame_num = picture->frame_num;
h264_params->ref_pic_flag = GST_H264_PICTURE_IS_REF (picture);
- /* FIXME: should be updated depending on field type? */
- h264_params->CurrFieldOrderCnt[0] = picture->top_field_order_cnt;
- h264_params->CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
-
- if (!self->last_sps || self->last_sps != sps) {
- GST_DEBUG_OBJECT (self, "Update params from SPS and PPS");
- gst_nv_h264_dec_picture_params_from_sps (self,
- sps, slice_header->field_pic_flag, h264_params);
- gst_nv_h264_dec_picture_params_from_pps (self, pps, h264_params);
- self->last_sps = sps;
- self->last_pps = pps;
- } else if (!self->last_pps || self->last_pps != pps) {
- GST_DEBUG_OBJECT (self, "Update params from PPS");
- gst_nv_h264_dec_picture_params_from_pps (self, pps, h264_params);
- self->last_pps = pps;
- } else {
- GST_TRACE_OBJECT (self, "SPS and PPS were not updated");
- }
-
- memset (&h264_params->dpb, 0, sizeof (h264_params->dpb));
- for (i = 0; i < G_N_ELEMENTS (h264_params->dpb); i++)
- h264_params->dpb[i].PicIdx = -1;
-
- dpb_array = gst_h264_dpb_get_pictures_all (dpb);
- for (i = 0; i < dpb_array->len && i < G_N_ELEMENTS (h264_params->dpb); i++) {
- GstH264Picture *other = g_array_index (dpb_array, GstH264Picture *, i);
- GstNvDecoderFrame *other_frame;
- gint picture_index = -1;
- CUVIDH264DPBENTRY *dpb = &h264_params->dpb[i];
-
- if (!other->ref)
- continue;
- other_frame = gst_nv_h264_dec_get_decoder_frame_from_picture (self, other);
+ gst_nv_h264_dec_picture_params_from_sps (self,
+ sps, slice_header->field_pic_flag, h264_params);
+ gst_nv_h264_dec_picture_params_from_pps (self, pps, h264_params);
- if (other_frame)
- picture_index = other_frame->index;
+ ref_frame_idx = 0;
+ g_array_set_size (ref_list, 0);
- dpb->PicIdx = picture_index;
- if (GST_H264_PICTURE_IS_LONG_TERM_REF (other)) {
- dpb->FrameIdx = other->long_term_frame_idx;
- dpb->is_long_term = 1;
- } else {
- dpb->FrameIdx = other->frame_num;
- dpb->is_long_term = 0;
- }
-
- dpb->not_existing = other->nonexisting;
- if (dpb->not_existing && dpb->PicIdx != -1) {
- GST_WARNING_OBJECT (self,
- "Non-existing frame has valid picture index %d", dpb->PicIdx);
- dpb->PicIdx = -1;
- }
-
- /* FIXME: 1=top_field, 2=bottom_field, 3=both_fields */
- dpb->used_for_reference = 3;
+ memset (&h264_params->dpb, 0, sizeof (h264_params->dpb));
+ gst_h264_dpb_get_pictures_short_term_ref (dpb, FALSE, FALSE, ref_list);
+ for (i = 0; ref_frame_idx < 16 && i < ref_list->len; i++) {
+ GstH264Picture *other = g_array_index (ref_list, GstH264Picture *, i);
+ gst_nv_h264_dec_fill_dpb (self, other, &h264_params->dpb[ref_frame_idx]);
+ ref_frame_idx++;
+ }
+ g_array_set_size (ref_list, 0);
- dpb->FieldOrderCnt[0] = other->top_field_order_cnt;
- dpb->FieldOrderCnt[1] = other->bottom_field_order_cnt;
+ gst_h264_dpb_get_pictures_long_term_ref (dpb, FALSE, ref_list);
+ for (i = 0; ref_frame_idx < 16 && i < ref_list->len; i++) {
+ GstH264Picture *other = g_array_index (ref_list, GstH264Picture *, i);
+ gst_nv_h264_dec_fill_dpb (self, other, &h264_params->dpb[ref_frame_idx]);
+ ref_frame_idx++;
}
+ g_array_set_size (ref_list, 0);
- g_array_unref (dpb_array);
+ for (i = ref_frame_idx; i < 16; i++)
+ h264_params->dpb[i].PicIdx = -1;
return TRUE;
}