mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 00:06:36 +00:00
bf7f4eef20
Note that we need mappings for all drm_fourcc, otherwise we will get GST_VIDEO_FORMAT_UNKNOWN for some formats... Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5991>
2125 lines
57 KiB
C
2125 lines
57 KiB
C
/* GStreamer Intel MSDK plugin
|
|
* Copyright (c) 2023, Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "gstmsdkcaps.h"
|
|
|
|
#ifndef _WIN32
|
|
#include <libdrm/drm_fourcc.h>
|
|
#include <gst/video/video-info-dma.h>
|
|
#include "gstmsdkallocator_libva.h"
|
|
#include <gst/va/gstvavideoformat.h>
|
|
#endif
|
|
|
|
#define DEFAULT_DELIMITER ", "
|
|
#define PROFILE_DELIMITER DEFAULT_DELIMITER
|
|
|
|
#define DEFAULT_VIDEO_FORMAT GST_VIDEO_FORMAT_NV12
|
|
|
|
#define ENC_IOPATTERN MFX_IOPATTERN_IN_VIDEO_MEMORY
|
|
#define DEC_IOPATTERN MFX_IOPATTERN_OUT_VIDEO_MEMORY
|
|
#define VPP_IOPATTERN \
|
|
MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_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)
|
|
{
|
|
guint i;
|
|
|
|
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
|
GstCapsFeatures *const features = gst_caps_get_features (caps, i);
|
|
/* Skip ANY features, we need an exact match for correct evaluation */
|
|
if (gst_caps_features_is_any (features))
|
|
continue;
|
|
if (gst_caps_features_contains (features, feature))
|
|
return TRUE;
|
|
}
|
|
|
|
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 gboolean
|
|
_strings_to_list (const gchar * strings, GValue * list)
|
|
{
|
|
gchar **strs = NULL;
|
|
|
|
if (!strings || !list)
|
|
return FALSE;
|
|
|
|
strs = g_strsplit (strings, DEFAULT_DELIMITER, 0);
|
|
for (guint i = 0; strs[i]; i++)
|
|
_list_append_string (list, strs[i]);
|
|
g_strfreev (strs);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
/* For RGB cases, the byte orders are different between vaImageFormat (LSB) and
|
|
* GStreamer video format (MSB). This function corrects the mapping between
|
|
* different order manners.
|
|
*/
|
|
static void
|
|
_fix_map (GstMsdkContext * context)
|
|
{
|
|
GstVaDisplay *display = NULL;
|
|
VAImageFormat *va_formats;
|
|
VADisplay dpy;
|
|
VAStatus status;
|
|
int max, num = 0;
|
|
|
|
display = (GstVaDisplay *) gst_msdk_context_get_va_display (context);
|
|
dpy = gst_va_display_get_va_dpy (display);
|
|
gst_object_unref (display);
|
|
|
|
max = vaMaxNumImageFormats (dpy);
|
|
if (max == 0)
|
|
return;
|
|
|
|
va_formats = g_new (VAImageFormat, max);
|
|
status = vaQueryImageFormats (dpy, va_formats, &num);
|
|
gst_va_video_format_fix_map (va_formats, num);
|
|
|
|
if (status != VA_STATUS_SUCCESS)
|
|
GST_WARNING ("vaQueryImageFormats: %s", vaErrorStr (status));
|
|
|
|
g_free (va_formats);
|
|
return;
|
|
}
|
|
|
|
static gboolean
|
|
_dma_fmt_to_dma_drm_fmts (GstMsdkContext * context,
|
|
GstMsdkContextJobType job_type,
|
|
const GValue * dma_fmts, GValue * dma_drm_fmts)
|
|
{
|
|
const gchar *fmt_str;
|
|
gchar *drm_fmt_str;
|
|
guint32 drm_fourcc;
|
|
guint64 modifier;
|
|
GstVideoFormat fmt;
|
|
GValue gval = G_VALUE_INIT;
|
|
GValue mods = G_VALUE_INIT;
|
|
|
|
g_return_val_if_fail (dma_fmts != NULL, FALSE);
|
|
g_return_val_if_fail (context != NULL, FALSE);
|
|
|
|
fmt_str = g_value_get_string (dma_fmts);
|
|
fmt = gst_video_format_from_string (fmt_str);
|
|
|
|
g_return_val_if_fail (fmt != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
|
|
|
|
_fix_map (context);
|
|
|
|
drm_fourcc = gst_va_drm_fourcc_from_video_format (fmt);
|
|
if (drm_fourcc == DRM_FORMAT_INVALID)
|
|
return FALSE;
|
|
|
|
g_value_init (&mods, GST_TYPE_LIST);
|
|
g_value_init (&gval, G_TYPE_STRING);
|
|
|
|
gst_msdk_get_supported_modifiers (context, job_type, fmt, &mods);
|
|
|
|
for (gint m = 0; m < gst_value_list_get_size (&mods); m++) {
|
|
const GValue *gmod = gst_value_list_get_value (&mods, m);
|
|
modifier = g_value_get_uint64 (gmod);
|
|
|
|
drm_fmt_str = gst_video_dma_drm_fourcc_to_string (drm_fourcc, modifier);
|
|
if (!drm_fmt_str)
|
|
continue;
|
|
|
|
g_value_set_string (&gval, drm_fmt_str);
|
|
gst_value_list_append_value (dma_drm_fmts, &gval);
|
|
|
|
GST_DEBUG ("Got modifier: %s", drm_fmt_str);
|
|
g_free (drm_fmt_str);
|
|
}
|
|
g_value_unset (&mods);
|
|
g_value_unset (&gval);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_dma_fmts_to_dma_drm_fmts (GstMsdkContext * context,
|
|
GstMsdkContextJobType job_type,
|
|
const GValue * dma_fmts, GValue * dma_drm_fmts)
|
|
{
|
|
gint size = gst_value_list_get_size (dma_fmts);
|
|
|
|
for (gint f = 0; f < size; f++) {
|
|
const GValue *dma_fmt = gst_value_list_get_value (dma_fmts, f);
|
|
if (!dma_fmt)
|
|
continue;
|
|
|
|
_dma_fmt_to_dma_drm_fmts (context, job_type, dma_fmt, dma_drm_fmts);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstCaps *
|
|
_create_dma_drm_caps (GstMsdkContext * context,
|
|
GstMsdkContextJobType job_type, const GValue * dma_formats)
|
|
{
|
|
GstCaps *dma_drm_caps = NULL;
|
|
GValue dma_drm_fmts = G_VALUE_INIT;
|
|
|
|
g_return_val_if_fail (context != NULL, FALSE);
|
|
g_return_val_if_fail (dma_formats != NULL, FALSE);
|
|
|
|
g_value_init (&dma_drm_fmts, GST_TYPE_LIST);
|
|
|
|
if (GST_VALUE_HOLDS_LIST (dma_formats))
|
|
_dma_fmts_to_dma_drm_fmts (context, job_type, dma_formats, &dma_drm_fmts);
|
|
else if (G_VALUE_HOLDS_STRING (dma_formats))
|
|
_dma_fmt_to_dma_drm_fmts (context, job_type, dma_formats, &dma_drm_fmts);
|
|
|
|
if (gst_value_list_get_size (&dma_drm_fmts) > 0) {
|
|
dma_drm_caps = gst_caps_from_string ("video/x-raw(memory:DMABuf)");
|
|
gst_caps_set_simple (dma_drm_caps, "format", G_TYPE_STRING, "DMA_DRM",
|
|
NULL);
|
|
gst_caps_set_value (dma_drm_caps, "drm-format", &dma_drm_fmts);
|
|
}
|
|
|
|
g_value_unset (&dma_drm_fmts);
|
|
|
|
return dma_drm_caps;
|
|
}
|
|
#endif
|
|
|
|
#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;
|
|
|
|
in->mfx.LowPower = MFX_CODINGOPTION_UNKNOWN;
|
|
if (!_enc_is_param_supported (session, in, out)) {
|
|
in->mfx.LowPower = (out->mfx.LowPower == MFX_CODINGOPTION_ON) ?
|
|
MFX_CODINGOPTION_OFF : MFX_CODINGOPTION_ON;
|
|
|
|
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);
|
|
}
|
|
|
|
g_value_unset (&fmts);
|
|
|
|
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, *raw_caps;
|
|
|
|
#ifndef _WIN32
|
|
caps = gst_caps_from_string
|
|
("video/x-raw(memory:VAMemory), format=(string){ NV12 }");
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_ENCODER,
|
|
supported_formats);
|
|
gst_caps_append (caps, dma_caps);
|
|
#else
|
|
VAR_UNUSED (dma_caps);
|
|
caps = gst_caps_from_string
|
|
("video/x-raw(memory:D3D11Memory), format=(string){ NV12 }");
|
|
#endif
|
|
|
|
raw_caps = gst_caps_from_string ("video/x-raw");
|
|
gst_caps_set_value (raw_caps, "format", supported_formats);
|
|
gst_caps_append (caps, raw_caps);
|
|
|
|
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;
|
|
}
|
|
|
|
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:
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
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, *raw_caps;
|
|
ResolutionRange res = { 1, G_MAXUINT16, 1, G_MAXUINT16 };
|
|
|
|
if (!_dec_get_resolution_range (session, dec_desc, codec_id, &res))
|
|
return NULL;
|
|
|
|
#ifndef _WIN32
|
|
caps = gst_caps_from_string
|
|
("video/x-raw(memory:VAMemory), format=(string){ NV12 }");
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_DECODER,
|
|
supported_formats);
|
|
gst_caps_append (caps, dma_caps);
|
|
#else
|
|
VAR_UNUSED (dma_caps);
|
|
caps = gst_caps_from_string
|
|
("video/x-raw(memory:D3D11Memory), format=(string){ NV12 }");
|
|
#endif
|
|
|
|
raw_caps = gst_caps_from_string ("video/x-raw");
|
|
gst_caps_set_value (raw_caps, "format", supported_formats);
|
|
gst_caps_append (caps, raw_caps);
|
|
|
|
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;
|
|
}
|
|
|
|
static void
|
|
_vpp_init_param (mfxVideoParam * param,
|
|
GstVideoFormat infmt, GstVideoFormat outfmt)
|
|
{
|
|
g_return_if_fail (param != NULL);
|
|
|
|
memset (param, 0, sizeof (mfxVideoParam));
|
|
param->IOPattern = VPP_IOPATTERN;
|
|
param->vpp.In.Width = default_width;
|
|
param->vpp.In.Height = default_height;
|
|
param->vpp.In.CropW = param->mfx.FrameInfo.Width;
|
|
param->vpp.In.CropH = param->mfx.FrameInfo.Height;
|
|
param->vpp.In.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
|
|
param->vpp.In.FrameRateExtN = 30;
|
|
param->vpp.In.FrameRateExtD = 1;
|
|
param->vpp.In.AspectRatioW = 1;
|
|
param->vpp.In.AspectRatioH = 1;
|
|
|
|
param->vpp.Out = param->vpp.In;
|
|
|
|
_fill_mfxframeinfo (infmt, ¶m->vpp.In);
|
|
_fill_mfxframeinfo (outfmt, ¶m->vpp.Out);
|
|
}
|
|
|
|
static inline gboolean
|
|
_vpp_is_param_supported (mfxSession * session,
|
|
mfxVideoParam * in, mfxVideoParam * out)
|
|
{
|
|
mfxStatus status = MFXVideoVPP_Query (*session, in, out);
|
|
if (status == MFX_ERR_NONE)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
_vpp_are_formats_supported (mfxSession * session,
|
|
GstVideoFormat infmt, GstVideoFormat outfmt,
|
|
mfxVideoParam * in, mfxVideoParam * out)
|
|
{
|
|
if (!_fill_mfxframeinfo (infmt, &in->vpp.In))
|
|
return FALSE;
|
|
|
|
if (!_fill_mfxframeinfo (outfmt, &in->vpp.Out))
|
|
return FALSE;
|
|
|
|
if (!_vpp_is_param_supported (session, in, out))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_vpp_get_supported_formats (mfxSession * session,
|
|
GValue * supported_in_fmts, GValue * supported_out_fmts)
|
|
{
|
|
guint size;
|
|
const GValue *gfmt;
|
|
GValue fmts = G_VALUE_INIT;
|
|
GstVideoFormat infmt = DEFAULT_VIDEO_FORMAT;
|
|
GstVideoFormat outfmt = DEFAULT_VIDEO_FORMAT;
|
|
gboolean infmt_in_list, outfmt_in_list;
|
|
mfxVideoParam in, out;
|
|
|
|
_vpp_init_param (&in, infmt, outfmt);
|
|
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 i = 0; i < size; i++) {
|
|
gfmt = gst_value_list_get_value (&fmts, i);
|
|
infmt = g_value_get_uint (gfmt);
|
|
|
|
for (guint j = 0; j < size; j++) {
|
|
gfmt = gst_value_list_get_value (&fmts, j);
|
|
outfmt = g_value_get_uint (gfmt);
|
|
|
|
infmt_in_list = _format_in_list (infmt, supported_in_fmts);
|
|
outfmt_in_list = _format_in_list (outfmt, supported_out_fmts);
|
|
if (infmt_in_list && outfmt_in_list)
|
|
continue;
|
|
|
|
if (!_vpp_are_formats_supported (session, infmt, outfmt, &in, &out))
|
|
continue;
|
|
|
|
if (!infmt_in_list)
|
|
_list_append_string (supported_in_fmts,
|
|
gst_video_format_to_string (infmt));
|
|
|
|
if (!outfmt_in_list)
|
|
_list_append_string (supported_out_fmts,
|
|
gst_video_format_to_string (outfmt));
|
|
}
|
|
}
|
|
|
|
g_value_unset (&fmts);
|
|
|
|
if (gst_value_list_get_size (supported_in_fmts) == 0 ||
|
|
gst_value_list_get_size (supported_out_fmts) == 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
_vpp_get_desc_image_range (mfxVPPDescription * vpp_desc,
|
|
GstVideoFormat format, mfxRange32U * width, mfxRange32U * height)
|
|
{
|
|
mfxU32 infmt = gst_msdk_get_mfx_fourcc_from_format (format);
|
|
|
|
for (guint f = 0; f < vpp_desc->NumFilters; f++) {
|
|
for (guint i = 0; i < vpp_desc->NumFilters; i++) {
|
|
if (vpp_desc->Filters[f].MemDesc->Formats[i].InFormat != infmt)
|
|
continue;
|
|
|
|
*width = vpp_desc->Filters[f].MemDesc->Width;
|
|
*height = vpp_desc->Filters[f].MemDesc->Height;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
_vpp_get_resolution_range (mfxSession * session,
|
|
mfxVPPDescription * vpp_desc, ResolutionRange * res_range)
|
|
{
|
|
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);
|
|
|
|
if (!_vpp_get_desc_image_range (vpp_desc,
|
|
DEFAULT_VIDEO_FORMAT, &width, &height))
|
|
return FALSE;
|
|
|
|
_vpp_init_param (&in, DEFAULT_VIDEO_FORMAT, DEFAULT_VIDEO_FORMAT);
|
|
out = in;
|
|
|
|
IsParamSupportedFunc func = _vpp_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 VPP supported resolution range "
|
|
"width: [%d, %d], height: [%d, %d]",
|
|
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 GstCaps *
|
|
_vpp_create_caps (GstMsdkContext * context,
|
|
GValue * supported_fmts, ResolutionRange * res)
|
|
{
|
|
GstCaps *caps, *dma_caps, *raw_caps;
|
|
|
|
#ifndef _WIN32
|
|
caps = gst_caps_from_string ("video/x-raw(memory:VAMemory), "
|
|
"format=(string){ NV12, VUYA, P010_10LE }");
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_VPP, supported_fmts);
|
|
gst_caps_append (caps, dma_caps);
|
|
#else
|
|
VAR_UNUSED (dma_caps);
|
|
caps = gst_caps_from_string ("video/x-raw(memory:D3D11Memory), "
|
|
"format=(string){ NV12, VUYA, P010_10LE }");
|
|
#endif
|
|
raw_caps = gst_caps_from_string ("video/x-raw");
|
|
gst_caps_set_value (raw_caps, "format", supported_fmts);
|
|
gst_caps_append (caps, raw_caps);
|
|
|
|
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_msdkcaps_set_strings (caps, "memory:SystemMemory",
|
|
"interlace-mode", "progressive, interleaved, mixed");
|
|
|
|
GST_DEBUG ("Create VPP caps %" GST_PTR_FORMAT, caps);
|
|
|
|
return caps;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_vpp_create_caps (GstMsdkContext * context,
|
|
gpointer vpp_description, GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
mfxVPPDescription *vpp_desc;
|
|
GstCaps *in_caps = NULL, *out_caps = NULL;
|
|
GValue supported_in_fmts = G_VALUE_INIT;
|
|
GValue supported_out_fmts = G_VALUE_INIT;
|
|
ResolutionRange res_range = { 1, G_MAXUINT16, 1, G_MAXUINT16 };
|
|
mfxSession session;
|
|
|
|
g_return_val_if_fail (context, FALSE);
|
|
g_return_val_if_fail (vpp_description, FALSE);
|
|
|
|
vpp_desc = (mfxVPPDescription *) vpp_description;
|
|
if (vpp_desc->NumFilters == 0)
|
|
return FALSE;
|
|
|
|
session = gst_msdk_context_get_session (context);
|
|
|
|
g_value_init (&supported_in_fmts, GST_TYPE_LIST);
|
|
g_value_init (&supported_out_fmts, GST_TYPE_LIST);
|
|
|
|
if (!_vpp_get_supported_formats (&session,
|
|
&supported_in_fmts, &supported_out_fmts))
|
|
goto failed;
|
|
|
|
if (!_vpp_get_resolution_range (&session, vpp_desc, &res_range))
|
|
goto failed;
|
|
|
|
in_caps = _vpp_create_caps (context, &supported_in_fmts, &res_range);
|
|
g_value_unset (&supported_in_fmts);
|
|
if (!in_caps)
|
|
goto failed;
|
|
|
|
out_caps = _vpp_create_caps (context, &supported_out_fmts, &res_range);
|
|
g_value_unset (&supported_out_fmts);
|
|
if (!out_caps)
|
|
goto failed;
|
|
|
|
*sink_caps = in_caps;
|
|
*src_caps = out_caps;
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_WARNING ("Failed to create caps for VPP");
|
|
|
|
g_value_unset (&supported_in_fmts);
|
|
g_value_unset (&supported_out_fmts);
|
|
if (in_caps)
|
|
gst_caps_unref (in_caps);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#else
|
|
|
|
gboolean
|
|
gst_msdkcaps_enc_create_caps (GstMsdkContext * context,
|
|
gpointer enc_description, guint codec_id,
|
|
GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_dec_create_caps (GstMsdkContext * context,
|
|
gpointer dec_description, guint codec_id,
|
|
GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_vpp_create_caps (GstMsdkContext * context,
|
|
gpointer vpp_description, GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
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_static_raw_formats (guint codec_id)
|
|
{
|
|
switch (codec_id) {
|
|
case MFX_CODEC_AVC:
|
|
return "NV12, YUY2, UYVY, BGRA";
|
|
case MFX_CODEC_HEVC:
|
|
return "NV12, YUY2, BGRA, BGR10A2_LE, P010_10LE, VUYA, Y410, Y210, "
|
|
"P012_LE";
|
|
case MFX_CODEC_MPEG2:
|
|
return "NV12";
|
|
case MFX_CODEC_VP9:
|
|
return "NV12, P010_10LE, VUYA, Y410";
|
|
case MFX_CODEC_AV1:
|
|
return "NV12, P010_10LE";
|
|
case MFX_CODEC_JPEG:
|
|
return "NV12, 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_static_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";
|
|
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_static_caps (GstMsdkContext * context,
|
|
guint codec_id, GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
GstCaps *in_caps = NULL, *out_caps = NULL;
|
|
GstCaps *dma_caps = NULL;
|
|
gchar *raw_caps_str;
|
|
const gchar *media_type = NULL;
|
|
const char *raw_fmts = NULL;
|
|
const char *dma_fmts_str = NULL;
|
|
GValue dma_fmts = G_VALUE_INIT;
|
|
GValue supported_profs = G_VALUE_INIT;
|
|
|
|
raw_fmts = _enc_get_static_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_str = _enc_get_static_dma_formats (codec_id);
|
|
if (!dma_fmts_str)
|
|
goto failed;
|
|
|
|
g_value_init (&dma_fmts, GST_TYPE_LIST);
|
|
_strings_to_list (dma_fmts_str, &dma_fmts);
|
|
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_ENCODER, &dma_fmts);
|
|
g_value_unset (&dma_fmts);
|
|
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);
|
|
VAR_UNUSED (dma_fmts_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;
|
|
}
|
|
|
|
static const char *
|
|
_dec_get_static_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_static_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_static_caps (GstMsdkContext * context,
|
|
guint codec_id, GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
GstCaps *in_caps = NULL, *out_caps = NULL;
|
|
GstCaps *dma_caps = NULL;
|
|
gchar *raw_caps_str;
|
|
const gchar *media_type = NULL;
|
|
const char *raw_fmts = NULL;
|
|
const char *dma_fmts_str = NULL;
|
|
GValue dma_fmts = G_VALUE_INIT;
|
|
|
|
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_static_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_str = _dec_get_static_dma_formats (codec_id);
|
|
if (!dma_fmts_str)
|
|
goto failed;
|
|
|
|
g_value_init (&dma_fmts, GST_TYPE_LIST);
|
|
_strings_to_list (dma_fmts_str, &dma_fmts);
|
|
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_DECODER, &dma_fmts);
|
|
g_value_unset (&dma_fmts);
|
|
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);
|
|
VAR_UNUSED (dma_fmts_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);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static const char *
|
|
_vpp_get_static_raw_formats (GstPadDirection direction)
|
|
{
|
|
switch (direction) {
|
|
case GST_PAD_SINK:
|
|
return "NV12, YV12, I420, YUY2, UYVY, VUYA, BGRA, BGRx, P010_10LE, "
|
|
"RGB16, Y410, Y210, P012_LE, Y212_LE, Y412_LE";
|
|
case GST_PAD_SRC:
|
|
return "NV12, BGRA, YUY2, UYVY, VUYA, BGRx, P010_10LE, BGR10A2_LE, "
|
|
"YV12, Y410, Y210, RGBP, BGRP, P012_LE, Y212_LE, Y412_LE";
|
|
default:
|
|
GST_WARNING ("Unsupported VPP direction");
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
static const char *
|
|
_vpp_get_static_dma_formats (GstPadDirection direction)
|
|
{
|
|
switch (direction) {
|
|
case GST_PAD_SINK:
|
|
return "NV12, BGRA, YUY2, UYVY, VUYA, P010_10LE, RGB16, Y410, Y210, "
|
|
"P012_LE, Y212_LE, Y412_LE";
|
|
case GST_PAD_SRC:
|
|
return "NV12, BGRA, YUY2, UYVY, VUYA, BGRx, P010_10LE, BGR10A2_LE, "
|
|
"YV12, Y410, Y210, RGBP, BGRP, P012_LE, Y212_LE, Y412_LE";
|
|
default:
|
|
GST_WARNING ("Unsupported VPP direction");
|
|
break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
static GstCaps *
|
|
_vpp_create_static_caps (GstMsdkContext * context, GstPadDirection direction)
|
|
{
|
|
GstCaps *caps = NULL, *dma_caps = NULL;
|
|
gchar *caps_str;
|
|
GValue dma_fmts = G_VALUE_INIT;
|
|
|
|
caps_str = g_strdup_printf ("video/x-raw, format=(string){ %s }",
|
|
_vpp_get_static_raw_formats (direction));
|
|
caps = gst_caps_from_string (caps_str);
|
|
g_free (caps_str);
|
|
|
|
#ifndef _WIN32
|
|
g_value_init (&dma_fmts, GST_TYPE_LIST);
|
|
_strings_to_list (_vpp_get_static_dma_formats (direction), &dma_fmts);
|
|
|
|
dma_caps = _create_dma_drm_caps (context, GST_MSDK_JOB_VPP, &dma_fmts);
|
|
g_value_unset (&dma_fmts);
|
|
gst_caps_append (caps, dma_caps);
|
|
|
|
gst_caps_append (caps, gst_caps_from_string ("video/x-raw(memory:VAMemory), "
|
|
"format=(string){ NV12, VUYA, P010_10LE }"));
|
|
#else
|
|
VAR_UNUSED (dma_caps);
|
|
VAR_UNUSED (dma_fmts);
|
|
|
|
gst_caps_append (caps,
|
|
gst_caps_from_string ("video/x-raw(memory:D3D11Memory), "
|
|
"format=(string){ NV12, VUYA, P010_10LE }"));
|
|
#endif
|
|
|
|
gst_caps_set_simple (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);
|
|
|
|
gst_msdkcaps_set_strings (caps, "memory:SystemMemory",
|
|
"interlace-mode", "progressive, interleaved, mixed");
|
|
|
|
return caps;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_vpp_create_static_caps (GstMsdkContext * context,
|
|
GstCaps ** sink_caps, GstCaps ** src_caps)
|
|
{
|
|
*sink_caps = _vpp_create_static_caps (context, GST_PAD_SINK);
|
|
*src_caps = _vpp_create_static_caps (context, GST_PAD_SRC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
_pad_template_init (GstElementClass * klass,
|
|
const gchar * name_template, GstPadDirection direction,
|
|
GstCaps * caps, const gchar * doc_caps_str)
|
|
{
|
|
GstPadTemplate *pad_templ;
|
|
|
|
if (!caps)
|
|
return;
|
|
|
|
pad_templ = gst_pad_template_new (name_template,
|
|
direction, GST_PAD_ALWAYS, caps);
|
|
if (doc_caps_str) {
|
|
GstCaps *doc_caps = gst_caps_from_string (doc_caps_str);
|
|
gst_pad_template_set_documentation_caps (pad_templ, doc_caps);
|
|
gst_caps_unref (doc_caps);
|
|
}
|
|
|
|
gst_element_class_add_pad_template (klass, pad_templ);
|
|
}
|
|
|
|
void
|
|
gst_msdkcaps_pad_template_init (GstElementClass * klass,
|
|
GstCaps * sink_caps, GstCaps * src_caps,
|
|
const gchar * doc_sink_caps_str, const gchar * doc_src_caps_str)
|
|
{
|
|
_pad_template_init (klass,
|
|
"sink", GST_PAD_SINK, sink_caps, doc_sink_caps_str);
|
|
|
|
_pad_template_init (klass, "src", GST_PAD_SRC, src_caps, doc_src_caps_str);
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_set_strings (GstCaps * caps,
|
|
const gchar * features, const char *field, const gchar * strings)
|
|
{
|
|
GValue list = G_VALUE_INIT;
|
|
guint size = gst_caps_get_size (caps);
|
|
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
g_return_val_if_fail (field != NULL, FALSE);
|
|
g_return_val_if_fail (strings != NULL, FALSE);
|
|
|
|
g_value_init (&list, GST_TYPE_LIST);
|
|
_strings_to_list (strings, &list);
|
|
|
|
if (features) {
|
|
GstStructure *s = NULL;
|
|
GstCapsFeatures *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))) {
|
|
s = gst_caps_get_structure (caps, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
gst_caps_features_free (f);
|
|
|
|
if (!s)
|
|
return FALSE;
|
|
|
|
/* When we use this function to get a fixated caps, we should set
|
|
* a single value instead of a list in the corresponding field.
|
|
*/
|
|
if (gst_value_list_get_size (&list) == 1)
|
|
gst_structure_set_value (s, field, gst_value_list_get_value (&list, 0));
|
|
else
|
|
gst_structure_set_value (s, field, &list);
|
|
} else {
|
|
gst_caps_set_value (caps, field, &list);
|
|
}
|
|
|
|
g_value_unset (&list);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_msdkcaps_video_info_from_caps (const GstCaps * caps,
|
|
GstVideoInfo * info, guint64 * modifier)
|
|
{
|
|
g_return_val_if_fail (caps != NULL, FALSE);
|
|
g_return_val_if_fail (info != NULL, FALSE);
|
|
|
|
#ifndef _WIN32
|
|
if (gst_video_is_dma_drm_caps (caps)) {
|
|
GstVideoInfoDmaDrm *drm_info = gst_video_info_dma_drm_new_from_caps (caps);
|
|
if (!drm_info)
|
|
goto failed;
|
|
|
|
if (!gst_video_info_dma_drm_to_video_info (drm_info, info)) {
|
|
gst_video_info_dma_drm_free (drm_info);
|
|
goto failed;
|
|
}
|
|
if (modifier)
|
|
*modifier = drm_info->drm_modifier;
|
|
|
|
gst_video_info_dma_drm_free (drm_info);
|
|
} else
|
|
#endif
|
|
|
|
if (!gst_video_info_from_caps (info, caps))
|
|
goto failed;
|
|
|
|
return TRUE;
|
|
|
|
failed:
|
|
GST_ERROR_OBJECT (caps, "Failed to get video info fom caps");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
GstCaps *
|
|
gst_msdkcaps_video_info_to_drm_caps (GstVideoInfo * info, guint64 modifier)
|
|
{
|
|
GstVideoInfoDmaDrm drm_info;
|
|
|
|
gst_video_info_dma_drm_init (&drm_info);
|
|
drm_info.vinfo = *info;
|
|
drm_info.drm_fourcc =
|
|
gst_va_drm_fourcc_from_video_format (GST_VIDEO_INFO_FORMAT (info));
|
|
drm_info.drm_modifier = modifier;
|
|
|
|
return gst_video_info_dma_drm_to_caps (&drm_info);
|
|
}
|
|
|
|
guint64
|
|
get_msdkcaps_get_modifier (const GstCaps * caps)
|
|
{
|
|
guint64 modifier = DRM_FORMAT_MOD_INVALID;
|
|
guint size = gst_caps_get_size (caps);
|
|
|
|
for (guint i = 0; i < size; i++) {
|
|
GstCapsFeatures *f = gst_caps_get_features (caps, i);
|
|
|
|
if (gst_caps_features_contains (f, GST_CAPS_FEATURE_MEMORY_DMABUF)) {
|
|
GstStructure *s = gst_caps_get_structure (caps, i);
|
|
const GValue *drm_fmts = gst_structure_get_value (s, "drm-format");
|
|
const gchar *drm_str = NULL;
|
|
|
|
if (!drm_fmts)
|
|
continue;
|
|
|
|
if (G_VALUE_HOLDS_STRING (drm_fmts))
|
|
drm_str = g_value_get_string (drm_fmts);
|
|
else if (GST_VALUE_HOLDS_LIST (drm_fmts)) {
|
|
const GValue *val = gst_value_list_get_value (drm_fmts, 0);
|
|
drm_str = g_value_get_string (val);
|
|
}
|
|
|
|
gst_video_dma_drm_fourcc_from_string (drm_str, &modifier);
|
|
}
|
|
}
|
|
|
|
GST_DEBUG ("got modifier: 0x%016lx", modifier);
|
|
|
|
return modifier;
|
|
}
|
|
#endif
|