From e8df47b022790be433ec258f4b052650765d9586 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sun, 7 Feb 2021 02:26:02 +0900 Subject: [PATCH] d3d11h265dec: Add support for interlaced stream Note that we have no D3D11 deinterlace element yet. If downstream is not support format:Interlaced caps feature including all D3D11 the other elements, aspect-ratio will be adjusted as an alternative approach. Part-of: --- sys/d3d11/gstd3d11decoder.c | 91 +++++++++++++++++++++++++++++-------- sys/d3d11/gstd3d11h265dec.c | 69 +++++++++++++++++++++++++--- 2 files changed, 135 insertions(+), 25 deletions(-) diff --git a/sys/d3d11/gstd3d11decoder.c b/sys/d3d11/gstd3d11decoder.c index ffa9365c93..2251ce6d6b 100644 --- a/sys/d3d11/gstd3d11decoder.c +++ b/sys/d3d11/gstd3d11decoder.c @@ -1431,7 +1431,10 @@ gst_d3d11_decoder_negotiate (GstVideoDecoder * decoder, GstVideoCodecState ** output_state, gboolean * downstream_supports_d3d11) { GstCaps *peer_caps; - GstVideoCodecState *state; + GstVideoCodecState *state = NULL; + gboolean alternate_interlaced; + gboolean alternate_supported = FALSE; + gboolean d3d11_supported = FALSE; g_return_val_if_fail (GST_IS_VIDEO_DECODER (decoder), FALSE); g_return_val_if_fail (input_state != NULL, FALSE); @@ -1441,21 +1444,11 @@ gst_d3d11_decoder_negotiate (GstVideoDecoder * decoder, g_return_val_if_fail (output_state != NULL, FALSE); g_return_val_if_fail (downstream_supports_d3d11 != NULL, FALSE); - state = gst_video_decoder_set_output_state (decoder, - format, width, height, input_state); - if (interlace_mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE) - state->info.interlace_mode = interlace_mode; - state->caps = gst_video_info_to_caps (&state->info); - - if (*output_state) - gst_video_codec_state_unref (*output_state); - *output_state = state; + alternate_interlaced = (interlace_mode == GST_VIDEO_INTERLACE_MODE_ALTERNATE); peer_caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (decoder)); GST_DEBUG_OBJECT (decoder, "Allowed caps %" GST_PTR_FORMAT, peer_caps); - *downstream_supports_d3d11 = FALSE; - if (!peer_caps || gst_caps_is_any (peer_caps)) { GST_DEBUG_OBJECT (decoder, "cannot determine output format, use system memory"); @@ -1466,19 +1459,79 @@ gst_d3d11_decoder_negotiate (GstVideoDecoder * decoder, for (i = 0; i < size; i++) { features = gst_caps_get_features (peer_caps, i); - if (features && gst_caps_features_contains (features, - GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) { - GST_DEBUG_OBJECT (decoder, "found D3D11 memory feature"); - gst_caps_set_features (state->caps, 0, - gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL)); - *downstream_supports_d3d11 = TRUE; - break; + if (!features) + continue; + + if (gst_caps_features_contains (features, + GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) { + d3d11_supported = TRUE; + } + + /* FIXME: software deinterlace element will not return interlaced caps + * feature... We should fix it */ + if (gst_caps_features_contains (features, + GST_CAPS_FEATURE_FORMAT_INTERLACED)) { + alternate_supported = TRUE; } } } gst_clear_caps (&peer_caps); + GST_DEBUG_OBJECT (decoder, + "Downstream feature support, D3D11 memory: %d, interlaced format %d", + d3d11_supported, alternate_supported); + + if (alternate_interlaced) { + /* FIXME: D3D11 cannot support alternating interlaced stream yet */ + GST_FIXME_OBJECT (decoder, + "Implement alternating interlaced stream for D3D11"); + + if (alternate_supported) { + /* Set caps resolution with display size, that's how we designed + * for alternating interlaced stream */ + height = 2 * height; + state = gst_video_decoder_set_interlaced_output_state (decoder, + format, interlace_mode, width, height, input_state); + } else { + GST_WARNING_OBJECT (decoder, + "Downstream doesn't support alternating interlaced stream"); + + state = gst_video_decoder_set_output_state (decoder, + format, width, height, input_state); + + /* XXX: adjust PAR, this would produce output similar to that of + * "line doubling" (so called bob deinterlacing) processing. + * apart from missing anchor line (top-field or bottom-field) information. + * Potentially flickering could happen. So this might not be correct. + * But it would be better than negotiation error of half-height squeezed + * image */ + state->info.par_d *= 2; + state->info.fps_n *= 2; + } + } else { + state = gst_video_decoder_set_interlaced_output_state (decoder, + format, interlace_mode, width, height, input_state); + } + + if (!state) { + GST_ERROR_OBJECT (decoder, "Couldn't set output state"); + return FALSE; + } + + state->caps = gst_video_info_to_caps (&state->info); + + if (*output_state) + gst_video_codec_state_unref (*output_state); + *output_state = state; + + if (d3d11_supported) { + gst_caps_set_features (state->caps, 0, + gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL)); + } + + *downstream_supports_d3d11 = d3d11_supported; + return TRUE; } diff --git a/sys/d3d11/gstd3d11h265dec.c b/sys/d3d11/gstd3d11h265dec.c index 84b16fc3a9..48a136a3e8 100644 --- a/sys/d3d11/gstd3d11h265dec.c +++ b/sys/d3d11/gstd3d11h265dec.c @@ -64,6 +64,7 @@ typedef struct _GstD3D11H265Dec guint bitdepth; guint chroma_format_idc; GstVideoFormat out_format; + GstVideoInterlaceMode interlace_mode; /* Array of DXVA_Slice_HEVC_Short */ GArray *slice_list; @@ -309,9 +310,9 @@ gst_d3d11_h265_dec_negotiate (GstVideoDecoder * decoder) if (!gst_d3d11_decoder_negotiate (decoder, h265dec->input_state, self->out_format, self->width, self->height, - GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, - &self->output_state, &self->use_d3d11_output)) + self->interlace_mode, &self->output_state, &self->use_d3d11_output)) { return FALSE; + } return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder); } @@ -359,6 +360,7 @@ gst_d3d11_h265_dec_new_sequence (GstH265Decoder * decoder, static const GUID *main_10_guid = &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10; static const GUID *main_guid = &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN; + GstVideoInterlaceMode interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; GST_LOG_OBJECT (self, "new sequence"); @@ -387,6 +389,25 @@ gst_d3d11_h265_dec_new_sequence (GstH265Decoder * decoder, modified = TRUE; } + if (sps->vui_parameters_present_flag && sps->vui_params.field_seq_flag) { + interlace_mode = GST_VIDEO_INTERLACE_MODE_ALTERNATE; + } else { + /* 7.4.4 Profile, tier and level sementics */ + if (sps->profile_tier_level.progressive_source_flag && + !sps->profile_tier_level.interlaced_source_flag) { + interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + } else { + interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; + } + } + + if (self->interlace_mode != interlace_mode) { + GST_INFO_OBJECT (self, "Interlace mode change %d -> %d", + self->interlace_mode, interlace_mode); + self->interlace_mode = interlace_mode; + modified = TRUE; + } + if (self->chroma_format_idc != sps->chroma_format_idc) { GST_INFO_OBJECT (self, "chroma format changed"); self->chroma_format_idc = sps->chroma_format_idc; @@ -775,8 +796,9 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, GstBuffer *view_buffer; gboolean direct_rendering = FALSE; - GST_LOG_OBJECT (self, - "Outputting picture %p, poc %d", picture, picture->pic_order_cnt); + GST_LOG_OBJECT (self, "Outputting picture %p, poc %d, picture_struct %d, " + "buffer flags 0x%x", picture, picture->pic_order_cnt, picture->pic_struct, + picture->buffer_flags); view_buffer = (GstBuffer *) gst_h265_picture_get_user_data (picture); @@ -824,6 +846,7 @@ gst_d3d11_h265_dec_output_picture (GstH265Decoder * decoder, goto error; } + GST_BUFFER_FLAG_SET (frame->output_buffer, picture->buffer_flags); gst_h265_picture_unref (picture); return gst_video_decoder_finish_frame (GST_VIDEO_DECODER (self), frame); @@ -1384,6 +1407,9 @@ gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device, }; GstCaps *sink_caps = NULL; GstCaps *src_caps = NULL; + GstCaps *src_caps_copy; + GstCaps *tmp; + GstCapsFeatures *caps_features; guint max_width = 0; guint max_height = 0; guint resolution; @@ -1450,8 +1476,7 @@ gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device, sink_caps = gst_caps_from_string ("video/x-h265, " "stream-format=(string) { hev1, hvc1, byte-stream }, " "alignment= (string) au"); - src_caps = gst_caps_from_string ("video/x-raw(" - GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY "); video/x-raw"); + src_caps = gst_caps_new_empty_simple ("video/x-raw"); if (have_main10) { /* main10 profile covers main and main10 */ @@ -1499,6 +1524,38 @@ gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device, "width", GST_TYPE_INT_RANGE, 64, resolution, "height", GST_TYPE_INT_RANGE, 64, resolution, NULL); + /* Copy src caps to append other capsfeatures */ + src_caps_copy = gst_caps_copy (src_caps); + + /* System memory with alternate interlace-mode */ + tmp = gst_caps_copy (src_caps_copy); + caps_features = gst_caps_features_new (GST_CAPS_FEATURE_FORMAT_INTERLACED, + NULL); + gst_caps_set_features_simple (tmp, caps_features); + gst_caps_set_simple (tmp, "interlace-mode", G_TYPE_STRING, "alternate", NULL); + gst_caps_append (src_caps, tmp); + + /* D3D11 memory feature */ + tmp = gst_caps_copy (src_caps_copy); + caps_features = gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, + NULL); + gst_caps_set_features_simple (tmp, caps_features); + gst_caps_append (src_caps, tmp); + + /* FIXME: D3D11 deinterlace element is not prepared, so this D3D11 with + * interlaced caps feature is pointless at the moment */ +#if 0 + /* D3D11 memory with alternate interlace-mode */ + tmp = gst_caps_copy (src_caps_copy); + caps_features = gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, + GST_CAPS_FEATURE_FORMAT_INTERLACED, NULL); + gst_caps_set_features_simple (tmp, caps_features); + gst_caps_set_simple (tmp, "interlace-mode", G_TYPE_STRING, "alternate", NULL); + gst_caps_append (src_caps, tmp); +#endif + + gst_caps_unref (src_caps_copy); + type_info.class_data = gst_d3d11_decoder_class_data_new (device, sink_caps, src_caps);