mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
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:
parent
97d62d2291
commit
4b07d54931
5 changed files with 1858 additions and 123 deletions
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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 (format != GST_VIDEO_FORMAT_UNKNOWN) {
|
||||||
|
GstCaps *simple_caps;
|
||||||
|
|
||||||
|
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)) {
|
if (!gst_caps_is_empty (size_caps)) {
|
||||||
tmp = caps;
|
tmp = simple_caps;
|
||||||
caps = gst_caps_intersect_full (tmp, size_caps, GST_CAPS_INTERSECT_FIRST);
|
simple_caps =
|
||||||
|
gst_caps_intersect_full (tmp, size_caps, GST_CAPS_INTERSECT_FIRST);
|
||||||
gst_caps_unref (tmp);
|
gst_caps_unref (tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Add a V4L2 to DRM fourcc translator for formats that we don't support
|
caps = gst_caps_merge (simple_caps, caps);
|
||||||
* in software.
|
}
|
||||||
*/
|
|
||||||
drm_fourcc = gst_video_dma_drm_format_from_gst_format (format, &modifier);
|
if (drm_fourcc != DRM_FORMAT_INVALID) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "Selected format %s %ix%i",
|
// Non-DMA_DRM caps, clean VideoInfo.
|
||||||
gst_video_format_to_string (format), tmp_vinfo_drm.vinfo.width,
|
vinfo_drm->drm_fourcc = DRM_FORMAT_INVALID;
|
||||||
tmp_vinfo_drm.vinfo.height);
|
vinfo_drm->drm_modifier = DRM_FORMAT_MOD_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_INFO_OBJECT (self,
|
||||||
|
"Selected format %s DRM %" GST_FOURCC_FORMAT ":0x%016" G_GINT64_MODIFIER
|
||||||
|
"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 {
|
||||||
|
|
|
@ -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 ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
g_once_init_leave (&once, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
1588
subprojects/gst-plugins-bad/sys/v4l2codecs/linux/drm_fourcc.h
Normal file
1588
subprojects/gst-plugins-bad/sys/v4l2codecs/linux/drm_fourcc.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue