msdkdec: Add function to dynamically create sink caps and src caps

We need to create the sink caps and src caps dynamically for different
platforms. By default, the dec init function create static pad template
and the compatibility and flexibility of the platform are too poor.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4177>
This commit is contained in:
Yinhang Liu 2023-03-10 16:32:03 +08:00 committed by GStreamer Marge Bot
parent a4fc1c5031
commit aa59d9828f
2 changed files with 456 additions and 0 deletions

View file

@ -37,6 +37,7 @@
#define DEFAULT_VIDEO_FORMAT GST_VIDEO_FORMAT_NV12
#define ENC_IOPATTERN MFX_IOPATTERN_IN_VIDEO_MEMORY
#define DEC_IOPATTERN MFX_IOPATTERN_OUT_VIDEO_MEMORY
#ifdef _WIN32
/* fix "unreferenced local variable" for windows */
@ -856,6 +857,298 @@ failed:
return FALSE;
}
static inline gboolean
_dec_is_param_supported (mfxSession * session,
mfxVideoParam * in, mfxVideoParam * out)
{
mfxStatus status = MFXVideoDECODE_Query (*session, in, out);
if (status == MFX_ERR_NONE)
return TRUE;
return FALSE;
}
static inline gboolean
_dec_ensure_codec (mfxDecoderDescription * dec_desc, guint c)
{
for (guint p = 0; p < dec_desc->Codecs[c].NumProfiles; p++) {
if (dec_desc->Codecs[c].Profiles[p].MemDesc->NumColorFormats)
return TRUE;
}
return FALSE;
}
static inline gint
_dec_get_codec_index (mfxDecoderDescription * dec_desc, guint codec_id)
{
gint c;
for (c = 0; c < dec_desc->NumCodecs; c++) {
if (dec_desc->Codecs[c].CodecID == codec_id) {
break;
}
}
if (c >= dec_desc->NumCodecs)
goto failed;
if (!_dec_ensure_codec (dec_desc, c))
goto failed;
return c;
failed:
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (codec_id));
return -1;
}
static void
_jpegdec_set_color_format (mfxVideoParam * param, GstVideoFormat format)
{
param->mfx.JPEGChromaFormat = param->mfx.FrameInfo.ChromaFormat;
switch (format) {
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_YUY2:
param->mfx.JPEGColorFormat = MFX_JPEG_COLORFORMAT_YCbCr;
break;
case GST_VIDEO_FORMAT_BGRA:
param->mfx.JPEGColorFormat = MFX_JPEG_COLORFORMAT_RGB;
break;
default:
GST_WARNING ("Jpegdec unsupported format %s",
gst_video_format_to_string (format));
break;
}
}
static gboolean
_dec_get_resolution_range (mfxSession * session,
mfxDecoderDescription * dec_desc, guint codec_id,
ResolutionRange * res_range)
{
guint c;
mfxVideoParam in, out;
mfxRange32U *width, *height;
ResolutionRange res = { default_width, default_width,
default_height, default_height
};
g_return_val_if_fail (res_range != NULL, FALSE);
c = _dec_get_codec_index (dec_desc, codec_id);
width = &dec_desc->Codecs[c].Profiles->MemDesc->Width;
height = &dec_desc->Codecs[c].Profiles->MemDesc->Height;
_codec_init_param (&in, codec_id, DEC_IOPATTERN, DEFAULT_VIDEO_FORMAT);
if (codec_id == MFX_CODEC_AV1)
in.mfx.CodecLevel = MFX_LEVEL_AV1_41;
if (codec_id == MFX_CODEC_JPEG)
_jpegdec_set_color_format (&in, GST_VIDEO_FORMAT_NV12);
out = in;
IsParamSupportedFunc func = _dec_is_param_supported;
if (!_get_min_width (session, &in, &out, func, width, &res.min_width) ||
!_get_max_width (session, &in, &out, func, width, &res.max_width) ||
!_get_min_height (session, &in, &out, func, height, &res.min_height) ||
!_get_max_height (session, &in, &out, func, height, &res.max_height))
return FALSE;
GST_DEBUG ("Got %" GST_FOURCC_FORMAT
" DEC supported resolution range width: [%d, %d], height: [%d, %d]",
GST_FOURCC_ARGS (dec_desc->Codecs[c].CodecID),
res.min_width, res.max_width, res.min_height, res.max_height);
res_range->min_width = res.min_width;
res_range->max_width = res.max_width;
res_range->min_height = res.min_height;
res_range->max_height = res.max_height;
return TRUE;
}
static gboolean
_dec_is_format_supported (mfxSession * session,
guint codec_id, GstVideoFormat format,
mfxVideoParam * in, mfxVideoParam * out)
{
if (!_fill_mfxframeinfo (format, &in->mfx.FrameInfo))
return FALSE;
if (codec_id == MFX_CODEC_JPEG)
_jpegdec_set_color_format (in, format);
in->mfx.LowPower = MFX_CODINGOPTION_UNKNOWN;
if (!_dec_is_param_supported (session, in, out)) {
in->mfx.LowPower = (out->mfx.LowPower == MFX_CODINGOPTION_ON) ?
MFX_CODINGOPTION_OFF : MFX_CODINGOPTION_ON;
if (!_dec_is_param_supported (session, in, out))
return FALSE;
}
return TRUE;
}
static gboolean
_dec_get_supported_formats (mfxSession * session,
mfxDecoderDescription * dec_desc, guint codec_id, GValue * supported_fmts)
{
guint size;
const GValue *gfmt;
GValue fmts = G_VALUE_INIT;
GstVideoFormat fmt = DEFAULT_VIDEO_FORMAT;
mfxVideoParam in, out;
gint c;
_codec_init_param (&in, codec_id, DEC_IOPATTERN, DEFAULT_VIDEO_FORMAT);
if (codec_id == MFX_CODEC_AV1)
in.mfx.CodecLevel = MFX_LEVEL_AV1_41;
out = in;
g_value_init (&fmts, GST_TYPE_LIST);
gst_msdk_get_video_format_list (&fmts);
size = gst_value_list_get_size (&fmts);
c = _dec_get_codec_index (dec_desc, codec_id);
for (guint p = 0; p < dec_desc->Codecs[c].NumProfiles; p++) {
in.mfx.CodecProfile = dec_desc->Codecs[c].Profiles[p].Profile;
for (guint i = 0; i < size; i++) {
gfmt = gst_value_list_get_value (&fmts, i);
fmt = g_value_get_uint (gfmt);
if (_format_in_list (fmt, supported_fmts))
continue;
if (!_fourcc_in_array (gst_msdk_get_mfx_fourcc_from_format (fmt),
dec_desc->Codecs[c].Profiles[p].MemDesc->ColorFormats,
dec_desc->Codecs[c].Profiles[p].MemDesc->NumColorFormats))
continue;
if (!_dec_is_format_supported (session, codec_id, fmt, &in, &out))
continue;
_list_append_string (supported_fmts, gst_video_format_to_string (fmt));
}
}
g_value_unset (&fmts);
return (gst_value_list_get_size (supported_fmts) == 0) ? FALSE : TRUE;
}
static GstCaps *
_dec_create_sink_caps (guint codec_id)
{
GstCaps *caps;
const gchar *media_type = NULL;
media_type = _get_media_type (codec_id);
if (!media_type)
return NULL;
caps = gst_caps_new_empty_simple (media_type);
GST_DEBUG ("Create %" GST_FOURCC_FORMAT " DEC sink_caps %" GST_PTR_FORMAT,
GST_FOURCC_ARGS (codec_id), caps);
return caps;
}
static GstCaps *
_dec_create_src_caps (GstMsdkContext * context,
mfxSession * session, guint codec_id,
mfxDecoderDescription * dec_desc, GValue * supported_formats)
{
GstCaps *caps, *dma_caps;
ResolutionRange res = { 1, G_MAXUINT16, 1, G_MAXUINT16 };
if (!_dec_get_resolution_range (session, dec_desc, codec_id, &res))
return NULL;
caps = gst_caps_from_string ("video/x-raw");
gst_caps_set_value (caps, "format", supported_formats);
#ifndef _WIN32
dma_caps = gst_caps_from_string ("video/x-raw(memory:DMABuf)");
gst_caps_set_value (dma_caps, "format", supported_formats);
gst_caps_append (caps, dma_caps);
gst_caps_append (caps,
gst_caps_from_string
("video/x-raw(memory:VAMemory), format=(string){ NV12 }"));
#else
VAR_UNUSED (dma_caps);
gst_caps_append (caps,
gst_caps_from_string
("video/x-raw(memory:D3D11Memory), format=(string){ NV12 }"));
#endif
gst_caps_set_simple (caps,
"width", GST_TYPE_INT_RANGE, res.min_width, res.max_width,
"height", GST_TYPE_INT_RANGE, res.min_height, res.max_height,
"interlace-mode", G_TYPE_STRING, "progressive", NULL);
GST_DEBUG ("Create %" GST_FOURCC_FORMAT " DEC src_caps %" GST_PTR_FORMAT,
GST_FOURCC_ARGS (codec_id), caps);
return caps;
}
gboolean
gst_msdkcaps_dec_create_caps (GstMsdkContext * context,
gpointer dec_description, guint codec_id,
GstCaps ** sink_caps, GstCaps ** src_caps)
{
mfxDecoderDescription *dec_desc;
GstCaps *in_caps = NULL, *out_caps = NULL;
GValue supported_fmts = G_VALUE_INIT;
mfxSession session;
g_return_val_if_fail (context, FALSE);
g_return_val_if_fail (dec_description, FALSE);
session = gst_msdk_context_get_session (context);
dec_desc = (mfxDecoderDescription *) dec_description;
if (_dec_get_codec_index (dec_desc, codec_id) < 0)
goto failed;
g_value_init (&supported_fmts, GST_TYPE_LIST);
if (!_dec_get_supported_formats (&session,
dec_desc, codec_id, &supported_fmts))
goto failed;
in_caps = _dec_create_sink_caps (codec_id);
if (!in_caps)
goto failed;
out_caps = _dec_create_src_caps (context,
&session, codec_id, dec_desc, &supported_fmts);
g_value_unset (&supported_fmts);
if (!out_caps)
goto failed;
*sink_caps = in_caps;
*src_caps = out_caps;
return TRUE;
failed:
GST_WARNING ("Failed to create caps for %" GST_FOURCC_FORMAT " DEC",
GST_FOURCC_ARGS (codec_id));
g_value_unset (&supported_fmts);
if (in_caps)
gst_caps_unref (in_caps);
return FALSE;
}
#else
static gboolean
@ -1025,6 +1318,141 @@ failed:
return FALSE;
}
static const char *
_dec_get_raw_formats (guint codec_id)
{
switch (codec_id) {
case MFX_CODEC_AVC:
return "NV12, BGRA, BGRx";
case MFX_CODEC_HEVC:
return "NV12, P010_10LE, YUY2, Y210, VUYA, Y410, P012_LE, "
"Y212_LE, Y412_LE, BGRA, BGRx";
case MFX_CODEC_MPEG2:
return "NV12";
case MFX_CODEC_VP9:
return "NV12, P010_10LE, VUYA, Y410, P012_LE, Y412_LE";
case MFX_CODEC_AV1:
return "NV12, P010_10LE, VUYA, Y410";
case MFX_CODEC_JPEG:
return "NV12, YUY2";
case MFX_CODEC_VP8:
return "NV12";
case MFX_CODEC_VC1:
return "NV12";
default:
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (codec_id));
break;
}
return NULL;
}
#ifndef _WIN32
static const char *
_dec_get_dma_formats (guint codec_id)
{
switch (codec_id) {
case MFX_CODEC_AVC:
return "NV12, BGRA, BGRx";
case MFX_CODEC_HEVC:
return "NV12, P010_10LE, YUY2, Y210, VUYA, Y410, P012_LE, "
"Y212_LE, Y412_LE, BGRA, BGRx";
case MFX_CODEC_MPEG2:
return "NV12";
case MFX_CODEC_VP9:
return "NV12, P010_10LE, VUYA, Y410, P012_LE, Y412_LE";
case MFX_CODEC_AV1:
return "NV12, P010_10LE, VUYA, Y410";
case MFX_CODEC_JPEG:
return "NV12, YUY2";
case MFX_CODEC_VP8:
return "NV12";
case MFX_CODEC_VC1:
return "NV12";
default:
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (codec_id));
break;
}
return NULL;
}
#endif
gboolean
gst_msdkcaps_dec_create_caps (GstMsdkContext * context,
gpointer dec_description, guint codec_id,
GstCaps ** sink_caps, GstCaps ** src_caps)
{
GstCaps *in_caps = NULL, *out_caps = NULL;
GstCaps *dma_caps = NULL;
gchar *raw_caps_str, *dma_caps_str;
const gchar *media_type = NULL;
const char *raw_fmts = NULL;
const char *dma_fmts = NULL;
media_type = _get_media_type (codec_id);
if (!media_type)
goto failed;
in_caps = gst_caps_new_empty_simple (media_type);
raw_fmts = _dec_get_raw_formats (codec_id);
if (!raw_fmts)
goto failed;
raw_caps_str = g_strdup_printf ("video/x-raw, format=(string){ %s }",
raw_fmts);
out_caps = gst_caps_from_string (raw_caps_str);
g_free (raw_caps_str);
#ifndef _WIN32
dma_fmts = _dec_get_dma_formats (codec_id);
if (!dma_fmts)
goto failed;
dma_caps_str =
g_strdup_printf ("video/x-raw(memory:DMABuf), format=(string){ %s }",
dma_fmts);
dma_caps = gst_caps_from_string (dma_caps_str);
g_free (dma_caps_str);
gst_caps_append (out_caps, dma_caps);
gst_caps_append (out_caps,
gst_caps_from_string
("video/x-raw(memory:VAMemory), format=(string){ NV12 }"));
#else
VAR_UNUSED (dma_caps_str);
VAR_UNUSED (dma_fmts);
gst_caps_append (out_caps,
gst_caps_from_string
("video/x-raw(memory:D3D11Memory), format=(string){ NV12 }"));
#endif
gst_caps_set_simple (out_caps,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
"interlace-mode", G_TYPE_STRING, "progressive", NULL);
*sink_caps = in_caps;
*src_caps = out_caps;
return TRUE;
failed:
GST_WARNING ("Failed to create caps for %" GST_FOURCC_FORMAT " DEC",
GST_FOURCC_ARGS (codec_id));
if (in_caps)
gst_caps_unref (in_caps);
if (out_caps)
gst_caps_unref (out_caps);
if (dma_caps)
gst_caps_unref (dma_caps);
return FALSE;
}
#endif
static void
@ -1096,3 +1524,23 @@ gst_msdkcaps_set_strings (GstCaps * caps,
return TRUE;
}
gboolean
gst_msdkcaps_remove_structure (GstCaps * caps, const gchar * features)
{
guint size;
GstCapsFeatures *f;
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
g_return_val_if_fail (features != NULL, FALSE);
size = gst_caps_get_size (caps);
f = gst_caps_features_from_string (features);
for (guint i = 0; i < size; i++) {
if (gst_caps_features_is_equal (f, gst_caps_get_features (caps, i)))
gst_caps_remove_structure (caps, i);
}
return TRUE;
}

View file

@ -48,6 +48,11 @@ gst_msdkcaps_enc_create_caps (GstMsdkContext * context,
gpointer enc_description, guint codec_id,
GstCaps ** sink_caps, GstCaps ** src_caps);
gboolean
gst_msdkcaps_dec_create_caps (GstMsdkContext * context,
gpointer dec_description, guint codec_id,
GstCaps ** sink_caps, GstCaps ** src_caps);
void
gst_msdkcaps_pad_template_init (GstElementClass * klass,
GstCaps * sink_caps, GstCaps * src_caps,
@ -57,6 +62,9 @@ gboolean
gst_msdkcaps_set_strings (GstCaps * caps,
const gchar * features, const char * field, const gchar * strings);
gboolean
gst_msdkcaps_remove_structure (GstCaps * caps, const gchar * features);
G_END_DECLS
#endif /* __GST_MSDKCAPS_H__ */