From 5189e8b9563037bea176785ef828d57516b4f1cb Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Sat, 6 Jan 2024 13:07:16 +0100 Subject: [PATCH] v4l2codecs: decoders: Add DMA_DRM caps support In order to simplify caps negotiations for clients and, notably, be more compatible with va* decoders. Crucially this allows clients to know ahead of time whether buffers will actually be DMABufs. Similar to GstVaBaseDec we only announce system memory caps if the peer has ANY caps. Further more, and again like va decoders, we fail in `decide_allocation()` if DMA_DRM caps are used without VideoMeta. Apart from buggy peers this can happen e.g. when a peer with ANY caps is used in combination with caps filters. Part-of: --- .../sys/v4l2codecs/gstv4l2codecav1dec.c | 43 ++++++++++++-- .../sys/v4l2codecs/gstv4l2codech264dec.c | 42 ++++++++++++-- .../sys/v4l2codecs/gstv4l2codech265dec.c | 42 ++++++++++++-- .../sys/v4l2codecs/gstv4l2codecmpeg2dec.c | 41 +++++++++++-- .../sys/v4l2codecs/gstv4l2codecvp8dec.c | 41 +++++++++++-- .../sys/v4l2codecs/gstv4l2codecvp9dec.c | 42 ++++++++++++-- .../sys/v4l2codecs/gstv4l2decoder.c | 58 +++++++++++++++++-- .../sys/v4l2codecs/gstv4l2decoder.h | 4 +- 8 files changed, 271 insertions(+), 42 deletions(-) diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c index 27940d1af3..eb85addad5 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecav1dec.c @@ -53,9 +53,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, GST_STATIC_CAPS ("video/x-av1, alignment=frame")); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -68,6 +73,7 @@ struct _GstV4l2CodecAV1Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; GstV4l2CodecAllocator *sink_allocator; GstV4l2CodecAllocator *src_allocator; @@ -283,7 +289,9 @@ gst_v4l2_codec_av1_dec_negotiate (GstVideoDecoder * decoder) }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; + /* Ignore downstream renegotiation request. */ if (self->streaming) goto done; @@ -308,7 +316,13 @@ gst_v4l2_codec_av1_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -320,7 +334,8 @@ gst_v4l2_codec_av1_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"), ("No support for %ux%u", self->frame_width, self->frame_height)); @@ -335,7 +350,8 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->render_width, self->render_height, av1dec->input_state); + &self->vinfo_drm, self->render_width, self->render_height, + av1dec->input_state); if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) { if (self->streaming) @@ -368,6 +384,7 @@ gst_v4l2_codec_av1_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecAV1Dec *self = GST_V4L2_CODEC_AV1_DEC (decoder); + GstCaps *caps = NULL; guint min = 0, num_bitstream; /* If we are streaming here, then it means there is nothing allocation @@ -375,11 +392,24 @@ gst_v4l2_codec_av1_dec_decide_allocation (GstVideoDecoder * decoder, if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -1551,6 +1581,7 @@ gst_v4l2_codec_av1_dec_subinit (GstV4l2CodecAV1Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); self->tile_group_entries = g_array_new (FALSE, TRUE, sizeof (struct v4l2_ctrl_av1_tile_group_entry)); } diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c index de5dbdac71..39f63923c9 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech264dec.c @@ -51,9 +51,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, ); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -66,6 +71,7 @@ struct _GstV4l2CodecH264Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; gint display_width; gint display_height; gint coded_width; @@ -324,7 +330,8 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder) }, }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; /* Ignore downstream renegotiation request. */ if (self->streaming) @@ -350,7 +357,13 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -362,7 +375,8 @@ gst_v4l2_codec_h264_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported bitdepth/chroma format"), ("No support for %ux%u %ubit chroma IDC %i", self->coded_width, @@ -378,7 +392,8 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->display_width, self->display_height, h264dec->input_state); + &self->vinfo_drm, self->display_width, self->display_height, + h264dec->input_state); if (self->interlaced) self->output_state->info.interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; @@ -414,6 +429,7 @@ gst_v4l2_codec_h264_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecH264Dec *self = GST_V4L2_CODEC_H264_DEC (decoder); + GstCaps *caps = NULL; guint min = 0, num_bitstream; /* If we are streaming here, then it means there is nothing allocation @@ -421,11 +437,24 @@ gst_v4l2_codec_h264_dec_decide_allocation (GstVideoDecoder * decoder, if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -1484,6 +1513,7 @@ gst_v4l2_codec_h264_dec_subinit (GstV4l2CodecH264Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); self->slice_params = g_array_sized_new (FALSE, TRUE, sizeof (struct v4l2_ctrl_h264_slice_params), 4); g_array_set_size (self->slice_params, 4); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c index c32ca9757f..7be7aa311c 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codech265dec.c @@ -52,9 +52,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, ); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -67,6 +72,7 @@ struct _GstV4l2CodecH265Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; gint display_width; gint display_height; gint coded_width; @@ -358,7 +364,8 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder) }, }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; /* Ignore downstream renegotiation request. */ if (self->streaming) @@ -384,7 +391,13 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -396,7 +409,8 @@ gst_v4l2_codec_h265_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported bitdepth/chroma format"), ("No support for %ux%u %ubit chroma IDC %i", self->coded_width, @@ -412,7 +426,8 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->display_width, self->display_height, h265dec->input_state); + &self->vinfo_drm, self->display_width, self->display_height, + h265dec->input_state); if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) { if (self->streaming) @@ -445,16 +460,30 @@ gst_v4l2_codec_h265_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecH265Dec *self = GST_V4L2_CODEC_H265_DEC (decoder); + GstCaps *caps = NULL; guint min = 0; if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -1598,6 +1627,7 @@ gst_v4l2_codec_h265_dec_subinit (GstV4l2CodecH265Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); self->slice_params = g_array_sized_new (FALSE, TRUE, sizeof (struct v4l2_ctrl_hevc_slice_params), 4); g_array_set_size (self->slice_params, 4); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c index 749252a1ad..1f833eb662 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecmpeg2dec.c @@ -54,9 +54,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, "mpegversion=(int) 2, " "profile=(string) {main, simple} ")); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -70,6 +75,7 @@ struct _GstV4l2CodecMpeg2Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; guint16 width; guint16 height; @@ -246,7 +252,8 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder) }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; /* Ignore downstream renegotiation request. */ if (self->streaming) @@ -272,7 +279,13 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -284,7 +297,8 @@ gst_v4l2_codec_mpeg2_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported bitdepth/chroma format"), ("No support for %ux%u chroma IDC %i", self->width, @@ -300,7 +314,7 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->width, self->height, mpeg2dec->input_state); + &self->vinfo_drm, self->width, self->height, mpeg2dec->input_state); if (self->interlaced) self->output_state->info.interlace_mode = @@ -337,6 +351,7 @@ gst_v4l2_codec_mpeg2_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecMpeg2Dec *self = GST_V4L2_CODEC_MPEG2_DEC (decoder); + GstCaps *caps = NULL; guint min = 0, num_bitstream; /* If we are streaming here, then it means there is nothing allocation @@ -344,11 +359,24 @@ gst_v4l2_codec_mpeg2_dec_decide_allocation (GstVideoDecoder * decoder, if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -1009,6 +1037,7 @@ gst_v4l2_codec_mpeg2_dec_subinit (GstV4l2CodecMpeg2Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); } static void diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c index 6d6f49a8ae..02d88e9f1f 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp8dec.c @@ -55,9 +55,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, ); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -70,6 +75,7 @@ struct _GstV4l2CodecVp8Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; gint width; gint height; @@ -195,7 +201,8 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder) }, }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; /* Ignore downstream renegotiation request. */ if (self->streaming) @@ -221,7 +228,13 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -233,7 +246,8 @@ gst_v4l2_codec_vp8_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"), ("No support for %ux%u format %s", self->width, self->height, @@ -249,7 +263,7 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->width, self->height, vp8dec->input_state); + &self->vinfo_drm, self->width, self->height, vp8dec->input_state); if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) { if (self->streaming) @@ -282,17 +296,31 @@ gst_v4l2_codec_vp8_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecVp8Dec *self = GST_V4L2_CODEC_VP8_DEC (decoder); + GstCaps *caps = NULL; guint min = 0; guint num_bitstream; if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -869,6 +897,7 @@ gst_v4l2_codec_vp8_dec_subinit (GstV4l2CodecVp8Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); } static void diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c index 45ef5ac686..53be020b62 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2codecvp9dec.c @@ -56,9 +56,14 @@ GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, ); #define SRC_CAPS \ + GST_VIDEO_DMA_DRM_CAPS_MAKE " ; " \ + GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) + +#define SRC_CAPS_NO_DRM \ GST_VIDEO_CAPS_MAKE (GST_V4L2_DEFAULT_VIDEO_FORMATS) static GstStaticCaps static_src_caps = GST_STATIC_CAPS (SRC_CAPS); +static GstStaticCaps static_src_caps_no_drm = GST_STATIC_CAPS (SRC_CAPS_NO_DRM); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME, @@ -71,6 +76,7 @@ struct _GstV4l2CodecVp9Dec GstV4l2Decoder *decoder; GstVideoCodecState *output_state; GstVideoInfo vinfo; + GstVideoInfoDmaDrm vinfo_drm; gint width; gint height; @@ -467,7 +473,9 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder) }; /* *INDENT-ON* */ - GstCaps *filter, *caps; + GstCaps *peer_caps, *filter, *caps; + GstStaticCaps *static_filter; + /* Ignore downstream renegotiation request. */ if (self->streaming) goto done; @@ -491,7 +499,13 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder) return FALSE; } - filter = gst_v4l2_decoder_enum_src_formats (self->decoder, &static_src_caps); + /* If the peer has ANY caps only advertise system memory caps */ + peer_caps = gst_pad_peer_query_caps (decoder->srcpad, NULL); + static_filter = + gst_caps_is_any (peer_caps) ? &static_src_caps_no_drm : &static_src_caps; + gst_caps_unref (peer_caps); + + filter = gst_v4l2_decoder_enum_src_formats (self->decoder, static_filter); if (!filter) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("No supported decoder output formats"), (NULL)); @@ -503,7 +517,8 @@ gst_v4l2_codec_vp9_dec_negotiate (GstVideoDecoder * decoder) gst_caps_unref (filter); GST_DEBUG_OBJECT (self, "Peer supported formats: %" GST_PTR_FORMAT, caps); - if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo)) { + if (!gst_v4l2_decoder_select_src_format (self->decoder, caps, &self->vinfo, + &self->vinfo_drm)) { GST_ELEMENT_ERROR (self, CORE, NEGOTIATION, ("Unsupported pixel format"), ("No support for %ux%u format %s", self->width, self->height, @@ -519,7 +534,7 @@ done: self->output_state = gst_v4l2_decoder_set_output_state (GST_VIDEO_DECODER (self), &self->vinfo, - self->width, self->height, vp9dec->input_state); + &self->vinfo_drm, self->width, self->height, vp9dec->input_state); if (GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder)) { if (self->streaming) @@ -552,6 +567,7 @@ gst_v4l2_codec_vp9_dec_decide_allocation (GstVideoDecoder * decoder, GstQuery * query) { GstV4l2CodecVp9Dec *self = GST_V4L2_CODEC_VP9_DEC (decoder); + GstCaps *caps = NULL; guint min = 0; guint num_bitstream; @@ -560,11 +576,24 @@ gst_v4l2_codec_vp9_dec_decide_allocation (GstVideoDecoder * decoder, if (self->streaming) goto no_internal_changes; + g_clear_object (&self->src_pool); + g_clear_object (&self->src_allocator); + self->has_videometa = gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); - g_clear_object (&self->src_pool); - g_clear_object (&self->src_allocator); + gst_query_parse_allocation (query, &caps, NULL); + if (!caps) { + GST_ERROR_OBJECT (self, "No valid caps"); + return FALSE; + } + + if (gst_video_is_dma_drm_caps (caps) && !self->has_videometa) { + GST_ERROR_OBJECT (self, + "DMABuf caps negotiated without the mandatory support of VideoMeta"); + return FALSE; + } + gst_caps_unref (caps); if (gst_query_get_n_allocation_pools (query) > 0) gst_query_parse_nth_allocation_pool (query, 0, NULL, NULL, &min, NULL); @@ -1111,6 +1140,7 @@ gst_v4l2_codec_vp9_dec_subinit (GstV4l2CodecVp9Dec * self, { self->decoder = gst_v4l2_decoder_new (klass->device); gst_video_info_init (&self->vinfo); + gst_video_info_dma_drm_init (&self->vinfo_drm); } static void diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c index a9c7e2caa4..251ce48ee7 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.c @@ -410,6 +410,7 @@ gst_v4l2_decoder_probe_caps_for_format (GstV4l2Decoder * self, gint index = 0; GstCaps *caps, *tmp, *size_caps; GstVideoFormat format; + guint32 drm_fourcc; GST_DEBUG_OBJECT (self, "enumerate size for %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (pixelformat)); @@ -432,6 +433,31 @@ gst_v4l2_decoder_probe_caps_for_format (GstV4l2Decoder * self, gst_caps_unref (tmp); } + /* TODO: Add a V4L2 to DRM fourcc translator for formats that we don't support + * in software. + */ + drm_fourcc = gst_video_dma_drm_fourcc_from_format (format); + if (drm_fourcc /* != DRM_FORMAT_INVALID */ ) { + GstCaps *drm_caps; + + drm_caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, + "DMA_DRM", "drm-format", G_TYPE_STRING, + gst_video_dma_drm_fourcc_to_string (drm_fourcc, 0), NULL); + gst_caps_set_features_simple (drm_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF)); + + if (!gst_caps_is_empty (size_caps)) { + gst_caps_set_features_simple (size_caps, + gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF)); + tmp = drm_caps; + drm_caps = + gst_caps_intersect_full (tmp, size_caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (tmp); + } + + caps = gst_caps_merge (drm_caps, caps); + } + gst_caps_unref (size_caps); return caps; @@ -491,7 +517,7 @@ gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, - GstVideoInfo * vinfo) + GstVideoInfo * vinfo, GstVideoInfoDmaDrm * vinfo_drm) { gint ret; struct v4l2_format fmt = { @@ -500,6 +526,7 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, GstVideoFormat format; guint32 pix_fmt; GstVideoInfo tmp_vinfo; + GstVideoInfoDmaDrm tmp_vinfo_drm; if (gst_caps_is_empty (caps)) return FALSE; @@ -511,12 +538,15 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, } gst_video_info_init (&tmp_vinfo); + gst_video_info_dma_drm_init (&tmp_vinfo_drm); GST_DEBUG_OBJECT (self, "Original caps: %" GST_PTR_FORMAT, caps); caps = gst_caps_fixate (caps); GST_DEBUG_OBJECT (self, "Fixated caps: %" GST_PTR_FORMAT, caps); - if (gst_video_info_from_caps (&tmp_vinfo, caps)) { + if (gst_video_info_dma_drm_from_caps (&tmp_vinfo_drm, caps)) { + format = tmp_vinfo_drm.vinfo.finfo->format; + } else if (gst_video_info_from_caps (&tmp_vinfo, caps)) { format = tmp_vinfo.finfo->format; } else { GST_WARNING_OBJECT (self, "Can't transform caps into video info!"); @@ -547,6 +577,17 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, return FALSE; } + if (tmp_vinfo_drm.drm_fourcc) { + if (!gst_video_info_dma_drm_from_video_info (vinfo_drm, vinfo, 0)) { + GST_ERROR_OBJECT (self, + "Unsupported V4L2 pixelformat for DRM %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat)); + return FALSE; + } + } else { + gst_video_info_dma_drm_init (vinfo_drm); + } + GST_INFO_OBJECT (self, "Selected format %s %ix%i", gst_video_format_to_string (vinfo->finfo->format), vinfo->width, vinfo->height); @@ -556,15 +597,22 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, GstVideoCodecState * gst_v4l2_decoder_set_output_state (GstVideoDecoder * decoder, - GstVideoInfo * vinfo, guint width, guint height, - GstVideoCodecState * reference) + GstVideoInfo * vinfo, GstVideoInfoDmaDrm * vinfo_drm, guint width, + guint height, GstVideoCodecState * reference) { GstVideoCodecState *state; state = gst_video_decoder_set_output_state (decoder, vinfo->finfo->format, width, height, reference); - state->caps = gst_video_info_to_caps (&state->info); + if (vinfo_drm->drm_fourcc /* != DRM_FORMAT_INVALID */ ) { + GstVideoInfoDmaDrm tmp_vinfo_drm; + + gst_video_info_dma_drm_from_video_info (&tmp_vinfo_drm, &state->info, 0); + state->caps = gst_video_info_dma_drm_to_caps (&tmp_vinfo_drm); + } else { + state->caps = gst_video_info_to_caps (&state->info); + } GST_DEBUG_OBJECT (decoder, "Setting caps: %" GST_PTR_FORMAT, state->caps); diff --git a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h index 457985f4ab..c726c94b46 100644 --- a/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h +++ b/subprojects/gst-plugins-bad/sys/v4l2codecs/gstv4l2decoder.h @@ -72,10 +72,12 @@ GstCaps * gst_v4l2_decoder_enum_src_formats (GstV4l2Decoder * self, gboolean gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps, - GstVideoInfo * vinfo); + GstVideoInfo * vinfo, + GstVideoInfoDmaDrm * vinfo_drm); GstVideoCodecState * gst_v4l2_decoder_set_output_state (GstVideoDecoder * decoder, GstVideoInfo * vinfo, + GstVideoInfoDmaDrm * drm_info, guint width, guint height, GstVideoCodecState * reference);