mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
msdkenc: 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 enc 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:
parent
3f47cdaee8
commit
1f8d939559
2 changed files with 964 additions and 0 deletions
|
@ -31,6 +31,129 @@
|
|||
|
||||
#include "gstmsdkcaps.h"
|
||||
|
||||
#define DEFAULT_DELIMITER ", "
|
||||
#define PROFILE_DELIMITER DEFAULT_DELIMITER
|
||||
|
||||
#define DEFAULT_VIDEO_FORMAT GST_VIDEO_FORMAT_NV12
|
||||
|
||||
#define ENC_IOPATTERN MFX_IOPATTERN_IN_VIDEO_MEMORY
|
||||
|
||||
#ifdef _WIN32
|
||||
/* fix "unreferenced local variable" for windows */
|
||||
#define VAR_UNUSED(v) (void)(v)
|
||||
#endif
|
||||
|
||||
#if (MFX_VERSION >= 2000)
|
||||
static guint default_width = GST_ROUND_UP_16 (320);
|
||||
static guint default_height = GST_ROUND_UP_16 (240);
|
||||
|
||||
static guint max_res_widths[] = { 640, 1280, 1920, 2048, 4096, 8192, 16384 };
|
||||
|
||||
static guint max_res_heights[] = {
|
||||
480, 720, 1080, 1920, 2048, 4096, 8192, 12288, 16384
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mfxU32 id;
|
||||
const gchar *names;
|
||||
} Profile;
|
||||
|
||||
static const Profile profs_avc[] = {
|
||||
{MFX_PROFILE_AVC_MAIN, "main"},
|
||||
{MFX_PROFILE_AVC_BASELINE, "baseline"},
|
||||
{MFX_PROFILE_AVC_EXTENDED, "extended"},
|
||||
{MFX_PROFILE_AVC_HIGH, "high"},
|
||||
{MFX_PROFILE_AVC_CONSTRAINED_BASELINE, "constrained-baseline"},
|
||||
{MFX_PROFILE_AVC_CONSTRAINED_HIGH, "constrained-high"},
|
||||
{MFX_PROFILE_AVC_PROGRESSIVE_HIGH, "progressive-high"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_hevc[] = {
|
||||
{MFX_PROFILE_HEVC_MAIN, "main"},
|
||||
{MFX_PROFILE_HEVC_MAIN10, "main-10, main-10-still-picture"},
|
||||
{MFX_PROFILE_HEVC_MAINSP, "main-still-picture"},
|
||||
{MFX_PROFILE_HEVC_REXT, "main-444, main-444-10, main-422-10, main-12"},
|
||||
#if (MFX_VERSION >= 1032)
|
||||
{MFX_PROFILE_HEVC_SCC, "screen-extended-main, screen-extended-main-10, "
|
||||
"screen-extended-main-444, screen-extended-main-444-10"},
|
||||
#endif
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_mpeg2[] = {
|
||||
{MFX_PROFILE_MPEG2_MAIN, "main"},
|
||||
{MFX_PROFILE_MPEG2_SIMPLE, "simple"},
|
||||
{MFX_PROFILE_MPEG2_HIGH, "high"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_vc1[] = {
|
||||
{MFX_PROFILE_VC1_MAIN, "main"},
|
||||
{MFX_PROFILE_VC1_SIMPLE, "simple"},
|
||||
{MFX_PROFILE_VC1_ADVANCED, "advanced"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_vp8[] = {
|
||||
{MFX_PROFILE_VP8_0, "0"},
|
||||
{MFX_PROFILE_VP8_1, "1"},
|
||||
{MFX_PROFILE_VP8_2, "2"},
|
||||
{MFX_PROFILE_VP8_3, "3"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_vp9[] = {
|
||||
{MFX_PROFILE_VP9_0, "0"},
|
||||
{MFX_PROFILE_VP9_1, "1"},
|
||||
{MFX_PROFILE_VP9_2, "2"},
|
||||
{MFX_PROFILE_VP9_3, "3"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_av1[] = {
|
||||
#if (MFX_VERSION >= 1034)
|
||||
{MFX_PROFILE_AV1_MAIN, "main"},
|
||||
{MFX_PROFILE_AV1_HIGH, "high"},
|
||||
{MFX_PROFILE_AV1_PRO, "pro"},
|
||||
#endif
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const Profile profs_jpeg[] = {
|
||||
{MFX_PROFILE_JPEG_BASELINE, "baseline"},
|
||||
{MFX_PROFILE_UNKNOWN, NULL}
|
||||
};
|
||||
|
||||
static const struct CodecProfiles
|
||||
{
|
||||
guint codec;
|
||||
const gchar *media_type;
|
||||
const Profile *profiles;
|
||||
} codec_profs[] = {
|
||||
{MFX_CODEC_AVC, "video/x-h264", profs_avc},
|
||||
{MFX_CODEC_HEVC, "video/x-h265", profs_hevc},
|
||||
{MFX_CODEC_MPEG2, "video/mpeg", profs_mpeg2},
|
||||
{MFX_CODEC_VC1, "video/x-wmv", profs_vc1},
|
||||
{MFX_CODEC_VP8, "video/x-vp8", profs_vp8},
|
||||
{MFX_CODEC_VP9, "video/x-vp9", profs_vp9},
|
||||
{MFX_CODEC_AV1, "video/x-av1", profs_av1},
|
||||
{MFX_CODEC_JPEG, "image/jpeg", profs_jpeg}
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint min_width;
|
||||
guint max_width;
|
||||
guint min_height;
|
||||
guint max_height;
|
||||
} ResolutionRange;
|
||||
|
||||
typedef gboolean (*IsParamSupportedFunc) (mfxSession * session,
|
||||
mfxVideoParam * in, mfxVideoParam * out);
|
||||
|
||||
gboolean
|
||||
gst_msdkcaps_has_feature (const GstCaps * caps, const gchar * feature)
|
||||
{
|
||||
|
@ -47,3 +170,837 @@ gst_msdkcaps_has_feature (const GstCaps * caps, const gchar * feature)
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_list_append_string (GValue * list, const gchar * str)
|
||||
{
|
||||
GValue gval = G_VALUE_INIT;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
g_return_if_fail (str != NULL);
|
||||
|
||||
g_value_init (&gval, G_TYPE_STRING);
|
||||
g_value_set_string (&gval, str);
|
||||
|
||||
gst_value_list_append_value (list, &gval);
|
||||
g_value_unset (&gval);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
_get_media_type (guint codec)
|
||||
{
|
||||
for (int c = 0; c < G_N_ELEMENTS (codec_profs); c++) {
|
||||
if (codec_profs[c].codec == codec)
|
||||
return codec_profs[c].media_type;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if (MFX_VERSION >= 2000)
|
||||
|
||||
static gboolean
|
||||
_fill_mfxframeinfo (GstVideoFormat format, mfxFrameInfo * frameinfo)
|
||||
{
|
||||
if (format == GST_VIDEO_FORMAT_UNKNOWN)
|
||||
return FALSE;
|
||||
|
||||
frameinfo->ChromaFormat = gst_msdk_get_mfx_chroma_from_format (format);
|
||||
frameinfo->FourCC = gst_msdk_get_mfx_fourcc_from_format (format);
|
||||
|
||||
switch (format) {
|
||||
case GST_VIDEO_FORMAT_NV12:
|
||||
case GST_VIDEO_FORMAT_YV12:
|
||||
case GST_VIDEO_FORMAT_I420:
|
||||
case GST_VIDEO_FORMAT_YUY2:
|
||||
case GST_VIDEO_FORMAT_UYVY:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_VUYA:
|
||||
frameinfo->BitDepthLuma = 8;
|
||||
frameinfo->BitDepthChroma = 8;
|
||||
frameinfo->Shift = 0;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_BGR10A2_LE:
|
||||
frameinfo->BitDepthLuma = 10;
|
||||
frameinfo->BitDepthChroma = 10;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_P010_10LE:
|
||||
frameinfo->BitDepthLuma = 10;
|
||||
frameinfo->BitDepthChroma = 10;
|
||||
frameinfo->Shift = 1;
|
||||
break;
|
||||
#if (MFX_VERSION >= 1027)
|
||||
case GST_VIDEO_FORMAT_Y210:
|
||||
frameinfo->BitDepthLuma = 10;
|
||||
frameinfo->BitDepthChroma = 10;
|
||||
frameinfo->Shift = 1;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_Y410:
|
||||
frameinfo->BitDepthLuma = 10;
|
||||
frameinfo->BitDepthChroma = 10;
|
||||
frameinfo->Shift = 0;
|
||||
break;
|
||||
#endif
|
||||
#if (MFX_VERSION >= 1031)
|
||||
case GST_VIDEO_FORMAT_P012_LE:
|
||||
case GST_VIDEO_FORMAT_Y212_LE:
|
||||
case GST_VIDEO_FORMAT_Y412_LE:
|
||||
frameinfo->BitDepthLuma = 12;
|
||||
frameinfo->BitDepthChroma = 12;
|
||||
frameinfo->Shift = 1;
|
||||
break;
|
||||
#endif
|
||||
#if (MFX_VERSION >=2004)
|
||||
case GST_VIDEO_FORMAT_RGBP:
|
||||
case GST_VIDEO_FORMAT_BGRP:
|
||||
frameinfo->BitDepthLuma = 8;
|
||||
frameinfo->BitDepthChroma = 8;
|
||||
frameinfo->Shift = 0;
|
||||
break;
|
||||
#endif
|
||||
case GST_VIDEO_FORMAT_RGB16:
|
||||
/* Ignore parameters settings, do nothing */
|
||||
break;
|
||||
default:
|
||||
GST_WARNING ("Unsupported format %s",
|
||||
gst_video_format_to_string (format));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
_profile_to_string (guint codec, mfxU32 profile)
|
||||
{
|
||||
if (profile == MFX_PROFILE_UNKNOWN)
|
||||
return NULL;
|
||||
|
||||
for (int c = 0; c < G_N_ELEMENTS (codec_profs); c++) {
|
||||
if (codec_profs[c].codec == codec) {
|
||||
const Profile *p = codec_profs[c].profiles;
|
||||
for (; p->id != MFX_PROFILE_UNKNOWN; p++) {
|
||||
if (p->id == profile)
|
||||
return p->names;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static mfxU16
|
||||
_get_main_codec_profile (guint codec)
|
||||
{
|
||||
for (int c = 0; c < G_N_ELEMENTS (codec_profs); c++) {
|
||||
if (codec_profs[c].codec == codec) {
|
||||
return codec_profs[c].profiles->id;
|
||||
}
|
||||
}
|
||||
|
||||
return MFX_PROFILE_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
_codec_init_param (mfxVideoParam * param,
|
||||
guint codec_id, mfxU16 pattern, GstVideoFormat format)
|
||||
{
|
||||
g_return_if_fail (param != NULL);
|
||||
|
||||
memset (param, 0, sizeof (mfxVideoParam));
|
||||
param->IOPattern = pattern;
|
||||
param->mfx.CodecId = codec_id;
|
||||
param->mfx.CodecProfile = _get_main_codec_profile (codec_id);
|
||||
param->mfx.FrameInfo.Width = default_width;
|
||||
param->mfx.FrameInfo.Height = default_height;
|
||||
param->mfx.FrameInfo.CropW = param->mfx.FrameInfo.Width;
|
||||
param->mfx.FrameInfo.CropH = param->mfx.FrameInfo.Height;
|
||||
param->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
|
||||
param->mfx.FrameInfo.FrameRateExtN = 30;
|
||||
param->mfx.FrameInfo.FrameRateExtD = 1;
|
||||
param->mfx.FrameInfo.AspectRatioW = 1;
|
||||
param->mfx.FrameInfo.AspectRatioH = 1;
|
||||
|
||||
_fill_mfxframeinfo (format, ¶m->mfx.FrameInfo);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_min_width (mfxSession * session, mfxVideoParam * in,
|
||||
mfxVideoParam * out, IsParamSupportedFunc func,
|
||||
const mfxRange32U * width, guint * min_w)
|
||||
{
|
||||
g_return_val_if_fail (func != NULL, FALSE);
|
||||
|
||||
in->mfx.FrameInfo.Height = default_height;
|
||||
in->mfx.FrameInfo.CropH = default_height;
|
||||
out->mfx.FrameInfo.Height = in->mfx.FrameInfo.Height;
|
||||
out->mfx.FrameInfo.CropH = in->mfx.FrameInfo.CropH;
|
||||
|
||||
for (guint w = width->Min; w < *min_w;) {
|
||||
in->mfx.FrameInfo.Width = w;
|
||||
in->mfx.FrameInfo.CropW = w;
|
||||
out->mfx.FrameInfo.Width = in->mfx.FrameInfo.Width;
|
||||
out->mfx.FrameInfo.CropW = in->mfx.FrameInfo.CropW;
|
||||
|
||||
if (func (session, in, out)) {
|
||||
*min_w = in->mfx.FrameInfo.Width;
|
||||
return TRUE;
|
||||
} else {
|
||||
if (out->mfx.FrameInfo.Width != 0) {
|
||||
if (func (session, out, out)) {
|
||||
*min_w = out->mfx.FrameInfo.Width;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w += width->Step;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_min_height (mfxSession * session, mfxVideoParam * in,
|
||||
mfxVideoParam * out, IsParamSupportedFunc func,
|
||||
const mfxRange32U * height, guint * min_h)
|
||||
{
|
||||
g_return_val_if_fail (func != NULL, FALSE);
|
||||
|
||||
in->mfx.FrameInfo.Width = default_width;
|
||||
in->mfx.FrameInfo.CropW = default_width;
|
||||
out->mfx.FrameInfo.Width = in->mfx.FrameInfo.Width;
|
||||
out->mfx.FrameInfo.CropW = in->mfx.FrameInfo.CropW;
|
||||
|
||||
for (guint h = height->Min; h < *min_h;) {
|
||||
in->mfx.FrameInfo.Height = h;
|
||||
in->mfx.FrameInfo.CropH = h;
|
||||
out->mfx.FrameInfo.Height = h;
|
||||
out->mfx.FrameInfo.CropH = h;
|
||||
|
||||
if (func (session, in, out)) {
|
||||
*min_h = in->mfx.FrameInfo.Height;
|
||||
return TRUE;
|
||||
} else {
|
||||
if (out->mfx.FrameInfo.Height != 0) {
|
||||
if (func (session, out, out)) {
|
||||
*min_h = out->mfx.FrameInfo.Height;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h += height->Step;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static guint
|
||||
_get_smaller_res_width (guint cur_res_width)
|
||||
{
|
||||
guint i = G_N_ELEMENTS (max_res_widths) - 1;
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
if (max_res_widths[i] < cur_res_width)
|
||||
return max_res_widths[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_max_width (mfxSession * session, mfxVideoParam * in,
|
||||
mfxVideoParam * out, IsParamSupportedFunc func,
|
||||
const mfxRange32U * width, guint * max_w)
|
||||
{
|
||||
guint w;
|
||||
|
||||
g_return_val_if_fail (func != NULL, FALSE);
|
||||
|
||||
in->mfx.FrameInfo.Height = default_height;
|
||||
in->mfx.FrameInfo.CropH = default_height;
|
||||
out->mfx.FrameInfo.Height = in->mfx.FrameInfo.Height;
|
||||
out->mfx.FrameInfo.CropH = in->mfx.FrameInfo.CropH;
|
||||
|
||||
w = width->Max;
|
||||
do {
|
||||
in->mfx.FrameInfo.Width = w;
|
||||
in->mfx.FrameInfo.CropW = w;
|
||||
out->mfx.FrameInfo.Width = in->mfx.FrameInfo.Width;
|
||||
out->mfx.FrameInfo.CropW = in->mfx.FrameInfo.CropW;
|
||||
|
||||
if (func (session, in, out)) {
|
||||
*max_w = in->mfx.FrameInfo.Width;
|
||||
return TRUE;
|
||||
} else {
|
||||
if (out->mfx.FrameInfo.Width != 0) {
|
||||
if (func (session, out, out)) {
|
||||
*max_w = out->mfx.FrameInfo.Width;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w = _get_smaller_res_width (w);
|
||||
} while (w);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static guint
|
||||
_get_smaller_res_height (guint cur_res_height)
|
||||
{
|
||||
guint i = G_N_ELEMENTS (max_res_heights) - 1;
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
if (max_res_heights[i] < cur_res_height)
|
||||
return max_res_heights[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_get_max_height (mfxSession * session, mfxVideoParam * in,
|
||||
mfxVideoParam * out, IsParamSupportedFunc func,
|
||||
const mfxRange32U * height, guint * max_h)
|
||||
{
|
||||
guint h;
|
||||
|
||||
g_return_val_if_fail (func != NULL, FALSE);
|
||||
|
||||
in->mfx.FrameInfo.Width = default_width;
|
||||
in->mfx.FrameInfo.CropW = default_width;
|
||||
out->mfx.FrameInfo.Width = in->mfx.FrameInfo.Width;
|
||||
out->mfx.FrameInfo.CropW = in->mfx.FrameInfo.CropW;
|
||||
|
||||
h = height->Max;
|
||||
do {
|
||||
in->mfx.FrameInfo.Height = h;
|
||||
in->mfx.FrameInfo.CropH = h;
|
||||
out->mfx.FrameInfo.Height = in->mfx.FrameInfo.Height;
|
||||
out->mfx.FrameInfo.CropH = in->mfx.FrameInfo.CropH;
|
||||
|
||||
if (func (session, in, out)) {
|
||||
*max_h = in->mfx.FrameInfo.Height;
|
||||
return TRUE;
|
||||
} else {
|
||||
if (out->mfx.FrameInfo.Height != 0) {
|
||||
if (func (session, out, out)) {
|
||||
*max_h = out->mfx.FrameInfo.Height;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h = _get_smaller_res_height (h);
|
||||
} while (h);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_format_in_list (GstVideoFormat format, GValue * list)
|
||||
{
|
||||
const GValue *gfmt;
|
||||
const gchar *fmt_str = NULL;
|
||||
guint size = gst_value_list_get_size (list);
|
||||
|
||||
if (format == GST_VIDEO_FORMAT_UNKNOWN)
|
||||
return FALSE;
|
||||
|
||||
for (guint i = 0; i < size; i++) {
|
||||
gfmt = gst_value_list_get_value (list, i);
|
||||
fmt_str = g_value_get_string (gfmt);
|
||||
|
||||
if (format == gst_video_format_from_string (fmt_str))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_fourcc_in_array (mfxU32 fourcc, mfxU32 * array, mfxU16 num)
|
||||
{
|
||||
for (guint i = 0; i < num; i++) {
|
||||
if (array[i] == fourcc)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_enc_is_param_supported (mfxSession * session,
|
||||
mfxVideoParam * in, mfxVideoParam * out)
|
||||
{
|
||||
mfxStatus status = MFXVideoENCODE_Query (*session, in, out);
|
||||
if (status == MFX_ERR_NONE)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
_enc_ensure_codec (mfxEncoderDescription * enc_desc, guint c)
|
||||
{
|
||||
for (guint p = 0; p < enc_desc->Codecs[c].NumProfiles; p++) {
|
||||
if (enc_desc->Codecs[c].Profiles[p].MemDesc->NumColorFormats)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline gint
|
||||
_enc_get_codec_index (mfxEncoderDescription * enc_desc, guint codec_id)
|
||||
{
|
||||
gint c;
|
||||
|
||||
for (c = 0; c < enc_desc->NumCodecs; c++) {
|
||||
if (enc_desc->Codecs[c].CodecID == codec_id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (c >= enc_desc->NumCodecs)
|
||||
goto failed;
|
||||
|
||||
if (!_enc_ensure_codec (enc_desc, c))
|
||||
goto failed;
|
||||
|
||||
return c;
|
||||
|
||||
failed:
|
||||
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (codec_id));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_enc_get_resolution_range (mfxSession * session,
|
||||
mfxEncoderDescription * enc_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 = _enc_get_codec_index (enc_desc, codec_id);
|
||||
width = &enc_desc->Codecs[c].Profiles->MemDesc->Width;
|
||||
height = &enc_desc->Codecs[c].Profiles->MemDesc->Height;
|
||||
|
||||
_codec_init_param (&in, codec_id, ENC_IOPATTERN, DEFAULT_VIDEO_FORMAT);
|
||||
if (codec_id == MFX_CODEC_AV1)
|
||||
in.mfx.CodecLevel = MFX_LEVEL_AV1_41;
|
||||
out = in;
|
||||
|
||||
IsParamSupportedFunc func = _enc_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
|
||||
" ENC supported resolution range width: [%d, %d], height: [%d, %d]",
|
||||
GST_FOURCC_ARGS (enc_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
|
||||
_enc_is_format_supported (mfxSession * session,
|
||||
guint codec_id, GstVideoFormat format,
|
||||
mfxVideoParam * in, mfxVideoParam * out)
|
||||
{
|
||||
if (!_fill_mfxframeinfo (format, &in->mfx.FrameInfo))
|
||||
return FALSE;
|
||||
|
||||
if (!_enc_is_param_supported (session, in, out))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_enc_get_supported_formats_and_profiles (mfxSession * session,
|
||||
mfxEncoderDescription * enc_desc, guint codec_id,
|
||||
GValue * supported_fmts, GValue * supported_profs)
|
||||
{
|
||||
guint size;
|
||||
const GValue *gfmt;
|
||||
GValue fmts = G_VALUE_INIT;
|
||||
GstVideoFormat fmt = DEFAULT_VIDEO_FORMAT;
|
||||
mfxVideoParam in, out;
|
||||
gboolean prof_supported;
|
||||
const gchar *prof_str = NULL;
|
||||
gchar **profs = NULL;
|
||||
gint c = _enc_get_codec_index (enc_desc, codec_id);
|
||||
|
||||
_codec_init_param (&in, codec_id, ENC_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);
|
||||
|
||||
for (guint p = 0; p < enc_desc->Codecs[c].NumProfiles; p++) {
|
||||
in.mfx.CodecProfile = enc_desc->Codecs[c].Profiles[p].Profile;
|
||||
prof_supported = FALSE;
|
||||
|
||||
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),
|
||||
enc_desc->Codecs[c].Profiles[p].MemDesc->ColorFormats,
|
||||
enc_desc->Codecs[c].Profiles[p].MemDesc->NumColorFormats))
|
||||
continue;
|
||||
|
||||
if (!_enc_is_format_supported (session, codec_id, fmt, &in, &out))
|
||||
continue;
|
||||
|
||||
_list_append_string (supported_fmts, gst_video_format_to_string (fmt));
|
||||
prof_supported = TRUE;
|
||||
}
|
||||
|
||||
if (!prof_supported) {
|
||||
for (guint f = 0;
|
||||
f < enc_desc->Codecs[c].Profiles[p].MemDesc->NumColorFormats; f++) {
|
||||
fmt =
|
||||
gst_msdk_get_video_format_from_mfx_fourcc (enc_desc->
|
||||
Codecs[c].Profiles[p].MemDesc->ColorFormats[f]);
|
||||
if (_enc_is_format_supported (session, codec_id, fmt, &in, &out)) {
|
||||
prof_supported = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!prof_supported)
|
||||
continue;
|
||||
|
||||
prof_str = _profile_to_string (codec_id, in.mfx.CodecProfile);
|
||||
if (!prof_str)
|
||||
continue;
|
||||
|
||||
profs = g_strsplit (prof_str, PROFILE_DELIMITER, 0);
|
||||
for (guint i = 0; profs[i]; i++)
|
||||
_list_append_string (supported_profs, profs[i]);
|
||||
g_strfreev (profs);
|
||||
}
|
||||
|
||||
if (gst_value_list_get_size (supported_fmts) == 0 ||
|
||||
gst_value_list_get_size (supported_profs) == 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
_enc_create_sink_caps (GstMsdkContext * context, guint codec_id,
|
||||
const ResolutionRange * res, GValue * supported_formats)
|
||||
{
|
||||
GstCaps *caps, *dma_caps;
|
||||
|
||||
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 " ENC sink_caps %" GST_PTR_FORMAT,
|
||||
GST_FOURCC_ARGS (codec_id), caps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
_enc_create_src_caps (guint codec_id,
|
||||
const ResolutionRange * res, GValue * supported_profiles)
|
||||
{
|
||||
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_caps_set_value (caps, "profile", supported_profiles);
|
||||
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, NULL);
|
||||
|
||||
GST_DEBUG ("Create %" GST_FOURCC_FORMAT " ENC src_caps %" GST_PTR_FORMAT,
|
||||
GST_FOURCC_ARGS (codec_id), caps);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_msdkcaps_enc_create_caps (GstMsdkContext * context,
|
||||
gpointer enc_description, guint codec_id,
|
||||
GstCaps ** sink_caps, GstCaps ** src_caps)
|
||||
{
|
||||
mfxEncoderDescription *enc_desc;
|
||||
GstCaps *in_caps = NULL, *out_caps = NULL;
|
||||
ResolutionRange res_range = { 1, G_MAXUINT16, 1, G_MAXUINT16 };
|
||||
GValue supported_fmts = G_VALUE_INIT;
|
||||
GValue supported_profs = G_VALUE_INIT;
|
||||
mfxSession session;
|
||||
|
||||
g_return_val_if_fail (context, FALSE);
|
||||
g_return_val_if_fail (enc_description, FALSE);
|
||||
|
||||
session = gst_msdk_context_get_session (context);
|
||||
enc_desc = (mfxEncoderDescription *) enc_description;
|
||||
|
||||
if (_enc_get_codec_index (enc_desc, codec_id) < 0)
|
||||
goto failed;
|
||||
|
||||
g_value_init (&supported_fmts, GST_TYPE_LIST);
|
||||
g_value_init (&supported_profs, GST_TYPE_LIST);
|
||||
if (!_enc_get_supported_formats_and_profiles (&session,
|
||||
enc_desc, codec_id, &supported_fmts, &supported_profs))
|
||||
goto failed;
|
||||
|
||||
if (!_enc_get_resolution_range (&session, enc_desc, codec_id, &res_range))
|
||||
goto failed;
|
||||
|
||||
in_caps = _enc_create_sink_caps (context,
|
||||
codec_id, &res_range, &supported_fmts);
|
||||
g_value_unset (&supported_fmts);
|
||||
if (!in_caps)
|
||||
goto failed;
|
||||
|
||||
out_caps = _enc_create_src_caps (codec_id, &res_range, &supported_profs);
|
||||
g_value_unset (&supported_profs);
|
||||
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 " ENC",
|
||||
GST_FOURCC_ARGS (codec_id));
|
||||
|
||||
g_value_unset (&supported_fmts);
|
||||
g_value_unset (&supported_profs);
|
||||
if (in_caps)
|
||||
gst_caps_unref (in_caps);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static gboolean
|
||||
_get_profiles (guint codec_id, GValue * supported_profs)
|
||||
{
|
||||
const Profile *profiles = NULL;
|
||||
gchar **profs = NULL;
|
||||
|
||||
g_return_val_if_fail (supported_profs != NULL, FALSE);
|
||||
|
||||
for (guint c = 0; c < G_N_ELEMENTS (codec_profs); c++) {
|
||||
if (codec_profs[c].codec == codec_id) {
|
||||
profiles = codec_profs[c].profiles;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!profiles)
|
||||
return FALSE;
|
||||
|
||||
for (; profiles->id != MFX_PROFILE_UNKNOWN; profiles++) {
|
||||
profs = g_strsplit (profiles->names, PROFILE_DELIMITER, 0);
|
||||
for (guint p = 0; profs[p]; p++)
|
||||
_list_append_string (supported_profs, profs[p]);
|
||||
g_strfreev (profs);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_enc_get_raw_formats (guint codec_id)
|
||||
{
|
||||
switch (codec_id) {
|
||||
case MFX_CODEC_AVC:
|
||||
return "NV12, I420, YV12, YUY2, UYVY, BGRA";
|
||||
case MFX_CODEC_HEVC:
|
||||
return "NV12, I420, YV12, YUY2, UYVY, BGRA, BGR10A2_LE, "
|
||||
"P010_10LE, VUYA, Y410, Y210, P012_LE";
|
||||
case MFX_CODEC_MPEG2:
|
||||
return "NV12, I420, YV12, YUY2, UYVY, BGRA";
|
||||
case MFX_CODEC_VP9:
|
||||
return "NV12, I420, YV12, YUY2, UYVY, BGRA, P010_10LE, VUYA, Y410";
|
||||
case MFX_CODEC_AV1:
|
||||
return "NV12, P010_10LE";
|
||||
case MFX_CODEC_JPEG:
|
||||
return "NV12, I420, YV12, YUY2, UYVY, BGRA";
|
||||
default:
|
||||
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (codec_id));
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static const char *
|
||||
_enc_get_dma_formats (guint codec_id)
|
||||
{
|
||||
switch (codec_id) {
|
||||
case MFX_CODEC_AVC:
|
||||
return "NV12, BGRx";
|
||||
case MFX_CODEC_HEVC:
|
||||
return "NV12, P010_10LE";
|
||||
case MFX_CODEC_MPEG2:
|
||||
return "NV12, BGRx";
|
||||
case MFX_CODEC_VP9:
|
||||
return "NV12, P010_10LE";
|
||||
case MFX_CODEC_AV1:
|
||||
return "NV12, P010_10LE";
|
||||
case MFX_CODEC_JPEG:
|
||||
return "NV12, BGRx";
|
||||
default:
|
||||
GST_WARNING ("Unsupported codec %" GST_FOURCC_FORMAT,
|
||||
GST_FOURCC_ARGS (codec_id));
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
gst_msdkcaps_enc_create_caps (GstMsdkContext * context,
|
||||
gpointer enc_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;
|
||||
GValue supported_profs = G_VALUE_INIT;
|
||||
|
||||
raw_fmts = _enc_get_raw_formats (codec_id);
|
||||
if (!raw_fmts)
|
||||
goto failed;
|
||||
raw_caps_str = g_strdup_printf ("video/x-raw, format=(string){ %s }",
|
||||
raw_fmts);
|
||||
in_caps = gst_caps_from_string (raw_caps_str);
|
||||
g_free (raw_caps_str);
|
||||
|
||||
#ifndef _WIN32
|
||||
dma_fmts = _enc_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 (in_caps, dma_caps);
|
||||
|
||||
gst_caps_append (in_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 (in_caps,
|
||||
gst_caps_from_string
|
||||
("video/x-raw(memory:D3D11Memory), format=(string){ NV12 }"));
|
||||
#endif
|
||||
|
||||
gst_caps_set_simple (in_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);
|
||||
|
||||
media_type = _get_media_type (codec_id);
|
||||
if (!media_type)
|
||||
goto failed;
|
||||
|
||||
out_caps = gst_caps_new_empty_simple (media_type);
|
||||
|
||||
g_value_init (&supported_profs, GST_TYPE_LIST);
|
||||
if (!_get_profiles (codec_id, &supported_profs))
|
||||
goto failed;
|
||||
|
||||
gst_caps_set_value (out_caps, "profile", &supported_profs);
|
||||
g_value_unset (&supported_profs);
|
||||
|
||||
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, NULL);
|
||||
|
||||
*sink_caps = in_caps;
|
||||
*src_caps = out_caps;
|
||||
|
||||
return TRUE;
|
||||
|
||||
failed:
|
||||
GST_WARNING ("Failed to create caps for %" GST_FOURCC_FORMAT " ENC",
|
||||
GST_FOURCC_ARGS (codec_id));
|
||||
|
||||
g_value_unset (&supported_profs);
|
||||
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
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#define __GST_MSDKCAPS_H__
|
||||
|
||||
#include "msdk.h"
|
||||
#include "gstmsdkcontext.h"
|
||||
|
||||
#include <mfxjpeg.h>
|
||||
#include <mfxvp8.h>
|
||||
|
||||
|
@ -41,6 +43,11 @@ G_BEGIN_DECLS
|
|||
gboolean
|
||||
gst_msdkcaps_has_feature (const GstCaps * caps, const gchar * feature);
|
||||
|
||||
gboolean
|
||||
gst_msdkcaps_enc_create_caps (GstMsdkContext * context,
|
||||
gpointer enc_description, guint codec_id,
|
||||
GstCaps ** sink_caps, GstCaps ** src_caps);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MSDKCAPS_H__ */
|
||||
|
|
Loading…
Reference in a new issue