v4l2codecs: decoder: Translate V4L2 formats into DRM fourcc/mod pairs

V4L2 and DRM choose different, incompatible ways to represent
tiled/compressed etc. formats. While the later uses combinations of
format fourccs and opaque, vendor/hardware specific modifiers, for the
later every such combination is a distinct new format.

Traditionally Gst implemented each of the V4L2 formats if needed.
Given the large number of tiling and compression modes, this is
quite work intensive - and often actually not needed.
In many situations Gst just needs to pass buffers from V4L2 to DRM in
the form of EGL, VK, Wayland or KMS.

Thus implement a direct translation for some V4L2 formats to DRM ones,
limited to the DMA_DRM API, allowing much quicker enablement of formats
while requiring peers to use external implementations (usually Mesa or
KMS) for tiling etc.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7355>
This commit is contained in:
Robert Mader 2024-08-14 02:11:06 +02:00 committed by GStreamer Marge Bot
parent 97d62d2291
commit 4b07d54931
5 changed files with 1858 additions and 123 deletions

View file

@ -19,6 +19,7 @@
*/ */
#include "gstv4l2codecpool.h" #include "gstv4l2codecpool.h"
#include "gstv4l2format.h"
#include <string.h> #include <string.h>
@ -88,7 +89,7 @@ gst_v4l2_codec_pool_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer,
vmeta->format = GST_VIDEO_INFO_FORMAT (&self->vinfo_drm->vinfo); vmeta->format = GST_VIDEO_INFO_FORMAT (&self->vinfo_drm->vinfo);
vmeta->width = GST_VIDEO_INFO_WIDTH (&self->vinfo_drm->vinfo); vmeta->width = GST_VIDEO_INFO_WIDTH (&self->vinfo_drm->vinfo);
vmeta->height = GST_VIDEO_INFO_HEIGHT (&self->vinfo_drm->vinfo); vmeta->height = GST_VIDEO_INFO_HEIGHT (&self->vinfo_drm->vinfo);
vmeta->n_planes = GST_VIDEO_INFO_N_PLANES (&self->vinfo_drm->vinfo); vmeta->n_planes = gst_v4l2_format_get_n_planes (self->vinfo_drm);
memcpy (vmeta->offset, self->vinfo_drm->vinfo.offset, sizeof (vmeta->offset)); memcpy (vmeta->offset, self->vinfo_drm->vinfo.offset, sizeof (vmeta->offset));
memcpy (vmeta->stride, self->vinfo_drm->vinfo.stride, sizeof (vmeta->stride)); memcpy (vmeta->stride, self->vinfo_drm->vinfo.stride, sizeof (vmeta->stride));

View file

@ -25,6 +25,7 @@
#include "gstv4l2codecpool.h" #include "gstv4l2codecpool.h"
#include "gstv4l2decoder.h" #include "gstv4l2decoder.h"
#include "gstv4l2format.h" #include "gstv4l2format.h"
#include "linux/drm_fourcc.h"
#include "linux/media.h" #include "linux/media.h"
#include "linux/videodev2.h" #include "linux/videodev2.h"
@ -36,10 +37,6 @@
#include <gst/base/base.h> #include <gst/base/base.h>
#define DRM_FORMAT_INVALID 0
#define DRM_FORMAT_MOD_LINEAR 0ULL
#define DRM_FORMAT_MOD_INVALID 0xffffffffffffffULL
#define IMAGE_MINSZ (256*1024) /* 256kB */ #define IMAGE_MINSZ (256*1024) /* 256kB */
GST_DEBUG_CATEGORY (v4l2_decoder_debug); GST_DEBUG_CATEGORY (v4l2_decoder_debug);
@ -391,9 +388,7 @@ gst_v4l2_decoder_enum_size_for_format (GstV4l2Decoder * self,
guint32 pixelformat, gint index, gint unscaled_width, gint unscaled_height) guint32 pixelformat, gint index, gint unscaled_width, gint unscaled_height)
{ {
struct v4l2_frmsizeenum size; struct v4l2_frmsizeenum size;
GstVideoFormat format;
gint ret; gint ret;
gboolean res;
memset (&size, 0, sizeof (struct v4l2_frmsizeenum)); memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
size.index = index; size.index = index;
@ -421,9 +416,6 @@ gst_v4l2_decoder_enum_size_for_format (GstV4l2Decoder * self,
return NULL; return NULL;
} }
res = gst_v4l2_format_to_video_format (pixelformat, &format);
g_assert (res);
GST_DEBUG_OBJECT (self, "get size (%d x %d) index %d for %" GST_FOURCC_FORMAT, GST_DEBUG_OBJECT (self, "get size (%d x %d) index %d for %" GST_FOURCC_FORMAT,
size.discrete.width, size.discrete.height, index, size.discrete.width, size.discrete.height, index,
GST_FOURCC_ARGS (pixelformat)); GST_FOURCC_ARGS (pixelformat));
@ -446,11 +438,16 @@ gst_v4l2_decoder_probe_caps_for_format (GstV4l2Decoder * self,
GST_DEBUG_OBJECT (self, "enumerate size for %" GST_FOURCC_FORMAT, GST_DEBUG_OBJECT (self, "enumerate size for %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (pixelformat)); GST_FOURCC_ARGS (pixelformat));
if (!gst_v4l2_format_to_video_format (pixelformat, &format)) caps = gst_caps_new_empty ();
return gst_caps_new_empty (); if (!gst_v4l2_format_to_video_format (pixelformat, &format) ||
!gst_v4l2_format_to_drm_format (pixelformat, &drm_fourcc, &modifier)) {
return caps;
}
caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, GST_DEBUG_OBJECT (self,
gst_video_format_to_string (format), NULL); "got format %s DRM %" GST_FOURCC_FORMAT ":0x%016" G_GINT64_MODIFIER "x",
gst_video_format_to_string (format), GST_FOURCC_ARGS (drm_fourcc),
modifier);
size_caps = gst_caps_new_simple ("video/x-raw", size_caps = gst_caps_new_simple ("video/x-raw",
"width", G_TYPE_INT, unscaled_width, "width", G_TYPE_INT, unscaled_width,
@ -460,17 +457,23 @@ gst_v4l2_decoder_probe_caps_for_format (GstV4l2Decoder * self,
size_caps = gst_caps_merge (size_caps, tmp); size_caps = gst_caps_merge (size_caps, tmp);
} }
if (!gst_caps_is_empty (size_caps)) { if (format != GST_VIDEO_FORMAT_UNKNOWN) {
tmp = caps; GstCaps *simple_caps;
caps = gst_caps_intersect_full (tmp, size_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp); simple_caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING,
gst_video_format_to_string (format), NULL);
if (!gst_caps_is_empty (size_caps)) {
tmp = simple_caps;
simple_caps =
gst_caps_intersect_full (tmp, size_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (tmp);
}
caps = gst_caps_merge (simple_caps, caps);
} }
/* TODO: Add a V4L2 to DRM fourcc translator for formats that we don't support if (drm_fourcc != DRM_FORMAT_INVALID) {
* in software.
*/
drm_fourcc = gst_video_dma_drm_format_from_gst_format (format, &modifier);
if (drm_fourcc /* != DRM_FORMAT_INVALID */ ) {
GstCaps *drm_caps; GstCaps *drm_caps;
gchar *drm_format_str = gchar *drm_format_str =
gst_video_dma_drm_fourcc_to_string (drm_fourcc, modifier); gst_video_dma_drm_fourcc_to_string (drm_fourcc, modifier);
@ -665,15 +668,22 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
} }
format = tmp_vinfo_drm.vinfo.finfo->format; format = tmp_vinfo_drm.vinfo.finfo->format;
if (!gst_v4l2_format_from_video_format (format, &pix_fmt)) { if (!gst_v4l2_format_from_drm_format (tmp_vinfo_drm.drm_fourcc,
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT, tmp_vinfo_drm.drm_modifier, &pix_fmt) &&
GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat)); !gst_v4l2_format_from_video_format (format, &pix_fmt)) {
GST_ERROR_OBJECT (self,
"Unsupported format %s DRM %" GST_FOURCC_FORMAT ":0x%016"
G_GINT64_MODIFIER "x", gst_video_format_to_string (format),
GST_FOURCC_ARGS (tmp_vinfo_drm.drm_fourcc), tmp_vinfo_drm.drm_modifier);
return FALSE; return FALSE;
} }
if (pix_fmt != fmt.fmt.pix_mp.pixelformat) { if (pix_fmt != fmt.fmt.pix_mp.pixelformat) {
GST_WARNING_OBJECT (self, "Trying to use peer format: %s", GST_WARNING_OBJECT (self,
gst_video_format_to_string (format)); "Trying to use peer format: %s V4L2 %" GST_FOURCC_FORMAT " DRM %"
GST_FOURCC_FORMAT ":0x%016" G_GINT64_MODIFIER "x",
gst_video_format_to_string (format), GST_FOURCC_ARGS (pix_fmt),
GST_FOURCC_ARGS (tmp_vinfo_drm.drm_fourcc), tmp_vinfo_drm.drm_modifier);
fmt.fmt.pix_mp.pixelformat = pix_fmt; fmt.fmt.pix_mp.pixelformat = pix_fmt;
ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt); ret = ioctl (self->video_fd, VIDIOC_S_FMT, &fmt);
@ -683,23 +693,31 @@ gst_v4l2_decoder_select_src_format (GstV4l2Decoder * self, GstCaps * caps,
} }
} }
if (!gst_v4l2_format_to_video_info (&fmt, &vinfo_drm->vinfo)) { if (!gst_v4l2_format_to_dma_drm_info (&fmt, vinfo_drm)) {
GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT, GST_ERROR_OBJECT (self, "Unsupported V4L2 pixelformat %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat)); GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat));
return FALSE; return FALSE;
} }
vinfo_drm->drm_fourcc = DRM_FORMAT_INVALID; if (tmp_vinfo_drm.drm_fourcc == DRM_FORMAT_INVALID) {
vinfo_drm->drm_modifier = DRM_FORMAT_MOD_INVALID; if (vinfo_drm->vinfo.finfo->format == GST_VIDEO_FORMAT_DMA_DRM) {
if (tmp_vinfo_drm.drm_fourcc) { GST_ERROR_OBJECT (self,
vinfo_drm->drm_fourcc = "V4L2 pixelformat %" GST_FOURCC_FORMAT
gst_video_dma_drm_format_from_gst_format (tmp_vinfo_drm.vinfo. " only supported with DMA_DRM caps but non-DMA_DRM caps requested.",
finfo->format, &vinfo_drm->drm_modifier); GST_FOURCC_ARGS (fmt.fmt.pix_mp.pixelformat));
return FALSE;
}
// Non-DMA_DRM caps, clean VideoInfo.
vinfo_drm->drm_fourcc = DRM_FORMAT_INVALID;
vinfo_drm->drm_modifier = DRM_FORMAT_MOD_INVALID;
} }
GST_INFO_OBJECT (self, "Selected format %s %ix%i", GST_INFO_OBJECT (self,
gst_video_format_to_string (format), tmp_vinfo_drm.vinfo.width, "Selected format %s DRM %" GST_FOURCC_FORMAT ":0x%016" G_GINT64_MODIFIER
tmp_vinfo_drm.vinfo.height); "x %ix%i", gst_video_format_to_string (format),
GST_FOURCC_ARGS (vinfo_drm->drm_fourcc), vinfo_drm->drm_modifier,
vinfo_drm->vinfo.width, vinfo_drm->vinfo.height);
return TRUE; return TRUE;
} }
@ -716,11 +734,12 @@ gst_v4l2_decoder_set_output_state (GstVideoDecoder * decoder,
vinfo_drm->vinfo.finfo->format, width, height, reference); vinfo_drm->vinfo.finfo->format, width, height, reference);
if (vinfo_drm->drm_fourcc /* != DRM_FORMAT_INVALID */ ) { if (vinfo_drm->drm_fourcc /* != DRM_FORMAT_INVALID */ ) {
GstVideoInfoDmaDrm tmp_vinfo_drm = *vinfo_drm; GstVideoInfoDmaDrm tmp_vinfo_drm;
/* Use display width/height in output caps */ gst_video_info_dma_drm_init (&tmp_vinfo_drm);
tmp_vinfo_drm.vinfo.width = width; tmp_vinfo_drm.vinfo = state->info;
tmp_vinfo_drm.vinfo.height = height; tmp_vinfo_drm.drm_fourcc = vinfo_drm->drm_fourcc;
tmp_vinfo_drm.drm_modifier = vinfo_drm->drm_modifier;
state->caps = gst_video_info_dma_drm_to_caps (&tmp_vinfo_drm); state->caps = gst_video_info_dma_drm_to_caps (&tmp_vinfo_drm);
} else { } else {

View file

@ -19,121 +19,178 @@
#include "gstv4l2format.h" #include "gstv4l2format.h"
#include "linux/drm_fourcc.h"
#define GST_CAT_DEFAULT gstv4l2codecs_debug #define GST_CAT_DEFAULT gstv4l2codecs_debug
GST_DEBUG_CATEGORY_EXTERN (gstv4l2codecs_debug); GST_DEBUG_CATEGORY_EXTERN (gstv4l2codecs_debug);
struct FormatEntry typedef struct
{ {
guint32 v4l2_pix_fmt; guint32 v4l2_pix_fmt;
gint num_planes;
GstVideoFormat gst_fmt; GstVideoFormat gst_fmt;
guint bitdepth; guint32 drm_fourcc;
gint subsampling; guint64 drm_modifier;
}; gint num_planes;
} GstV4l2FormatDesc;
static struct FormatEntry format_map[] = { /* *INDENT-OFF* */
{V4L2_PIX_FMT_NV12, 1, GST_VIDEO_FORMAT_NV12, 8, 420}, static const GstV4l2FormatDesc gst_v4l2_descriptions[] = {
{V4L2_PIX_FMT_YUYV, 1, GST_VIDEO_FORMAT_YUY2, 8, 422}, {V4L2_PIX_FMT_MM21, GST_VIDEO_FORMAT_NV12_16L32S, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_SUNXI_TILED_NV12, 1, GST_VIDEO_FORMAT_NV12_32L32, 8, 422}, {V4L2_PIX_FMT_MT2110T, GST_VIDEO_FORMAT_MT2110T, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_NV12_4L4, 1, GST_VIDEO_FORMAT_NV12_4L4, 8, 420}, {V4L2_PIX_FMT_MT2110R, GST_VIDEO_FORMAT_MT2110R, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_MM21, 2, GST_VIDEO_FORMAT_NV12_16L32S, 8, 420}, {V4L2_PIX_FMT_NV12, GST_VIDEO_FORMAT_NV12, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_YUV420M, 3, GST_VIDEO_FORMAT_I420, 8, 420}, {V4L2_PIX_FMT_NV12_4L4, GST_VIDEO_FORMAT_NV12_4L4, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_P010, 1, GST_VIDEO_FORMAT_P010_10LE, 16, 420}, {V4L2_PIX_FMT_NV15_4L4, GST_VIDEO_FORMAT_NV12_10LE40_4L4, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_NV15_4L4, 1, GST_VIDEO_FORMAT_NV12_10LE40_4L4, 10, 420}, {V4L2_PIX_FMT_P010, GST_VIDEO_FORMAT_P010_10LE, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_MT2110T, 2, GST_VIDEO_FORMAT_MT2110T, 10, 420}, {V4L2_PIX_FMT_SUNXI_TILED_NV12, GST_VIDEO_FORMAT_NV12_32L32, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{V4L2_PIX_FMT_MT2110R, 2, GST_VIDEO_FORMAT_MT2110R, 10, 420}, {V4L2_PIX_FMT_YUV420M, GST_VIDEO_FORMAT_I420, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
{0,} {V4L2_PIX_FMT_YUYV, GST_VIDEO_FORMAT_YUY2, DRM_FORMAT_INVALID, DRM_FORMAT_MOD_INVALID, 0},
}; };
/* *INDENT-ON* */
#define GST_V4L2_FORMAT_DESC_COUNT (G_N_ELEMENTS (gst_v4l2_descriptions))
static struct FormatEntry * static const GstV4l2FormatDesc *
lookup_v4l2_fmt (guint v4l2_pix_fmt) gst_v4l2_format_get_descriptions (void)
{ {
gint i; static GstV4l2FormatDesc v4l2_descs[GST_V4L2_FORMAT_DESC_COUNT];
struct FormatEntry *ret = NULL; static gsize once = 0;
for (i = 0; format_map[i].v4l2_pix_fmt; i++) { if (g_once_init_enter (&once)) {
if (format_map[i].v4l2_pix_fmt == v4l2_pix_fmt) { for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) {
ret = format_map + i; v4l2_descs[i].v4l2_pix_fmt = gst_v4l2_descriptions[i].v4l2_pix_fmt;
break; if (gst_v4l2_descriptions[i].gst_fmt != GST_VIDEO_FORMAT_UNKNOWN) {
const GstVideoFormatInfo *info;
guint64 drm_modifier;
v4l2_descs[i].gst_fmt = gst_v4l2_descriptions[i].gst_fmt;
v4l2_descs[i].drm_fourcc =
gst_video_dma_drm_format_from_gst_format (gst_v4l2_descriptions
[i].gst_fmt, &drm_modifier);
v4l2_descs[i].drm_modifier = drm_modifier;
info = gst_video_format_get_info (gst_v4l2_descriptions[i].gst_fmt);
v4l2_descs[i].num_planes = GST_VIDEO_FORMAT_INFO_N_PLANES (info);
} else if (gst_v4l2_descriptions[i].drm_fourcc != DRM_FORMAT_INVALID &&
gst_v4l2_descriptions[i].num_planes > 0) {
v4l2_descs[i].gst_fmt = GST_VIDEO_FORMAT_DMA_DRM;
v4l2_descs[i].drm_fourcc = gst_v4l2_descriptions[i].drm_fourcc;
v4l2_descs[i].drm_modifier = gst_v4l2_descriptions[i].drm_modifier;
v4l2_descs[i].num_planes = gst_v4l2_descriptions[i].num_planes;
} else {
g_assert_not_reached ();
}
} }
g_once_init_leave (&once, 1);
} }
return ret; return v4l2_descs;
} }
static struct FormatEntry * static const GstV4l2FormatDesc *
lookup_gst_fmt (GstVideoFormat gst_fmt) gst_v4l2_lookup_pix_format (guint32 pix_format)
{ {
gint i; const GstV4l2FormatDesc *fmt_descs = gst_v4l2_format_get_descriptions ();
struct FormatEntry *ret = NULL;
for (i = 0; format_map[i].v4l2_pix_fmt; i++) { for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) {
if (format_map[i].gst_fmt == gst_fmt) { if (fmt_descs[i].v4l2_pix_fmt == pix_format)
ret = format_map + i; return &fmt_descs[i];
break;
}
} }
return NULL;
}
return ret; static const GstV4l2FormatDesc *
gst_v4l2_lookup_drm_format (guint32 drm_fourcc, guint64 drm_modifier)
{
const GstV4l2FormatDesc *fmt_descs = gst_v4l2_format_get_descriptions ();
if (drm_fourcc == DRM_FORMAT_INVALID)
return NULL;
for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) {
if (fmt_descs[i].drm_fourcc == drm_fourcc &&
fmt_descs[i].drm_modifier == drm_modifier)
return &fmt_descs[i];
}
return NULL;
}
static const GstV4l2FormatDesc *
gst_v4l2_loopup_video_format (GstVideoFormat gst_format)
{
const GstV4l2FormatDesc *fmt_descs = gst_v4l2_format_get_descriptions ();
if (gst_format == GST_VIDEO_FORMAT_UNKNOWN ||
gst_format == GST_VIDEO_FORMAT_DMA_DRM)
return NULL;
for (int i = 0; i < GST_V4L2_FORMAT_DESC_COUNT; i++) {
if (fmt_descs[i].gst_fmt == gst_format)
return &fmt_descs[i];
}
return NULL;
} }
static void static void
set_stride (GstVideoInfo * info, gint plane, gint stride) set_stride (GstVideoInfoDmaDrm * info, gint plane, gint stride)
{ {
const GstVideoFormatInfo *finfo = info->finfo; const GstVideoFormatInfo *finfo = info->vinfo.finfo;
if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo)) { if (GST_VIDEO_FORMAT_INFO_IS_TILED (finfo) &&
info->drm_modifier == DRM_FORMAT_MOD_INVALID) {
guint x_tiles, y_tiles, tile_height, padded_height; guint x_tiles, y_tiles, tile_height, padded_height;
tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (finfo, plane); tile_height = GST_VIDEO_FORMAT_INFO_TILE_HEIGHT (finfo, plane);
padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane, padded_height = GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (finfo, plane,
info->height); info->vinfo.height);
x_tiles = stride / GST_VIDEO_FORMAT_INFO_TILE_STRIDE (finfo, plane); x_tiles = stride / GST_VIDEO_FORMAT_INFO_TILE_STRIDE (finfo, plane);
y_tiles = (padded_height + tile_height - 1) / tile_height; y_tiles = (padded_height + tile_height - 1) / tile_height;
info->stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles); info->vinfo.stride[plane] = GST_VIDEO_TILE_MAKE_STRIDE (x_tiles, y_tiles);
} else { } else {
info->stride[plane] = stride; info->vinfo.stride[plane] = stride;
} }
} }
gboolean gboolean
gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info) gst_v4l2_format_to_dma_drm_info (struct v4l2_format *fmt,
GstVideoInfoDmaDrm * out_drm_info)
{ {
struct FormatEntry *entry = lookup_v4l2_fmt (fmt->fmt.pix_mp.pixelformat);
struct v4l2_pix_format_mplane *pix_mp = &fmt->fmt.pix_mp; struct v4l2_pix_format_mplane *pix_mp = &fmt->fmt.pix_mp;
struct v4l2_pix_format *pix = &fmt->fmt.pix; struct v4l2_pix_format *pix = &fmt->fmt.pix;
gint n_planes;
gint plane; gint plane;
gsize offset = 0; gsize offset = 0;
gboolean extrapolate = FALSE; gboolean extrapolate = FALSE;
GstVideoFormat format;
guint32 drm_fourcc;
guint64 drm_mod;
if (!entry) if (!gst_v4l2_format_to_video_format (pix_mp->pixelformat, &format) ||
!gst_v4l2_format_to_drm_format (pix_mp->pixelformat, &drm_fourcc,
&drm_mod))
return FALSE; return FALSE;
/* validate the entry against the format */ g_return_val_if_fail (format != GST_VIDEO_FORMAT_DMA_DRM
if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { || drm_fourcc != DRM_FORMAT_INVALID, FALSE);
if (entry->num_planes != pix_mp->num_planes) {
GST_ERROR ("Miss-matched number of planes in internal entry "
"(%i != %i)", entry->num_planes, pix_mp->num_planes);
return FALSE;
}
} else if (entry->num_planes != 1) {
GST_ERROR ("Miss-matched number of planes in internal entry "
"(must be 1 for non-multiplanar, got %i)", entry->num_planes);
return FALSE;
}
if (!gst_video_info_set_format (out_info, entry->gst_fmt, gst_video_info_dma_drm_init (out_drm_info);
pix_mp->width, pix_mp->height)) out_drm_info->vinfo.finfo = gst_video_format_get_info (format);
return FALSE;
out_drm_info->vinfo.width = pix_mp->width;
out_drm_info->vinfo.height = pix_mp->height;
out_drm_info->drm_fourcc = drm_fourcc;
out_drm_info->drm_modifier = drm_mod;
if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) {
out_info->size = 0; out_drm_info->vinfo.size = 0;
for (plane = 0; plane < pix_mp->num_planes; plane++) for (plane = 0; plane < pix_mp->num_planes; plane++)
out_info->size += pix_mp->plane_fmt[plane].sizeimage; out_drm_info->vinfo.size += pix_mp->plane_fmt[plane].sizeimage;
n_planes = pix_mp->num_planes;
} else { } else {
out_info->size = pix->sizeimage; out_drm_info->vinfo.size = pix->sizeimage;
n_planes = 1;
} }
/* /*
@ -141,38 +198,45 @@ gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info)
* extrapolate the per-plane stride. Do this check once to prevent * extrapolate the per-plane stride. Do this check once to prevent
* complex inner loop. * complex inner loop.
*/ */
if (entry->num_planes == 1 && out_info->finfo->n_planes != entry->num_planes) if (n_planes == 1 && gst_v4l2_format_get_n_planes (out_drm_info) != n_planes)
extrapolate = TRUE; extrapolate = TRUE;
for (plane = 0; plane < GST_VIDEO_INFO_N_PLANES (out_info); plane++) { g_return_val_if_fail (format != GST_VIDEO_FORMAT_DMA_DRM
|| drm_mod == DRM_FORMAT_MOD_LINEAR || !extrapolate, FALSE);
for (plane = 0; plane < gst_v4l2_format_get_n_planes (out_drm_info); plane++) {
gint stride; gint stride;
if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) { if (V4L2_TYPE_IS_MULTIPLANAR (fmt->type)) {
if (extrapolate) if (extrapolate)
stride = gst_video_format_info_extrapolate_stride (out_info->finfo, stride =
gst_video_format_info_extrapolate_stride (out_drm_info->vinfo.finfo,
plane, pix_mp->plane_fmt[0].bytesperline); plane, pix_mp->plane_fmt[0].bytesperline);
else else
stride = pix_mp->plane_fmt[plane].bytesperline; stride = pix_mp->plane_fmt[plane].bytesperline;
} else { } else {
if (extrapolate) if (extrapolate)
stride = gst_video_format_info_extrapolate_stride (out_info->finfo, stride =
gst_video_format_info_extrapolate_stride (out_drm_info->vinfo.finfo,
plane, pix->bytesperline); plane, pix->bytesperline);
else else
stride = pix->bytesperline; stride = pix->bytesperline;
} }
set_stride (out_info, plane, stride); set_stride (out_drm_info, plane, stride);
out_info->offset[plane] = offset; out_drm_info->vinfo.offset[plane] = offset;
if ((V4L2_TYPE_IS_MULTIPLANAR (fmt->type) && !extrapolate)) if ((V4L2_TYPE_IS_MULTIPLANAR (fmt->type) && !extrapolate))
offset += pix_mp->plane_fmt[plane].sizeimage; offset += pix_mp->plane_fmt[plane].sizeimage;
else else
offset += stride * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_info->finfo, offset +=
plane, pix_mp->height); stride *
GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (out_drm_info->vinfo.finfo, plane,
pix_mp->height);
} }
/* Check that the extrapolation didn't overflow the reported sizeimage */ /* Check that the extrapolation didn't overflow the reported sizeimage */
if (extrapolate && offset > out_info->size) { if (extrapolate && offset > out_drm_info->vinfo.size) {
GST_ERROR ("Extrapolated plane offset overflow the image size."); GST_ERROR ("Extrapolated plane offset overflow the image size.");
return FALSE; return FALSE;
} }
@ -181,25 +245,78 @@ gst_v4l2_format_to_video_info (struct v4l2_format *fmt, GstVideoInfo * out_info)
} }
gboolean gboolean
gst_v4l2_format_to_video_format (guint32 pix_fmt, GstVideoFormat * out_format) gst_v4l2_format_to_video_format (guint32 pix_fmt, GstVideoFormat * out_gst_fmt)
{ {
struct FormatEntry *entry = lookup_v4l2_fmt (pix_fmt); const GstV4l2FormatDesc *fmt_desc;
if (!entry) fmt_desc = gst_v4l2_lookup_pix_format (pix_fmt);
if (!fmt_desc)
return FALSE; return FALSE;
*out_format = entry->gst_fmt; if (out_gst_fmt)
*out_gst_fmt = fmt_desc->gst_fmt;
return TRUE;
}
gboolean
gst_v4l2_format_to_drm_format (guint32 pix_fmt, guint32 * out_drm_fourcc,
guint64 * out_drm_mod)
{
const GstV4l2FormatDesc *fmt_desc;
fmt_desc = gst_v4l2_lookup_pix_format (pix_fmt);
if (!fmt_desc)
return FALSE;
if (out_drm_fourcc)
*out_drm_fourcc = fmt_desc->gst_fmt;
if (out_drm_mod)
*out_drm_mod = fmt_desc->drm_modifier;
return TRUE; return TRUE;
} }
gboolean gboolean
gst_v4l2_format_from_video_format (GstVideoFormat format, guint32 * out_pix_fmt) gst_v4l2_format_from_video_format (GstVideoFormat format, guint32 * out_pix_fmt)
{ {
struct FormatEntry *entry = lookup_gst_fmt (format); const GstV4l2FormatDesc *fmt_desc;
if (!entry) fmt_desc = gst_v4l2_loopup_video_format (format);
if (!fmt_desc)
return FALSE; return FALSE;
*out_pix_fmt = entry->v4l2_pix_fmt; if (out_pix_fmt)
*out_pix_fmt = fmt_desc->v4l2_pix_fmt;
return TRUE; return TRUE;
} }
gboolean
gst_v4l2_format_from_drm_format (guint32 drm_fourcc, guint64 drm_mod,
guint32 * out_pix_fmt)
{
const GstV4l2FormatDesc *fmt_desc;
fmt_desc = gst_v4l2_lookup_drm_format (drm_fourcc, drm_mod);
if (!fmt_desc)
return FALSE;
if (out_pix_fmt)
*out_pix_fmt = fmt_desc->v4l2_pix_fmt;
return TRUE;
}
guint
gst_v4l2_format_get_n_planes (GstVideoInfoDmaDrm * info)
{
const GstV4l2FormatDesc *fmt_desc;
fmt_desc = gst_v4l2_loopup_video_format (info->vinfo.finfo->format);
if (fmt_desc)
return fmt_desc->num_planes;
fmt_desc = gst_v4l2_lookup_drm_format (info->drm_fourcc, info->drm_modifier);
if (fmt_desc)
return fmt_desc->num_planes;
g_warn_if_reached ();
return 0;
}

View file

@ -29,13 +29,23 @@
"NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420" \ "NV12, YUY2, NV12_4L4, NV12_32L32, NV12_16L32S, I420" \
"}" "}"
gboolean gst_v4l2_format_to_video_info (struct v4l2_format * fmt, gboolean gst_v4l2_format_to_dma_drm_info (struct v4l2_format * fmt,
GstVideoInfo * out_info); GstVideoInfoDmaDrm * out_drm_info);
gboolean gst_v4l2_format_to_video_format (guint32 pix_fmt, gboolean gst_v4l2_format_to_video_format (guint32 pix_fmt,
GstVideoFormat * out_format); GstVideoFormat * out_format);
gboolean gst_v4l2_format_to_drm_format (guint32 pix_fmt,
guint32 * out_drm_fourcc,
guint64 * out_drm_mod);
gboolean gst_v4l2_format_from_video_format (GstVideoFormat format, gboolean gst_v4l2_format_from_video_format (GstVideoFormat format,
guint32 * out_pix_fmt); guint32 * out_pix_fmt);
gboolean gst_v4l2_format_from_drm_format (guint32 drm_fourcc,
guint64 drm_mod,
guint32 * out_pix_fmt);
guint gst_v4l2_format_get_n_planes (GstVideoInfoDmaDrm * info);
#endif /* __GST_V4L2_FORMAT_H__ */ #endif /* __GST_V4L2_FORMAT_H__ */

File diff suppressed because it is too large Load diff