libs: video-format: Refine the video format mapping.

Improve the mapping between va format and gst format. The new map
will be generated dynamically, based on the query result of image
format in VA driver. Also consider the ambiguity of RGB color
format in LSB mode.
This commit is contained in:
He Junyan 2019-09-05 14:48:22 +08:00 committed by Víctor Manuel Jáquez Leal
parent a90daabb84
commit 32bf6f1e09
3 changed files with 301 additions and 62 deletions

View file

@ -675,6 +675,11 @@ ensure_image_formats (GstVaapiDisplay * display)
for (i = 0; i < n; i++)
GST_DEBUG (" %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
if (!gst_vaapi_video_format_create_map (formats, n)) {
GST_ERROR ("fail to create map between gst video format and vaImageFormat");
goto cleanup;
}
append_formats (priv->image_formats, formats, NULL, n);
g_array_sort (priv->image_formats, compare_yuv_formats);
success = TRUE;
@ -906,6 +911,12 @@ gst_vaapi_display_create (GstVaapiDisplay * display,
GST_INFO_OBJECT (display, "new display addr=%p", display);
g_free (priv->display_name);
priv->display_name = g_strdup (info.display_name);
if (!ensure_image_formats (display)) {
gst_vaapi_display_destroy (display);
return FALSE;
}
return TRUE;
}

View file

@ -38,59 +38,128 @@
# define VIDEO_VA_ENDIANESS VA_LSB_FIRST
#endif
typedef struct
typedef struct _GstVideoFormatMapMap
{
GstVideoFormat format;
GstVaapiChromaType chroma_type;
VAImageFormat va_format;
} GstVideoFormatMap;
#define DEF_YUV(FORMAT, FOURCC, BPP, SUB) \
#define VA_BYTE_ORDER_NOT_CARE 0
#define DEF_YUV(BYTE_ORDER, FORMAT, FOURCC, BPP, SUB) \
{ G_PASTE(GST_VIDEO_FORMAT_,FORMAT), \
G_PASTE(GST_VAAPI_CHROMA_TYPE_YUV,SUB), \
{ VA_FOURCC FOURCC, VIDEO_VA_ENDIANESS, BPP, }, }
{ VA_FOURCC FOURCC, BYTE_ORDER, BPP, }, }
#define DEF_RGB(FORMAT, FOURCC, BPP, DEPTH, R,G,B,A) \
#define DEF_RGB(BYTE_ORDER, FORMAT, FOURCC, BPP, DEPTH, R,G,B,A) \
{ G_PASTE(GST_VIDEO_FORMAT_,FORMAT), \
G_PASTE(GST_VAAPI_CHROMA_TYPE_RGB,BPP), \
{ VA_FOURCC FOURCC, VIDEO_VA_ENDIANESS, BPP, DEPTH, R,G,B,A }, }
{ VA_FOURCC FOURCC, BYTE_ORDER, BPP, DEPTH, R, G, B, A }, }
/* Image formats, listed in HW order preference */
/* *INDENT-OFF* */
static const GstVideoFormatMap gst_vaapi_video_formats[] = {
static const GstVideoFormatMap gst_vaapi_video_default_formats[] = {
/* LSB and MSB video formats definitions are unclear and ambiguous.
*
* For MSB, there is no ambiguity: same order in define, memory and
* CPU. For example,
*
* RGBA is RGBA in memory and RGBA with channel mask R:0xFF0000
* G:0x00FF0000 B:0x0000FF00 A:0x000000FF in CPU.
*
* For LSB, CPU's perspective and memory's perspective are
* different. For example,
*
* RGBA in LSB, from CPU's perspective, it's RGBA order in memory,
* but when it is stored in memory, because CPU's little
* endianness, it will be re-ordered, with mask R:0x000000FF
* G:0x0000FF00 B:0x00FF0000 A:0xFF000000. In other words, from
* memory's perspective, RGBA LSB is equal as ABGR MSB.
*
* These definitions are mixed used all over the media system and we
* need to correct the mapping form VA video format to GStreamer
* video format in both manners, especially for RGB format.
*/
/* YUV formats */
DEF_YUV (NV12, ('N', 'V', '1', '2'), 12, 420),
DEF_YUV (YV12, ('Y', 'V', '1', '2'), 12, 420),
DEF_YUV (I420, ('I', '4', '2', '0'), 12, 420),
DEF_YUV (YUY2, ('Y', 'U', 'Y', '2'), 16, 422),
DEF_YUV (UYVY, ('U', 'Y', 'V', 'Y'), 16, 422),
DEF_YUV (Y210, ('Y', '2', '1', '0'), 32, 422_10BPP),
DEF_YUV (Y410, ('Y', '4', '1', '0'), 32, 444_10BPP),
DEF_YUV (AYUV, ('A', 'Y', 'U', 'V'), 32, 444),
DEF_YUV (Y444, ('4', '4', '4', 'P'), 24, 444),
DEF_YUV (GRAY8, ('Y', '8', '0', '0'), 8, 400),
DEF_YUV (P010_10LE, ('P', '0', '1', '0'), 24, 420_10BPP),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, NV12, ('N', 'V', '1', '2'), 12, 420),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YV12, ('Y', 'V', '1', '2'), 12, 420),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, I420, ('I', '4', '2', '0'), 12, 420),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YUY2, ('Y', 'U', 'Y', '2'), 16, 422),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, UYVY, ('U', 'Y', 'V', 'Y'), 16, 422),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y444, ('4', '4', '4', 'P'), 24, 444),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, GRAY8, ('Y', '8', '0', '0'), 8, 400),
DEF_YUV (VA_LSB_FIRST, P010_10LE, ('P', '0', '1', '0'), 24, 420_10BPP),
/* AYUV is a clear defined format by doc */
DEF_YUV (VA_LSB_FIRST, VUYA, ('A', 'Y', 'U', 'V'), 32, 444),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y210, ('Y', '2', '1', '0'), 32, 422_10BPP),
DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y410, ('Y', '4', '1', '0'), 32, 444_10BPP),
/* RGB formats */
DEF_RGB (ARGB, ('A', 'R', 'G', 'B'), 32,
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
DEF_RGB (ABGR, ('A', 'B', 'G', 'R'), 32,
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
DEF_RGB (xRGB, ('X', 'R', 'G', 'B'), 32,
24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (xBGR, ('X', 'B', 'G', 'R'), 32,
24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000),
DEF_RGB (BGRA, ('B', 'G', 'R', 'A'), 32,
32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
DEF_RGB (RGBA, ('R', 'G', 'B', 'A'), 32,
32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
DEF_RGB (BGRx, ('B', 'G', 'R', 'X'), 32,
24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (RGBx, ('R', 'G', 'B', 'X'), 32,
24, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000),
DEF_RGB (RGB16, ('R', 'G', '1', '6'), 16,
16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000),
DEF_RGB (RGB, ('R', 'G', '2', '4'), 32,
24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (VA_LSB_FIRST, ARGB, ('A', 'R', 'G', 'B'), 32, 32, 0x0000ff00,
0x00ff0000, 0xff000000, 0x000000ff),
DEF_RGB (VA_LSB_FIRST, ARGB, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00,
0x00ff0000, 0xff000000, 0x000000ff),
DEF_RGB (VA_MSB_FIRST, ARGB, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000,
0x0000ff00, 0x000000ff, 0xff000000),
DEF_RGB (VA_LSB_FIRST, xRGB, ('X', 'R', 'G', 'B'), 32, 24, 0x0000ff00,
0x00ff0000, 0xff000000, 0x00000000),
DEF_RGB (VA_LSB_FIRST, xRGB, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00,
0x00ff0000, 0xff000000, 0x00000000),
DEF_RGB (VA_MSB_FIRST, xRGB, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000,
0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (VA_LSB_FIRST, RGBA, ('R', 'G', 'B', 'A'), 32, 32, 0x000000ff,
0x0000ff00, 0x00ff0000, 0xff000000),
DEF_RGB (VA_LSB_FIRST, RGBA, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff,
0x0000ff00, 0x00ff0000, 0xff000000),
DEF_RGB (VA_MSB_FIRST, RGBA, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000,
0x00ff0000, 0x0000ff00, 0x000000ff),
DEF_RGB (VA_LSB_FIRST, RGBx, ('R', 'G', 'B', 'X'), 32, 24, 0x000000ff,
0x0000ff00, 0x00ff0000, 0x00000000),
DEF_RGB (VA_LSB_FIRST, RGBx, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff,
0x0000ff00, 0x00ff0000, 0x00000000),
DEF_RGB (VA_MSB_FIRST, RGBx, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000,
0x00ff0000, 0x0000ff00, 0x00000000),
DEF_RGB (VA_LSB_FIRST, ABGR, ('A', 'B', 'G', 'R'), 32, 32, 0xff000000,
0x00ff0000, 0x0000ff00, 0x000000ff),
DEF_RGB (VA_LSB_FIRST, ABGR, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000,
0x00ff0000, 0x0000ff00, 0x000000ff),
DEF_RGB (VA_MSB_FIRST, ABGR, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff,
0x0000ff00, 0x00ff0000, 0xff000000),
DEF_RGB (VA_LSB_FIRST, xBGR, ('X', 'B', 'G', 'R'), 32, 24, 0xff000000,
0x00ff0000, 0x0000ff00, 0x00000000),
DEF_RGB (VA_LSB_FIRST, xBGR, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000,
0x00ff0000, 0x0000ff00, 0x00000000),
DEF_RGB (VA_MSB_FIRST, xBGR, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff,
0x0000ff00, 0x00ff0000, 0x00000000),
DEF_RGB (VA_LSB_FIRST, BGRA, ('B', 'G', 'R', 'A'), 32, 32, 0x00ff0000,
0x0000ff00, 0x000000ff, 0xff000000),
DEF_RGB (VA_LSB_FIRST, BGRA, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000,
0x0000ff00, 0x000000ff, 0xff000000),
DEF_RGB (VA_MSB_FIRST, BGRA, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00,
0x00ff0000, 0xff000000, 0x000000ff),
DEF_RGB (VA_LSB_FIRST, BGRx, ('B', 'G', 'R', 'X'), 32, 24, 0x00ff0000,
0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (VA_LSB_FIRST, BGRx, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000,
0x0000ff00, 0x000000ff, 0x00000000),
DEF_RGB (VA_MSB_FIRST, BGRx, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00,
0x00ff0000, 0xff000000, 0x00000000),
DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB16, ('R', 'G', '1', '6'), 16, 16,
0x0000f800, 0x000007e0, 0x0000001f, 0x00000000),
DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB, ('R', 'G', '2', '4'), 32, 24,
0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
{0,}
};
/* *INDENT-ON* */
@ -98,6 +167,8 @@ static const GstVideoFormatMap gst_vaapi_video_formats[] = {
#undef DEF_RGB
#undef DEF_YUV
static GArray *gst_vaapi_video_formats_map;
static inline gboolean
va_format_is_rgb (const VAImageFormat * va_format)
{
@ -113,8 +184,7 @@ va_format_is_yuv (const VAImageFormat * va_format)
static inline gboolean
va_format_is_same_rgb (const VAImageFormat * fmt1, const VAImageFormat * fmt2)
{
return (fmt1->byte_order == fmt2->byte_order &&
fmt1->red_mask == fmt2->red_mask &&
return (fmt1->red_mask == fmt2->red_mask &&
fmt1->green_mask == fmt2->green_mask &&
fmt1->blue_mask == fmt2->blue_mask &&
fmt1->alpha_mask == fmt2->alpha_mask);
@ -125,21 +195,89 @@ va_format_is_same (const VAImageFormat * fmt1, const VAImageFormat * fmt2)
{
if (fmt1->fourcc != fmt2->fourcc)
return FALSE;
if (fmt1->byte_order != VA_BYTE_ORDER_NOT_CARE &&
fmt2->byte_order != VA_BYTE_ORDER_NOT_CARE &&
fmt1->byte_order != fmt2->byte_order)
return FALSE;
return va_format_is_rgb (fmt1) ? va_format_is_same_rgb (fmt1, fmt2) : TRUE;
}
static const GstVideoFormatMap *
get_map (GstVideoFormat format)
get_map_in_default_by_gst_format (GstVideoFormat format)
{
const GstVideoFormatMap *m;
for (m = gst_vaapi_video_formats; m->format; m++) {
for (m = gst_vaapi_video_default_formats; m->format; m++) {
if (m->format == format)
return m;
}
return NULL;
}
static const GstVideoFormatMap *
get_map_in_default_by_va_format (const VAImageFormat * va_format)
{
const GstVideoFormatMap *m, *n;
n = NULL;
for (m = gst_vaapi_video_default_formats; m->format; m++) {
if (va_format_is_same (&m->va_format, va_format)) {
/* Should not map to VAImageFormat to same GstVideoFormat */
g_assert (n == NULL);
n = m;
}
}
return n;
}
static const GstVideoFormatMap *
get_map_by_gst_format (const GArray * formats, GstVideoFormat format)
{
const GstVideoFormatMap *entry;
guint i;
for (i = 0; i < formats->len; i++) {
entry = &g_array_index (formats, GstVideoFormatMap, i);
if (entry->format == format)
return entry;
}
return NULL;
}
static const GstVideoFormatMap *
get_map_by_va_format (const VAImageFormat * va_format)
{
const GArray *formats = gst_vaapi_video_formats_map;
const GstVideoFormatMap *entry;
guint i;
for (i = 0; i < formats->len; i++) {
entry = &g_array_index (formats, GstVideoFormatMap, i);
if (va_format_is_same (&entry->va_format, va_format))
return entry;
}
return NULL;
}
static guint
get_fmt_score_in_default (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map_in_default_by_gst_format (format);
return m ? (m - &gst_vaapi_video_default_formats[0]) : G_MAXUINT;
}
static gint
video_format_compare_by_score (gconstpointer a, gconstpointer b)
{
const GstVideoFormatMap *m1 = (GstVideoFormatMap *) a;
const GstVideoFormatMap *m2 = (GstVideoFormatMap *) b;
return ((gint) get_fmt_score_in_default (m1->format) -
(gint) get_fmt_score_in_default (m2->format));
}
/**
* gst_vaapi_video_format_to_string:
* @format: a #GstVideoFormat
@ -166,8 +304,8 @@ gst_vaapi_video_format_to_string (GstVideoFormat format)
gboolean
gst_vaapi_video_format_is_rgb (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map (format);
const GstVideoFormatMap *const m =
get_map_by_gst_format (gst_vaapi_video_formats_map, format);
return m && va_format_is_rgb (&m->va_format);
}
@ -182,8 +320,8 @@ gst_vaapi_video_format_is_rgb (GstVideoFormat format)
gboolean
gst_vaapi_video_format_is_yuv (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map (format);
const GstVideoFormatMap *const m =
get_map_by_gst_format (gst_vaapi_video_formats_map, format);
return m && va_format_is_yuv (&m->va_format);
}
@ -199,12 +337,15 @@ gst_vaapi_video_format_is_yuv (GstVideoFormat format)
GstVideoFormat
gst_vaapi_video_format_from_va_fourcc (guint32 fourcc)
{
const GArray *map = gst_vaapi_video_formats_map;
const GstVideoFormatMap *m;
guint i;
/* Note: VA fourcc values are now standardized and shall represent
a unique format. The associated VAImageFormat is just a hint to
determine RGBA component ordering */
for (m = gst_vaapi_video_formats; m->format; m++) {
for (i = 0; i < map->len; i++) {
m = &g_array_index (map, GstVideoFormatMap, i);
if (m->va_format.fourcc == fourcc)
return m->format;
}
@ -224,13 +365,8 @@ gst_vaapi_video_format_from_va_fourcc (guint32 fourcc)
GstVideoFormat
gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format)
{
const GstVideoFormatMap *m;
for (m = gst_vaapi_video_formats; m->format; m++) {
if (va_format_is_same (&m->va_format, va_format))
return m->format;
}
return GST_VIDEO_FORMAT_UNKNOWN;
const GstVideoFormatMap *const m = get_map_by_va_format (va_format);
return m ? m->format : GST_VIDEO_FORMAT_UNKNOWN;
}
/**
@ -246,8 +382,8 @@ gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format)
const VAImageFormat *
gst_vaapi_video_format_to_va_format (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map (format);
const GstVideoFormatMap *const m =
get_map_by_gst_format (gst_vaapi_video_formats_map, format);
return m ? &m->va_format : NULL;
}
@ -264,8 +400,8 @@ gst_vaapi_video_format_to_va_format (GstVideoFormat format)
guint
gst_vaapi_video_format_get_chroma_type (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map (format);
const GstVideoFormatMap *const m =
get_map_by_gst_format (gst_vaapi_video_formats_map, format);
return m ? m->chroma_type : 0;
}
@ -281,9 +417,7 @@ gst_vaapi_video_format_get_chroma_type (GstVideoFormat format)
guint
gst_vaapi_video_format_get_score (GstVideoFormat format)
{
const GstVideoFormatMap *const m = get_map (format);
return m ? (m - &gst_vaapi_video_formats[0]) : G_MAXUINT;
return get_fmt_score_in_default (format);
}
/**
@ -336,7 +470,98 @@ gst_vaapi_video_format_get_best_native (GstVideoFormat format)
if (format == GST_VIDEO_FORMAT_ENCODED)
return GST_VIDEO_FORMAT_NV12;
chroma_type = gst_vaapi_video_format_get_chroma_type (format);
return gst_vaapi_video_format_from_chroma (chroma_type);
}
struct ImageFormatsData
{
VAImageFormat *formats;
guint n;
};
static gpointer
video_format_create_map_once (gpointer data)
{
const GstVideoFormatMap *src_entry, *entry;
guint i;
VAImageFormat *formats = ((struct ImageFormatsData *) data)->formats;
guint n = ((struct ImageFormatsData *) data)->n;
GArray *array = NULL;
if (formats == NULL || n == 0)
return NULL;
array = g_array_new (FALSE, TRUE, sizeof (GstVideoFormatMap));
if (array == NULL)
return NULL;
for (i = 0; i < n; i++) {
src_entry = get_map_in_default_by_va_format (&formats[i]);
if (src_entry) {
entry = get_map_by_gst_format (array, src_entry->format);
if (entry && !va_format_is_same (&entry->va_format, &formats[i])) {
GST_INFO ("va_format1 with fourcc %" GST_FOURCC_FORMAT
" byte order: %d, BPP: %d, depth %d, red mask 0x%4x,"
" green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x"
" conflict with va_foramt2 fourcc %" GST_FOURCC_FORMAT
" byte order: %d, BPP: %d, depth %d, red mask 0x%4x,"
" green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x."
" Both map to the same GST format: %s, which is not"
" allowed, va_format1 will be skipped",
GST_FOURCC_ARGS (entry->va_format.fourcc),
entry->va_format.byte_order, entry->va_format.bits_per_pixel,
entry->va_format.depth, entry->va_format.red_mask,
entry->va_format.green_mask, entry->va_format.blue_mask,
entry->va_format.alpha_mask,
GST_FOURCC_ARGS (formats[i].fourcc),
formats[i].byte_order, formats[i].bits_per_pixel, formats[i].depth,
formats[i].red_mask, formats[i].green_mask, formats[i].blue_mask,
formats[i].alpha_mask, gst_video_format_to_string (entry->format));
continue;
}
g_array_append_val (array, (*src_entry));
}
if (va_format_is_rgb (&formats[i])) {
GST_LOG ("%s to map RGB va_format with fourcc: %"
GST_FOURCC_FORMAT
", byte order: %d BPP: %d, depth %d, red mask %4x,"
" green mask %4x, blue mask %4x, alpha mask %4x to %s gstreamer"
" video format", src_entry ? "succeed" : "failed",
GST_FOURCC_ARGS (formats[i].fourcc), formats[i].byte_order,
formats[i].bits_per_pixel, formats[i].depth, formats[i].red_mask,
formats[i].green_mask, formats[i].blue_mask, formats[i].alpha_mask,
src_entry ? gst_video_format_to_string (src_entry->format) : "any");
} else {
GST_LOG ("%s to map YUV va format with fourcc: %"
GST_FOURCC_FORMAT ", byte order: %d BPP: %d to %s gstreamer"
" video format", src_entry ? "succeed" : "failed",
GST_FOURCC_ARGS (formats[i].fourcc), formats[i].byte_order,
formats[i].bits_per_pixel,
src_entry ? gst_video_format_to_string (src_entry->format) : "any");
}
}
g_array_sort (array, video_format_compare_by_score);
gst_vaapi_video_formats_map = array;
return array;
}
/**
* gst_vaapi_video_format_new_map:
* @formats: all #VAImageFormat need to map
* @n: the number of VAImageFormat
*
* Return: True if create successfully.
**/
gboolean
gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n)
{
static GOnce once = G_ONCE_INIT;
struct ImageFormatsData data = { formats, n };
g_once (&once, video_format_create_map_once, &data);
return once.retval != NULL;
}

View file

@ -59,6 +59,9 @@ gst_vaapi_video_format_from_chroma (guint chroma);
GstVideoFormat
gst_vaapi_video_format_get_best_native (GstVideoFormat format);
gboolean
gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n);
G_END_DECLS
#endif /* GST_VAAPI_VIDEO_FORMAT_H */