diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml index fd4605f..e4eb95e 100644 --- a/.github/workflows/build-tests.yml +++ b/.github/workflows/build-tests.yml @@ -66,7 +66,7 @@ jobs: cd "${GITHUB_WORKSPACE}/hal" mkdir -p build && cd build - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ../src/hal/hal_adaptor + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib -DBUILD_CAMHAL_ADAPTOR=ON -DBUILD_CAMHAL_PLUGIN=ON -DIPU_VERSIONS="ipu6;ipu6ep;ipu6epmtl" -DUSE_PG_LITE_PIPE=ON .. make -j$(nproc) install - uses: actions/checkout@v3 @@ -77,18 +77,6 @@ jobs: env: CHROME_SLIM_CAMHAL: ON run: | - case "${{ matrix.os }}" in - ("ubuntu:24.04") - fortify_level=3 - ;; - ("ubuntu:22.04"|"ubuntu:20.04") - fortify_level=2 - ;; - (*) - echo "${{ matrix.os }} is unsupported yet. Please find the default fortify_level in /usr/share/perl5/Dpkg/Vendor/Ubuntu.pm or /usr/share/perl5/Dpkg/Vendor/Debian.pm." - exit 1 - ;; - esac cd "${GITHUB_WORKSPACE}/icamerasrc" - CPPFLAGS="-D_FORTIFY_SOURCE=$fortify_level" ./autogen.sh && make -j$(nproc) install + ./autogen.sh && make -j$(nproc) install diff --git a/README.md b/README.md index 3a68aa4..b98f2d5 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,13 @@ This repository supports MIPI cameras through the IPU6/IPU6EP/IPU6SE on Intel Ti ## Build instructions: * Prerequisites: ipu6-camera-bins and ipu6-camera-hal installed -* Prerequisites: libdrm-dev +* Prerequisites: libdrm-dev libva-dev libgstreamer-plugins-bad1.0-dev ```sh export CHROME_SLIM_CAMHAL=ON -# for libdrm.pc -export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig" -# only for yocto -export PKG_CONFIG_PATH="/usr/lib/pkgconfig" ./autogen.sh -make -j8 +./configure --prefix=/usr +make # binary install sudo make install # build rpm package and then install @@ -29,6 +26,15 @@ make rpm rpm -ivh --force --nodeps icamerasrc-*.rpm ``` +NOTE: +For gstreamer version > 1.22.0, add support for drm dma buffer. +It depends on libdrm, please install it when build icamerasrc +and add option "--enable-gstdrmformat=yes" to enable drm dma buffer. +```sh +sudo apt install libdrm-dev +./configure --prefix=/usr --enable-gstdrmformat=yes +``` + ## Pipeline examples * Ensure `${GST_PLUGIN_PATH}` includes icamerasrc installation path * Testpattern generator (no sensor) @@ -64,4 +70,5 @@ sudo -E gst-launch-1.0 icamerasrc device-name=ov13858-uf af-mode=2 ! video/x-raw * Sensor ar0234 ``` sudo -E gst-launch-1.0 icamerasrc device-name=ar0234 ! video/x-raw,format=NV12,width=1280,height=960 ! videoconvert ! glimagesink +sudo -E gst-launch-1.0 icamerasrc device-name=ar0234 io-mode=dma_mode ! 'video/x-raw(memory:DMABuf),drm-format=NV12,width=1280,height=960' ! glimagesink ``` diff --git a/autogen.sh b/autogen.sh index d89003b..9647c50 100755 --- a/autogen.sh +++ b/autogen.sh @@ -50,8 +50,7 @@ autoreconf --verbose --force --install --make || { exit 1; } -args="--prefix=/usr \ ---libdir=/usr/lib" +args="--prefix=/usr" ./configure $args || { echo 'configure failed'; diff --git a/configure.ac b/configure.ac index a73f47f..071b604 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # # GStreamer -# Copyright (C) 2015-2023 Intel Corporation +# Copyright (C) 2015-2024 Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -94,6 +94,15 @@ AC_ARG_WITH([androidstubs], [], [with_androidstubs=no]) +AC_ARG_WITH([haladaptor], + AC_HELP_STRING([--with-haladaptor], [Link hal adaptor library [default=no]])) + +AC_ARG_ENABLE([gstdrmformat], + AC_HELP_STRING([--enable-gstdrmformat], [Enable DRM format [default=no]])) + +AC_ARG_ENABLE([internalbuild], + AC_HELP_STRING([--enable-internalbuild], [Internal build [default=no]])) + AC_ARG_VAR([DEFAULT_CAMERA], [the default camera ID]) @@ -180,6 +189,29 @@ PKG_CHECK_MODULES(LIBDRM, [libdrm libdrm_intel], [ AC_MSG_ERROR([Cannot find libdrm pkgconfig]) ]) +AS_IF([test "x$enable_gstdrmformat" = "xyes"], [ + PKG_CHECK_MODULES(GST_1_23, [gstreamer-1.0 >= 1.23], [ have_gstdrmformat=yes ], [ + PKG_CHECK_MODULES(GST_1_22_6, [gstreamer-1.0 = 1.22.6], [ have_gstdrmformat=yes ], [ have_gstdrmformat=no ]) + ]) + + AS_IF([test "x$have_gstdrmformat" = "xyes"], [ + PKG_CHECK_MODULES(DEP_GSTDRMFORMAT, [gstreamer-va-1.0 libva libva-drm], [ + AC_SUBST(DEP_GSTDRMFORMAT_CFLAGS) + AC_SUBST(DEP_GSTDRMFORMAT_LIBS) + ], [ + have_gstdrmformat=no + AC_MSG_ERROR([Need gstreamer-va-1.0 libva libva-drm to enable GstVaDisplay]) + ]) + ], [ + AC_MSG_ERROR([Need GStreamer >= 1.23 or == 1.22.6, and gstreamer-va-1.0 libva libva-drm to enable GstVaDisplay]) + ]) + + AS_IF([test "x$have_gstdrmformat" = "xyes"], [ + AC_DEFINE([GST_DRM_FORMAT], [1], [GStreamer at least 1.23 or exactly 1.22.6 supports DRM format]) + AC_MSG_NOTICE(Define GST_DRM_FORMAT) + ]) +], []) + dnl check if compiler understands -Wall (if yes, add -Wall to GST_CFLAGS) AC_MSG_CHECKING([to see if compiler understands -Wall]) save_CFLAGS="$CFLAGS" @@ -190,6 +222,38 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], [ ])], [ ], [ AC_MSG_RESULT([no]) ]) +CFLAGS="$save_CFLAGS" + +AC_DEFUN([AC_CHECK_FORTIFY_SOURCE], [ + AC_MSG_CHECKING([for _FORTIFY_SOURCE value with -O2]) + old_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -O2" + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + #ifndef _FORTIFY_SOURCE + #error + #endif + int main() { printf("%d\n", _FORTIFY_SOURCE); return 0; } + ]])], + [ + fortify_source_value=`./conftest$EXEEXT` + ], + [ + AC_MSG_RESULT([no]) + fortify_source_value=0 + ], + [ + AC_MSG_CHECKING([for cross-compiling _FORTIFY_SOURCE depends on toolchain]) + AC_MSG_RESULT([no]) + fortify_source_value=0 + ] + ) + CFLAGS="$old_CFLAGS" + AC_SUBST([fortify_source_value]) +]) +AC_CHECK_FORTIFY_SOURCE +AM_CONDITIONAL([NO_FORTIFY_SOURCE], [test "x$fortify_source_value" = "x0"]) dnl set the plugindir where plugins should be installed (for src/Makefile.am) if test "x${prefix}" = "x$HOME"; then diff --git a/src/Makefile.am b/src/Makefile.am index 0f26be9..8e9ae08 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ # # GStreamer -# Copyright (C) 2015-2023 Intel Corporation +# Copyright (C) 2015-2024 Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -73,6 +73,7 @@ libgsticamerasrc_la_CPPFLAGS = \ $(GST_CFLAGS) \ $(CAMHAL_CFLAGS) \ $(LIBDRM_CFLAGS) \ + $(DEP_GSTDRMFORMAT_CFLAGS) \ -std=c++11 \ -Werror \ $(LIBUTILS_CFLAGS) \ @@ -91,12 +92,19 @@ libgsticamerasrc_la_LIBADD = $(GST_LIBS) \ -lgstvideo-$(GST_API_VERSION) \ interfaces/libgsticamerainterface-$(GST_API_VERSION).la \ $(LIBDRM_LIBS) \ + $(DEP_GSTDRMFORMAT_LIBS) \ $(CAMHAL_LIBS) libgsticamerasrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) # for hardening-check libgsticamerasrc_la_LDFLAGS += -fPIE -fPIC -Wformat -Wformat-security -Wl,-z,relro -Wl,-z,now +# test default fortify level +if NO_FORTIFY_SOURCE +libgsticamerasrc_la_CPPFLAGS+= -D_FORTIFY_SOURCE=2 +libgsticamerasrc_la_LDFLAGS+= -D_FORTIFY_SOURCE=2 +endif + # headers we need but don't want installed noinst_HEADERS = gstcamerasrc.h \ gstcameraformat.h \ diff --git a/src/gstcambasesrc.cpp b/src/gstcambasesrc.cpp index 66dd45b..8646c7f 100644 --- a/src/gstcambasesrc.cpp +++ b/src/gstcambasesrc.cpp @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2015-2021 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -42,7 +42,7 @@ */ #ifdef HAVE_CONFIG_H -# include +#include #endif #include "gstcambasesrc.h" @@ -447,6 +447,9 @@ gst_cam_base_src_init(GstCamBaseSrc *basesrc, GstCamBaseSrcClass *klass) gst_video_info_init(&basesrc->srcpad_info); basesrc->is_info_change = FALSE; #endif +#ifdef GST_DRM_FORMAT + basesrc->is_dma_drm_caps = FALSE; +#endif basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->clock_id = NULL; @@ -701,11 +704,10 @@ gst_cam_base_src_query_latency (GstCamBaseSrc * src, gboolean * live, { GstClockTime min; - g_return_val_if_fail (GST_IS_CAM_BASE_SRC (src), FALSE); - - GST_OBJECT_LOCK (src); - if (live) - *live = src->is_live; + if (live) { + *live = gst_cam_base_src_is_live(src); + GST_LOG_OBJECT(src, "live: %s", *live == TRUE ? "TRUE" : "FALSE"); + } /* if we have a startup latency, report this one, else report 0. Subclasses * are supposed to override the query function if they want something @@ -720,10 +722,8 @@ gst_cam_base_src_query_latency (GstCamBaseSrc * src, gboolean * live, if (max_latency) *max_latency = min; - GST_LOG_OBJECT (src, "latency: live %d, min %" GST_TIME_FORMAT - ", max %" GST_TIME_FORMAT, src->is_live, GST_TIME_ARGS (min), - GST_TIME_ARGS (min)); - GST_OBJECT_UNLOCK (src); + GST_LOG_OBJECT (src, "latency: min %" GST_TIME_FORMAT ", max %" + GST_TIME_FORMAT, GST_TIME_ARGS (min), GST_TIME_ARGS (min)); return TRUE; } @@ -845,8 +845,12 @@ static gboolean gst_cam_base_src_send_video_stream_start(GstCamBaseSrc *src, GstPad *pad) { gboolean ret = TRUE; - guint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + gint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_ERROR_OBJECT(src, "invalid stream_id: %d", stream_id); + return FALSE; + } /* start video stream */ if (src->priv->muxPriv[stream_id].vid_stream_start_pending) { gchar *vid_stream_id; @@ -1445,7 +1449,11 @@ gst_cam_base_src_default_alloc (GstCamBaseSrc * src, GstPad *pad, allocator = priv->allocator; params = priv->params; } else { - guint stream_id = CameraSrcUtils::get_stream_id_by_pad(priv->request_stream_map, pad); + gint stream_id = CameraSrcUtils::get_stream_id_by_pad(priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_ERROR_OBJECT(src, "invalid stream_id: %d", stream_id); + return GST_FLOW_ERROR; + } pool = priv->muxPriv[stream_id].vid_pool; allocator = priv->muxPriv[stream_id].vid_allocator; params = priv->muxPriv[stream_id].vid_params; @@ -1817,7 +1825,7 @@ gst_cam_base_src_send_event (GstElement * element, GstEvent * event) start = (GST_PAD_MODE (src->srcpad) == GST_PAD_MODE_PUSH); GST_OBJECT_UNLOCK (src->srcpad); - if (src->is_live) { + if (gst_cam_base_src_is_live(src)) { if (!src->live_running) start = FALSE; } @@ -2498,7 +2506,7 @@ gst_cam_base_src_get_range (GstCamBaseSrc * src, GstPad *pad, guint64 offset, bclass = GST_CAM_BASE_SRC_GET_CLASS (src); again: - if (src->is_live) { + if (gst_cam_base_src_is_live(src)) { if (G_UNLIKELY (!src->live_running)) { ret = gst_cam_base_src_wait_playing (src); if (ret != GST_FLOW_OK) @@ -2579,7 +2587,7 @@ gst_cam_base_src_get_range (GstCamBaseSrc * src, GstPad *pad, guint64 offset, /* no timestamp set and we are at offset 0, we can timestamp with 0 */ if (offset == 0 && src->segment.time == 0 - && (gint64)GST_BUFFER_DTS (res_buf) == -1 && !src->is_live) { + && (gint64)GST_BUFFER_DTS (res_buf) == -1 && !gst_cam_base_src_is_live(src)) { GST_DEBUG_OBJECT (src, "%s pad: setting first timestamp to 0", padname); res_buf = gst_buffer_make_writable (res_buf); GST_BUFFER_DTS (res_buf) = 0; @@ -2702,8 +2710,13 @@ gst_cam_base_src_video_get_range (GstCamBaseSrc * src, GstPad *pad, guint64 offs GstClockReturn status; GstBuffer *res_buf, *in_buf; gchar *padname = gst_pad_get_name(pad); - guint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + gint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_ERROR("pad %s has no stream_id %d", padname, stream_id); + g_free(padname); + return GST_FLOW_ERROR; + } bclass = GST_CAM_BASE_SRC_GET_CLASS(src); if (G_UNLIKELY (!GST_CAM_BASE_SRC_IS_STARTED (src) @@ -2738,7 +2751,7 @@ gst_cam_base_src_video_get_range (GstCamBaseSrc * src, GstPad *pad, guint64 offs } if (offset == 0 && src->mux[stream_id].vid_segment.time == 0 - && (gint64)GST_BUFFER_DTS (res_buf) == -1 && !src->is_live) { + && (gint64)GST_BUFFER_DTS (res_buf) == -1 && !gst_cam_base_src_is_live(src)) { GST_DEBUG_OBJECT (src, "%s pad: setting first timestamp to 0", padname); res_buf = gst_buffer_make_writable (res_buf); GST_BUFFER_DTS (res_buf) = 0; @@ -2902,7 +2915,7 @@ gst_cam_base_src_loop (GstPad * pad) if (G_UNLIKELY (src->priv->flushing || GST_PAD_IS_FLUSHING (pad))) goto flushing; - blocksize = src->blocksize; + blocksize = gst_cam_base_src_get_blocksize(src); /* if we operate in bytes, we can calculate an offset */ if (src->segment.format == GST_FORMAT_BYTES) { @@ -3164,8 +3177,12 @@ static void gst_cam_base_src_video_loop (GstPad * pad) guint blocksize; gchar *padname = gst_pad_get_name(pad); GstCamBaseSrc *src = GST_CAM_BASE_SRC(GST_OBJECT_PARENT(pad)); - guint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + gint stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_DEBUG_OBJECT(src, "%s pad: invalid stream id: %d", padname, stream_id); + goto done; + } /* Just leave immediately if we're flushing */ GST_VID_LIVE_LOCK (src, stream_id); if (G_UNLIKELY (src->priv->flushing || GST_PAD_IS_FLUSHING (pad))) @@ -3194,7 +3211,7 @@ static void gst_cam_base_src_video_loop (GstPad * pad) } GST_VID_LIVE_LOCK(src, stream_id); - blocksize = src->blocksize; + blocksize = gst_cam_base_src_get_blocksize(src); /* we only consider the scenario of GST_FORMAT_TIME */ if (src->mux[stream_id].vid_segment.format == GST_FORMAT_TIME) @@ -3364,7 +3381,12 @@ gst_cam_base_src_set_allocation (GstCamBaseSrc * basesrc, GstPad *pad, else gst_allocation_params_init(&priv->params); } else { - guint stream_id = CameraSrcUtils::get_stream_id_by_pad(priv->request_stream_map, pad); + gint stream_id = CameraSrcUtils::get_stream_id_by_pad(priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_ERROR_OBJECT(basesrc, "invalid stream_id: %d", stream_id); + GST_OBJECT_UNLOCK(basesrc); + return GST_FLOW_ERROR; + } oldalloc = priv->muxPriv[stream_id].vid_allocator; oldpool = priv->muxPriv[stream_id].vid_pool; priv->muxPriv[stream_id].vid_allocator = allocator; @@ -3617,11 +3639,12 @@ gst_cam_base_src_default_negotiate (GstCamBaseSrc * basesrc, GstPad *pad) gboolean result = FALSE; GstCaps *current_caps = NULL; - current_caps = gst_pad_get_current_caps (pad); + current_caps = gst_pad_get_current_caps (pad); if (current_caps){ - GST_DEBUG_OBJECT (basesrc, "straight return without negotiate"); - return TRUE; + GST_DEBUG_OBJECT (basesrc, "straight return without negotiate"); + gst_caps_unref (current_caps); + return TRUE; } /* first see what is possible on our source pad */ @@ -3715,9 +3738,17 @@ gst_cam_base_src_negotiate (GstCamBaseSrc * basesrc, GstPad *pad) caps = gst_pad_get_current_caps (pad); +#ifdef GST_DRM_FORMAT + basesrc->is_dma_drm_caps = gst_video_is_dma_drm_caps(caps); +#endif + #if GST_VERSION_MINOR >= 18 if (basesrc->is_info_change) { +#ifdef GST_DRM_FORMAT + if (!CameraSrcUtils::gst_video_info_from_dma_drm_caps(&vinfo, caps)) +#else if (!gst_video_info_from_caps(&vinfo, caps)) +#endif GST_DEBUG_OBJECT (basesrc, "Failed to get video info from caps."); else { if (!gst_video_info_is_equal(&basesrc->srcpad_info, &vinfo)) @@ -3731,6 +3762,11 @@ gst_cam_base_src_negotiate (GstCamBaseSrc * basesrc, GstPad *pad) #endif result = gst_cam_base_src_prepare_allocation (basesrc, caps, pad); +#if GST_VERSION_MINOR >= 18 + if (tmp_caps) + gst_caps_unref (tmp_caps); +#endif + if (caps) gst_caps_unref (caps); } @@ -4318,6 +4354,11 @@ gst_cam_base_src_activate_mode (GstPad * pad, GstObject * parent, res = gst_cam_base_src_activate_push (pad, parent, active); } else { int stream_id = CameraSrcUtils::get_stream_id_by_pad(src->priv->request_stream_map, pad); + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM - 1) { + GST_ERROR("pad %s has no stream_id %d", padname, stream_id); + res = FALSE; + break; + } src->priv->muxPriv[stream_id].vid_stream_start_pending = active; res = gst_cam_base_src_video_activate_push (pad, parent, stream_id, active); } diff --git a/src/gstcambasesrc.h b/src/gstcambasesrc.h index c6df5cd..3eac0bb 100644 --- a/src/gstcambasesrc.h +++ b/src/gstcambasesrc.h @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2015-2021 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -135,6 +135,10 @@ struct _GstCamBaseSrc { GstVideoInfo srcpad_info; gboolean is_info_change; #endif +#ifdef GST_DRM_FORMAT + /* indicate current caps is dma_drm type for io_mode=dma_mode. */ + bool is_dma_drm_caps; +#endif /* available to subclass implementations */ /* MT-protected (with LIVE_LOCK) */ diff --git a/src/gstcameradeinterlace.cpp b/src/gstcameradeinterlace.cpp index 2c7a0ea..cffb420 100644 --- a/src/gstcameradeinterlace.cpp +++ b/src/gstcameradeinterlace.cpp @@ -44,7 +44,7 @@ #define LOG_TAG "GstCameraDeinterlace" #ifdef HAVE_CONFIG_H -# include +#include #endif #include diff --git a/src/gstcameraformat.cpp b/src/gstcameraformat.cpp index c90b068..bba2548 100644 --- a/src/gstcameraformat.cpp +++ b/src/gstcameraformat.cpp @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2015-2021 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -44,7 +44,7 @@ #define LOG_TAG "GstCameraFormat" #ifdef HAVE_CONFIG_H -# include +#include #endif #include @@ -93,7 +93,13 @@ static void update_main_resolution(int format, cameraSrc_Res_Range res_range, vector &main_res_range); static GstStructure *create_structure (guint32 fourcc); +#ifdef GST_DRM_FORMAT +static void +set_structure_to_caps(vector main_res_range, + GstCaps **caps, GstVaDisplay *display_drm); +#else static void set_structure_to_caps(vector main_res_range, GstCaps **caps); +#endif static GstStructure * create_structure (guint32 fourcc) @@ -173,11 +179,61 @@ create_structure (guint32 fourcc) * Merge all structures into caps */ #define GST_CAPS_FEATURE_MEMORY_DMABUF "memory:DMABuf" +#ifdef GST_DRM_FORMAT +static void +set_structure_to_caps(vector main_res_range, + GstCaps **caps, GstVaDisplay *display_drm) +#else static void set_structure_to_caps(vector main_res_range, GstCaps **caps) +#endif { GstStructure *structure = NULL; int feature_index = 0; +#ifdef GST_DRM_FORMAT + if (display_drm) { + /* Set caps with dmabuffer */ + for (auto &res_range : main_res_range) { + structure = create_structure(res_range.format); + if (structure) { + const gchar *fmt_str = gst_structure_get_string(structure, "format"); + GstVideoFormat fmt = gst_video_format_from_string(fmt_str); + GValue dma_drm_fmts = G_VALUE_INIT; + g_value_init(&dma_drm_fmts, GST_TYPE_LIST); + if (!CameraSrcUtils::_dma_fmt_to_dma_drm_fmts(display_drm, fmt, + &dma_drm_fmts) || + gst_value_list_get_size(&dma_drm_fmts) <= 0) { + gst_structure_free(structure); + g_value_unset(&dma_drm_fmts); + continue; + } + gst_structure_set(structure, "format", G_TYPE_STRING, "DMA_DRM", NULL); + gst_structure_set_value(structure, "drm-format", &dma_drm_fmts); + g_value_unset(&dma_drm_fmts); + /* If has only one resolution */ + if (res_range.range.max_w == res_range.range.min_w && + res_range.range.max_h == res_range.range.min_h) + gst_structure_set(structure, "width", G_TYPE_INT, res_range.range.max_w, + "height", G_TYPE_INT, res_range.range.max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, + 1, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, + NULL); + else + gst_structure_set(structure, "width", GST_TYPE_INT_RANGE, + res_range.range.min_w, res_range.range.max_w, + "height", GST_TYPE_INT_RANGE, res_range.range.min_h, + res_range.range.max_h, "framerate", + GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); + *caps = gst_caps_merge_structure(*caps, structure); + gst_caps_set_features( + *caps, feature_index, + gst_caps_features_new(GST_CAPS_FEATURE_MEMORY_DMABUF, NULL)); + feature_index++; + } + } + } +#else /* Set caps with dmabuffer */ for (auto&res_range : main_res_range) { structure = create_structure (res_range.format); @@ -204,6 +260,7 @@ set_structure_to_caps(vector main_res_range, GstCaps feature_index++; } } +#endif /* Set caps with userptr */ for (auto&res_range : main_res_range) { structure = create_structure (res_range.format); @@ -329,7 +386,17 @@ GstCaps *gst_camerasrc_get_all_caps () vector fmt_res; vector main_res_range; - static GstCaps *caps = gst_caps_new_empty (); + static GstCaps *caps = NULL; + if (caps != NULL && GST_IS_CAPS(caps)) { + return caps; + } +#ifdef GST_DRM_FORMAT + GstVaDisplay *display_drm = NULL; + display_drm = gst_va_display_drm_new_from_path("/dev/dri/renderD128"); + if (NULL == display_drm) { + g_warning("Couldn't create a VA DRM display"); + } +#endif int count = get_number_of_cameras(); for(int i = 0; i < count; i++) { @@ -339,22 +406,44 @@ GstCaps *gst_camerasrc_get_all_caps () //get configuration of camera int ret = get_camera_info(i, info); if (ret != 0) { - GST_ERROR("failed to get camera info from libcamhal"); - gst_caps_unref(caps); + g_printerr("failed to get camera info from libcamhal"); +#ifdef GST_DRM_FORMAT + if (display_drm) { + gst_object_unref(display_drm); + display_drm = NULL; + } +#endif return NULL; } info.capability->getSupportedStreamConfig(configs); ret = register_format_and_resolution(configs, fmt_res, main_res_range); if (ret != 0) { - GST_ERROR("failed to get format info from libcamhal"); - gst_caps_unref(caps); + g_printerr("failed to get format info from libcamhal"); +#ifdef GST_DRM_FORMAT + if (display_drm) { + gst_object_unref(display_drm); + display_drm = NULL; + } +#endif return NULL; } } + caps = gst_caps_new_empty(); +#ifdef GST_DRM_FORMAT + set_structure_to_caps(main_res_range, &caps, display_drm); +#else set_structure_to_caps(main_res_range, &caps); +#endif + caps = gst_caps_simplify(caps); main_res_range.clear(); +#ifdef GST_DRM_FORMAT + if (display_drm) { + gst_object_unref(display_drm); + display_drm = NULL; + } +#endif - return gst_caps_simplify(caps); + return caps; } diff --git a/src/gstcameraformat.h b/src/gstcameraformat.h index ed55bf3..949af15 100644 --- a/src/gstcameraformat.h +++ b/src/gstcameraformat.h @@ -44,9 +44,6 @@ #ifndef __GST_CAMERAFORMAT_H__ #define __GST_CAMERAFORMAT_H__ -GST_DEBUG_CATEGORY_EXTERN(gst_camerasrc_debug); -#define GST_CAT_DEFAULT gst_camerasrc_debug - GstCaps *gst_camerasrc_get_all_caps (); #endif /* __GST_CAMERAFORMAT_H__ */ diff --git a/src/gstcamerasrc.cpp b/src/gstcamerasrc.cpp index 41f24a2..88c4530 100644 --- a/src/gstcamerasrc.cpp +++ b/src/gstcamerasrc.cpp @@ -2,7 +2,7 @@ * GStreamer * Copyright (C) 2005 Thomas Vander Stichele * Copyright (C) 2005 Ronald S. Bultje - * Copyright (C) 2015-2023 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -46,7 +46,7 @@ #define LOG_TAG "GstCameraSrc" #ifdef HAVE_CONFIG_H -# include +#include #endif #include @@ -177,7 +177,7 @@ G_DEFINE_TYPE_WITH_CODE (Gstcamerasrc, gst_camerasrc, GST_TYPE_CAM_PUSH_SRC, G_DEFINE_TYPE_WITH_CODE (Gstcamerasrc, gst_camerasrc, GST_TYPE_CAM_PUSH_SRC, G_IMPLEMENT_INTERFACE(GST_TYPE_CAMERASRC_3A_IF, gst_camerasrc_3a_interface_init); G_IMPLEMENT_INTERFACE(GST_TYPE_CAMERASRC_ISP_IF, gst_camerasrc_isp_interface_init); - G_IMPLEMENT_INTERFACE(GST_TYPE_CAMERASRC_DEWARPING_IF, gst_camerasrc_dewarping_interface_init) ); + G_IMPLEMENT_INTERFACE(GST_TYPE_CAMERASRC_DEWARPING_IF, gst_camerasrc_dewarping_interface_init)); #endif static void gst_camerasrc_set_property (GObject * object, guint prop_id, @@ -922,13 +922,13 @@ static GstStaticPadTemplate video_pad_template = GST_STATIC_PAD_TEMPLATE( GST_CAM_BASE_VIDEO_PAD_NAMES, GST_PAD_SRC, GST_PAD_REQUEST, - gst_camerasrc_get_all_caps()); + {gst_camerasrc_get_all_caps()}); static GstStaticPadTemplate still_pad_template = GST_STATIC_PAD_TEMPLATE( GST_CAM_BASE_STILL_PAD_NAMES, GST_PAD_SRC, GST_PAD_REQUEST, - gst_camerasrc_get_all_caps()); + {gst_camerasrc_get_all_caps()}); static void gst_camerasrc_class_init (GstcamerasrcClass * klass) @@ -953,6 +953,8 @@ gst_camerasrc_class_init (GstcamerasrcClass * klass) gstelement_class->request_new_pad = GST_DEBUG_FUNCPTR(gst_camerasrc_request_new_pad); gstelement_class->release_pad = GST_DEBUG_FUNCPTR(gst_camerasrc_release_pad); + GST_DEBUG_CATEGORY_INIT(gst_camerasrc_debug, "icamerasrc", 0, "camerasrc source element"); + g_object_class_install_property(gobject_class,PROP_BUFFERCOUNT, g_param_spec_int("buffer-count","buffer count","The number of buffer to allocate when do the streaming", MIN_PROP_BUFFERCOUNT,MAX_PROP_BUFFERCOUNT,DEFAULT_PROP_BUFFERCOUNT, @@ -1227,8 +1229,6 @@ gst_camerasrc_class_init (GstcamerasrcClass * klass) basesrc_class->negotiate = GST_DEBUG_FUNCPTR(gst_camerasrc_negotiate); basesrc_class->decide_allocation = GST_DEBUG_FUNCPTR(gst_camerasrc_decide_allocation); pushsrc_class->fill = GST_DEBUG_FUNCPTR(gst_camerasrc_fill); - - GST_DEBUG_CATEGORY_INIT (gst_camerasrc_debug, "icamerasrc", 0, "camerasrc source element"); } static void @@ -1296,6 +1296,10 @@ gst_camerasrc_init (Gstcamerasrc * camerasrc) camerasrc->streams[GST_CAMERASRC_MAIN_STREAM_ID].stream_config_done = FALSE; camerasrc->streams[GST_CAMERASRC_MAIN_STREAM_ID].activated = TRUE; camerasrc->streams[GST_CAMERASRC_MAIN_STREAM_ID].stream_usage = DEFAULT_PROP_SRC_STREAM_USAGE; +#ifdef GST_DRM_FORMAT + camerasrc->streams[GST_CAMERASRC_MAIN_STREAM_ID].drm_modifier = + DRM_FORMAT_MOD_LINEAR; +#endif /* set default value for 3A manual control*/ camerasrc->param = new Parameters; @@ -1440,7 +1444,7 @@ static GstPad *gst_camerasrc_request_new_pad (GstElement * element, } } else { GST_ERROR("Invalid pad name: %s, please follow 'video_%%u' or 'still_%%u' as template to name it", name_templ); - GST_CAMSRC_LOCK(camerasrc); + GST_CAMSRC_UNLOCK(camerasrc); return NULL; } @@ -1483,6 +1487,7 @@ static GstPad *gst_camerasrc_request_new_pad (GstElement * element, req_pad = GST_CAM_BASE_SRC_CLASS (parent_class)->add_video_pad(basesrc, klass, videopad, index, padname); if (!req_pad) { GST_ERROR("CameraId=%d failed to add video source pad.", camerasrc->device_id); + g_free(padname); GST_CAMSRC_UNLOCK(camerasrc); return NULL; } @@ -1498,17 +1503,24 @@ static void gst_camerasrc_release_pad (GstElement * element, GstPad * pad) Gstcamerasrc *camerasrc = GST_CAMERASRC(element); gchar *padname = gst_pad_get_name(pad); int stream_id = CameraSrcUtils::get_stream_id_by_pad(camerasrc->stream_map, pad); + + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM) { + GST_ERROR("CameraId=%d pad %s has no stream_id %d", camerasrc->device_id, + padname, stream_id); + g_free(padname); + return; + } GST_INFO("CameraId=%d.", camerasrc->device_id); GST_CAMSRC_LOCK(camerasrc); - g_hash_table_remove(camerasrc->pad_indexes, GUINT_TO_POINTER(camerasrc->stream_map[padname])); + g_hash_table_remove(camerasrc->pad_indexes, GUINT_TO_POINTER(stream_id)); camerasrc->stream_map.erase(padname); camerasrc->number_of_activepads--; camerasrc->streams[stream_id].activated = FALSE; gst_pad_set_active(pad, FALSE); gst_element_remove_pad (element, pad); - g_free (padname); GST_CAMSRC_UNLOCK(camerasrc); + g_free (padname); } /** @@ -2474,8 +2486,7 @@ gst_camerasrc_find_match_stream(Gstcamerasrc* camerasrc, } static gboolean -gst_camerasrc_get_caps_info (Gstcamerasrc* camerasrc, - GstCaps * caps, int stream_id, stream_config_t *stream_list) +gst_camerasrc_get_caps_info (Gstcamerasrc* camerasrc, GstCaps * caps, int stream_id) { PERF_CAMERA_ATRACE(); GstVideoInfo info; @@ -2483,12 +2494,29 @@ gst_camerasrc_get_caps_info (Gstcamerasrc* camerasrc, GstStructure *structure = gst_caps_get_structure (caps, 0); const gchar *mimetype = gst_structure_get_name (structure); - /* raw caps, parse into video info */ - if (!gst_video_info_from_caps (&info, caps)) { - GST_ERROR("CameraId=%d, StreamId=%d Caps can't be parsed", - camerasrc->device_id, stream_id); - return FALSE; +#ifdef GST_DRM_FORMAT + if (!gst_video_is_dma_drm_caps(caps)) { +#endif + /* raw caps, parse into video info */ + if (!gst_video_info_from_caps(&info, caps)) { + GST_ERROR("CameraId=%d, StreamId=%d Caps can't be parsed", + camerasrc->device_id, stream_id); + return FALSE; + } +#ifdef GST_DRM_FORMAT + } else { + GstVideoInfoDmaDrm drm_info; + if (!gst_video_info_dma_drm_from_caps(&drm_info, caps)) { + GST_ERROR("CameraId=%d, StreamId=%d Caps[dma_drm] can't be parsed", + camerasrc->device_id, stream_id); + return FALSE; + } + camerasrc->streams[stream_id].drm_modifier = drm_info.drm_modifier; + if (!gst_video_info_dma_drm_to_video_info(&drm_info, &info)) { + return FALSE; + } } +#endif GstVideoFormat gst_fmt = GST_VIDEO_INFO_FORMAT (&info); /* parse format from caps */ @@ -2645,7 +2673,8 @@ gst_camerasrc_set_caps(GstCamBaseSrc *src, GstPad *pad, GstCaps *caps) int stream_id = CameraSrcUtils::get_stream_id_by_pad(camerasrc->stream_map, pad); gchar *padname = gst_pad_get_name(pad); - if (stream_id < 0) { + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM) { + GST_ERROR("pad %s has no stream_id %d", padname, stream_id); g_free (padname); return FALSE; } @@ -2661,14 +2690,18 @@ gst_camerasrc_set_caps(GstCamBaseSrc *src, GstPad *pad, GstCaps *caps) } /* Get caps info from structure and match from HAL */ - if (!gst_camerasrc_get_caps_info (camerasrc, caps, stream_id, &camerasrc->stream_list)) { + if (!gst_camerasrc_get_caps_info(camerasrc, caps, stream_id)) { g_free (padname); return FALSE; } #if GST_VERSION_MINOR >= 18 if (camerasrc->io_mode == GST_CAMERASRC_IO_MODE_DMA_MODE) { +#ifdef GST_DRM_FORMAT + if (CameraSrcUtils::gst_video_info_from_dma_drm_caps(&vinfo, caps)) { +#else if (gst_video_info_from_caps(&vinfo, caps)) { +#endif gst_camerasrc_set_video_alignment(&vinfo, 0, 0, &align); gst_video_info_align(&vinfo, &align); GST_CAM_BASE_SRC_CLASS(parent_class)->add_video_info(src, &vinfo, TRUE); @@ -2984,8 +3017,10 @@ gst_camerasrc_decide_allocation(GstCamBaseSrc *bsrc,GstQuery *query, GstPad *pad const char* GST_MSDK_SELECT="gstMsdkSelect"; int stream_id = CameraSrcUtils::get_stream_id_by_pad(camerasrc->stream_map, pad); - if (stream_id < 0) + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM) { + GST_ERROR("CameraId=%d has no stream_id %d", camerasrc->device_id, stream_id); return FALSE; + } GST_INFO("CameraId=%d, StreamId=%d.", camerasrc->device_id, stream_id); active = gst_buffer_pool_is_active(GST_BUFFER_POOL_CAST(camerasrc->streams[stream_id].pool)); @@ -3122,8 +3157,10 @@ gst_camerasrc_fill(GstCamPushSrc *src, GstPad *pad, GstBuffer *buf) GstClock *clock; GstClockTime base_time, timestamp, duration; int stream_id = CameraSrcUtils::get_stream_id_by_pad(camerasrc->stream_map, pad); - if (stream_id < 0) + if (stream_id < 0 || stream_id >= GST_CAMERASRC_MAX_STREAM_NUM) { + GST_ERROR("CameraId=%d has no stream_id %d", camerasrc->device_id, stream_id); return GST_FLOW_ERROR; + } GstCamerasrcBufferPool *bpool = GST_CAMERASRC_BUFFER_POOL(camerasrc->streams[stream_id].pool); diff --git a/src/gstcamerasrc.h b/src/gstcamerasrc.h index 5a5f2e0..508a405 100644 --- a/src/gstcamerasrc.h +++ b/src/gstcamerasrc.h @@ -2,7 +2,7 @@ * GStreamer * Copyright (C) 2005 Thomas Vander Stichele * Copyright (C) 2005 Ronald S. Bultje - * Copyright (C) 2015-2021 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -463,6 +463,10 @@ struct _GstStreamInfo /* Buffer config */ guint bpl; GstVideoInfo info; +#ifdef GST_DRM_FORMAT + /* drm modifier used currently after negotiated. */ + guint64 drm_modifier; +#endif const char *fmt_name; camera_info_t cam_info; diff --git a/src/gstcamerasrcbufferpool.cpp b/src/gstcamerasrcbufferpool.cpp index 9829927..12228c9 100644 --- a/src/gstcamerasrcbufferpool.cpp +++ b/src/gstcamerasrcbufferpool.cpp @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2015-2022 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -44,7 +44,7 @@ #define LOG_TAG "GstCameraSrcBufferPool" #ifdef HAVE_CONFIG_H -# include +#include #endif #include @@ -89,6 +89,19 @@ gst_camerasrc_meta_api_get_type (void) return type; } +static gboolean +gst_camerasrc_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer) +{ + GstCamerasrcMeta *emeta = (GstCamerasrcMeta *) meta; + + emeta->index = 0; + emeta->mem = NULL; + emeta->buffer = NULL; + + return TRUE; +} + + const GstMetaInfo * gst_camerasrc_meta_get_info (void) { @@ -98,7 +111,7 @@ gst_camerasrc_meta_get_info (void) if (g_once_init_enter (&meta_info)) { const GstMetaInfo *meta = gst_meta_register (gst_camerasrc_meta_api_get_type (), "GstCamerasrcMeta", - sizeof (GstCamerasrcMeta), (GstMetaInitFunction) NULL, + sizeof (GstCamerasrcMeta), gst_camerasrc_meta_init, (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL); g_once_init_leave (&meta_info, meta); } @@ -128,6 +141,12 @@ gst_camerasrc_buffer_pool_finalize (GObject * object) PERF_CAMERA_ATRACE(); GstCamerasrcBufferPool *pool = GST_CAMERASRC_BUFFER_POOL (object); GST_INFO("CameraId=%d, StreamId=%d.", pool->src->device_id, pool->stream_id); +#ifdef GST_DRM_FORMAT + if (pool->display_drm) { + gst_object_unref(pool->display_drm); + pool->display_drm = NULL; + } +#endif G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -158,6 +177,10 @@ gst_camerasrc_buffer_pool_init (GstCamerasrcBufferPool * pool) #if GST_VERSION_MINOR >= 18 pool->need_alignment = FALSE; #endif + +#ifdef GST_DRM_FORMAT + pool->display_drm = NULL; +#endif } GstBufferPool * @@ -176,7 +199,11 @@ gst_camerasrc_buffer_pool_new (Gstcamerasrc *camerasrc, if (camerasrc->io_mode == GST_CAMERASRC_IO_MODE_DMA_MODE) { #if GST_VERSION_MINOR >= 18 +#ifdef GST_DRM_FORMAT + if (!CameraSrcUtils::gst_video_info_from_dma_drm_caps(&info, caps)) { +#else if (!gst_video_info_from_caps(&info, caps)) { +#endif GST_ERROR("CameraId=%d, StreamId=%d failed to get video info from caps.", camerasrc->device_id, stream_id); return NULL; @@ -264,7 +291,11 @@ gst_camerasrc_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * conf } #if GST_VERSION_MINOR >= 18 +#ifdef GST_DRM_FORMAT + if (!CameraSrcUtils::gst_video_info_from_dma_drm_caps(&video_info, caps)) { +#else if (!gst_video_info_from_caps (&video_info, caps)) { +#endif GST_ERROR("CameraId=%d, StreamId=%d failed to get video info from caps.", camerasrc->device_id, pool->stream_id); return FALSE; @@ -282,7 +313,19 @@ gst_camerasrc_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * conf pool->allocator = NULL; if (camerasrc->io_mode == GST_CAMERASRC_IO_MODE_DMA_EXPORT || camerasrc->io_mode == GST_CAMERASRC_IO_MODE_DMA_MODE) { +#ifdef GST_DRM_FORMAT + if (NULL == pool->display_drm) { + pool->display_drm = + gst_va_display_drm_new_from_path("/dev/dri/renderD128"); + if (NULL == pool->display_drm) { + GST_ERROR("Couldn't create a VA DRM display"); + return FALSE; + } + } + pool->allocator = gst_va_dmabuf_allocator_new(pool->display_drm); +#else pool->allocator = gst_dmabuf_allocator_new (); +#endif } else { pool->allocator = allocator; } @@ -535,7 +578,7 @@ gst_camerasrc_alloc_dma_export(GstCamerasrcBufferPool *pool, return GST_FLOW_ERROR; } - int dmafd = dup ((*meta)->buffer->dmafd); + int dmafd = (*meta)->buffer->dmafd; if (dmafd < 0) goto err_get_fd; @@ -588,7 +631,7 @@ gst_camerasrc_alloc_dma_import(GstCamerasrcBufferPool *pool, mem = gst_buffer_peek_memory(*alloc_buffer, 0); - (*meta)->buffer->dmafd = dup(gst_dmabuf_memory_get_fd(mem)); + (*meta)->buffer->dmafd = gst_dmabuf_memory_get_fd(mem); if ((*meta)->buffer->dmafd < 0) goto err_get_fd; @@ -633,8 +676,8 @@ gst_camerasrc_alloc_dma_mode(GstCamerasrcBufferPool *pool, int dmafd = -1; int intel_fd = -1; int size = 0; - drm_intel_bufmgr *bufmgr; - drm_intel_bo *drm_bo; + drm_intel_bufmgr *bufmgr = NULL; + drm_intel_bo *drm_bo = NULL; Gstcamerasrc *src = pool->src; #if GST_VERSION_MINOR >= 18 GstVideoInfo info = src->streams[pool->stream_id].info; @@ -650,6 +693,10 @@ gst_camerasrc_alloc_dma_mode(GstCamerasrcBufferPool *pool, if ((*meta)->buffer == NULL) return GST_FLOW_ERROR; +#ifdef GST_DRM_FORMAT + if (!GST_CAM_BASE_SRC(src)->is_dma_drm_caps) { +#endif + intel_fd = open("/dev/dri/renderD128", O_RDWR); if (intel_fd < 0) { @@ -700,6 +747,35 @@ gst_camerasrc_alloc_dma_mode(GstCamerasrcBufferPool *pool, close(intel_fd); drm_intel_bufmgr_destroy(bufmgr); drm_intel_bo_unreference(drm_bo); +#ifdef GST_DRM_FORMAT + } else { + if (NULL == pool->display_drm) { + GST_ERROR("Couldn't create a VA DRM display"); + return GST_FLOW_ERROR; + } + VADRMPRIMESurfaceDescriptor desc = { + 0, + }; + VASurfaceID surface; + guint64 drm_modifier = src->streams[pool->stream_id].drm_modifier; + if (!CameraSrcUtils::_va_create_surface_and_export_to_dmabuf( + pool->display_drm, VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC, + &drm_modifier, 1, &info, &surface, &desc)) + return GST_FLOW_ERROR; + for (guint32 i = 0; i < desc.num_objects; i++) { + gint fd = desc.objects[i].fd; + gsize size = CameraSrcUtils::_get_fd_size(fd); + GST_DEBUG("CameraId=%d, StreamId=%d DMA import buffer fd=%d.", + src->device_id, pool->stream_id, fd); + (*meta)->buffer->dmafd = fd; + (*meta)->buffer->s = src->s[pool->stream_id]; + (*meta)->buffer->s.memType = V4L2_MEMORY_DMABUF; + (*meta)->buffer->flags = BUFFER_FLAG_DMA_EXPORT; + GstMemory *mem = gst_dmabuf_allocator_alloc(pool->allocator, fd, size); + gst_buffer_append_memory(*alloc_buffer, mem); + } + } +#endif return GST_FLOW_OK; @@ -812,7 +888,7 @@ gst_camerasrc_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buff goto err_alloc_buffer; break; default: - break; + goto err_alloc_buffer; } meta->index = pool->number_allocated; diff --git a/src/gstcamerasrcbufferpool.h b/src/gstcamerasrcbufferpool.h index e7484ea..981fecd 100644 --- a/src/gstcamerasrcbufferpool.h +++ b/src/gstcamerasrcbufferpool.h @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2015-2021 Intel Corporation + * Copyright (C) 2015-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -49,6 +49,8 @@ #include "gstcampushsrc.h" #include "gstcamerasrc.h" +#include "utils.h" + typedef struct _GstCamerasrcBufferPool GstCamerasrcBufferPool;//in use of qbuf&dqbuf typedef struct _GstCamerasrcBufferPoolClass GstCamerasrcBufferPoolClass;//in use of _class_init @@ -87,6 +89,11 @@ struct _GstCamerasrcBufferPool gboolean need_alignment; GstVideoAlignment alignment; #endif + +#ifdef GST_DRM_FORMAT + /* operate on /dev/dri/renderD128 */ + GstVaDisplay *display_drm; +#endif }; struct _GstCamerasrcBufferPoolClass diff --git a/src/interfaces/Makefile.am b/src/interfaces/Makefile.am index 2e92bb7..4d9d77e 100644 --- a/src/interfaces/Makefile.am +++ b/src/interfaces/Makefile.am @@ -66,6 +66,12 @@ libgsticamerainterface_@GST_API_VERSION@_la_LIBADD = $(GST_LIBS) $(CAMHAL_LIBS) # for hardening-check libgsticamerainterface_@GST_API_VERSION@_la_LDFLAGS = -fPIE -fPIC -Wformat -Wformat-security -Wl,-z,relro -Wl,-z,now -version-info $(LT_VERSION_INFO) +# test default fortify level +if NO_FORTIFY_SOURCE +libgsticamerainterface_@GST_API_VERSION@_la_CPPFLAGS+= -D_FORTIFY_SOURCE=2 +libgsticamerainterface_@GST_API_VERSION@_la_LDFLAGS+= -D_FORTIFY_SOURCE=2 +endif + libgsticamerainterfaceincludedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/icamera libgsticamerainterfaceinclude_HEADERS = gstcamera3ainterface.h \ diff --git a/src/utils.cpp b/src/utils.cpp index f938798..8996619 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2018-2021 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -43,6 +43,9 @@ #define LOG_TAG "GstCameraUtils" +#ifdef HAVE_CONFIG_H +#include +#endif #include "utils.h" struct FormatCvt { @@ -149,7 +152,7 @@ void CameraSrcUtils::get_stream_info_by_caps(GstCaps *caps, const char **format, gst_structure_get_int(structure, "height", height); } -int CameraSrcUtils::get_stream_id_by_pad(map streamMap, GstPad *pad) +int CameraSrcUtils::get_stream_id_by_pad(map &streamMap, GstPad *pad) { int stream_id = -1; gchar *padname = gst_pad_get_name(pad); @@ -158,9 +161,699 @@ int CameraSrcUtils::get_stream_id_by_pad(map streamMap, GstPad *pad if (iter != streamMap.end()) stream_id = iter->second; else { - GST_ERROR("failed to get StreamId: %d", stream_id); + GST_ERROR("failed to find StreamId by pad: %s", padname); } g_free(padname); return stream_id; } + +#ifdef GST_DRM_FORMAT + +#define VA_NSB_FIRST 0 /* No Significant Bit */ + +/* *INDENT-OFF* */ +static struct FormatMap { + GstVideoFormat format; + guint va_rtformat; + VAImageFormat va_format; + /* The drm fourcc may have different definition from VA */ + guint drm_fourcc; +} format_map[] = { +#ifndef G_OS_WIN32 +#define F(format, drm, fourcc, rtformat, order, bpp, depth, r, g, b, a) \ + { \ + G_PASTE(GST_VIDEO_FORMAT_, format), G_PASTE(VA_RT_FORMAT_, rtformat), \ + {VA_FOURCC fourcc, \ + G_PASTE(G_PASTE(VA_, order), _FIRST), \ + bpp, \ + depth, \ + r, \ + g, \ + b, \ + a}, \ + G_PASTE(DRM_FORMAT_, drm) \ + } +#else +#define F(format, drm, fourcc, rtformat, order, bpp, depth, r, g, b, a) \ + { \ + G_PASTE(GST_VIDEO_FORMAT_, format), G_PASTE(VA_RT_FORMAT_, rtformat), \ + {VA_FOURCC fourcc, \ + G_PASTE(G_PASTE(VA_, order), _FIRST), \ + bpp, \ + depth, \ + r, \ + g, \ + b, \ + a}, \ + 0 /* DRM_FORMAT_INVALID */ \ + } +#endif +#define G(format, drm, fourcc, rtformat, order, bpp) \ + F(format, drm, fourcc, rtformat, order, bpp, 0, 0, 0, 0, 0) + G(NV12, NV12, ('N', 'V', '1', '2'), YUV420, NSB, 12), + G(NV21, NV21, ('N', 'V', '2', '1'), YUV420, NSB, 21), + G(VUYA, AYUV, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32), + F(RGBA, RGBA8888, ('R', 'G', 'B', 'A'), RGB32, LSB, 32, 32, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0xff000000), + F(RGBx, RGBX8888, ('R', 'G', 'B', 'X'), RGB32, LSB, 32, 24, 0x000000ff, + 0x0000ff00, 0x00ff0000, 0x00000000), + F(BGRA, BGRA8888, ('B', 'G', 'R', 'A'), RGB32, LSB, 32, 32, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0xff000000), + F(ARGB, ARGB8888, ('A', 'R', 'G', 'B'), RGB32, LSB, 32, 32, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x000000ff), + F(xRGB, XRGB8888, ('X', 'R', 'G', 'B'), RGB32, LSB, 32, 24, 0x0000ff00, + 0x00ff0000, 0xff000000, 0x00000000), + F(ABGR, ABGR8888, ('A', 'B', 'G', 'R'), RGB32, LSB, 32, 32, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x000000ff), + F(xBGR, XBGR8888, ('X', 'B', 'G', 'R'), RGB32, LSB, 32, 24, 0xff000000, + 0x00ff0000, 0x0000ff00, 0x00000000), + F(BGRx, BGRX8888, ('B', 'G', 'R', 'X'), RGB32, LSB, 32, 24, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0x00000000), + G(UYVY, UYVY, ('U', 'Y', 'V', 'Y'), YUV422, NSB, 16), + G(YUY2, YUYV, ('Y', 'U', 'Y', '2'), YUV422, NSB, 16), + G(AYUV, AYUV, ('A', 'Y', 'U', 'V'), YUV444, LSB, 32), + /* F (????, NV11), */ + G(YV12, YVU420, ('Y', 'V', '1', '2'), YUV420, NSB, 12), + /* F (????, P208), */ + G(I420, YUV420, ('I', '4', '2', '0'), YUV420, NSB, 12), + /* F (????, YV24), */ + /* F (????, YV32), */ + /* F (????, Y800), */ + /* F (????, IMC3), */ + /* F (????, 411P), */ + /* F (????, 411R), */ + G(Y42B, YUV422, ('4', '2', '2', 'H'), YUV422, LSB, 16), + /* F (????, 422V), */ + /* F (????, 444P), */ + /* No RGBP support in drm fourcc */ + G(RGBP, INVALID, ('R', 'G', 'B', 'P'), RGBP, LSB, 8), + /* F (????, BGRP), */ + /* F (????, RGB565), */ + /* F (????, BGR565), */ + G(Y210, Y210, ('Y', '2', '1', '0'), YUV422_10, NSB, 32), + /* F (????, Y216), */ + G(Y410, Y410, ('Y', '4', '1', '0'), YUV444_10, NSB, 32), + G(Y212_LE, Y212, ('Y', '2', '1', '2'), YUV422_12, NSB, 32), + G(Y412_LE, Y412, ('Y', '4', '1', '2'), YUV444_12, NSB, 32), + /* F (????, Y416), */ + /* F (????, YV16), */ + G(P010_10LE, P010, ('P', '0', '1', '0'), YUV420_10, NSB, 24), + G(P012_LE, P012, ('P', '0', '1', '2'), YUV420_12, NSB, 24), + /* F (P016_LE, P016, ????), */ + /* F (????, I010), */ + /* F (????, IYUV), */ + /* F (????, A2R10G10B10), */ + /* F (????, A2B10G10R10), */ + /* F (????, X2R10G10B10), */ + /* F (????, X2B10G10R10), */ + /* No GRAY8 support in drm fourcc */ + G(GRAY8, INVALID, ('Y', '8', '0', '0'), YUV400, NSB, 8), + G(Y444, YUV444, ('4', '4', '4', 'P'), YUV444, NSB, 24), + /* F (????, Y16), */ + /* G (VYUY, VYUY, YUV422), */ + /* G (YVYU, YVYU, YUV422), */ + /* F (ARGB64, ARGB64, ????), */ + /* F (????, ABGR64), */ + F(RGB16, RGB565, ('R', 'G', '1', '6'), RGB16, NSB, 16, 16, 0x0000f800, + 0x000007e0, 0x0000001f, 0x00000000), + F(RGB, RGB888, ('R', 'G', '2', '4'), RGB32, NSB, 32, 24, 0x00ff0000, + 0x0000ff00, 0x000000ff, 0x00000000), + F(BGR10A2_LE, ARGB2101010, ('A', 'R', '3', '0'), RGB32, LSB, 32, 30, + 0x3ff00000, 0x000ffc00, 0x000003ff, 0x30000000), +#undef F +#undef G +}; + +static const struct RBG32FormatMap { + GstVideoFormat format; + guint drm_fourcc; + VAImageFormat va_format[2]; +} rgb32_format_map[] = { +#define F(fourcc, order, bpp, depth, r, g, b, a) \ + { \ + VA_FOURCC fourcc, G_PASTE(G_PASTE(VA_, order), _FIRST), bpp, depth, r, g, \ + b, a \ + } +#define A(fourcc, order, r, g, b, a) F(fourcc, order, 32, 32, r, g, b, a) +#define X(fourcc, order, r, g, b) F(fourcc, order, 32, 24, r, g, b, 0x0) +#ifndef G_OS_WIN32 +#define D(format, drm_fourcc) \ + G_PASTE(GST_VIDEO_FORMAT_, format), G_PASTE(DRM_FORMAT_, drm_fourcc) +#else +#define D(format, drm_fourcc) \ + G_PASTE(GST_VIDEO_FORMAT_, format), 0 /* DRM_FORMAT_INVALID */ +#endif + {D(ARGB, BGRA8888), + { + A(('B', 'G', 'R', 'A'), LSB, 0x0000ff00, 0x00ff0000, 0xff000000, + 0x000000ff), + A(('A', 'R', 'G', 'B'), MSB, 0x00ff0000, 0x0000ff00, 0x000000ff, + 0xff000000), + }}, + {D(RGBA, ABGR8888), + { + A(('A', 'B', 'G', 'R'), LSB, 0x000000ff, 0x0000ff00, 0x00ff0000, + 0xff000000), + A(('R', 'G', 'B', 'A'), MSB, 0xff000000, 0x00ff0000, 0x0000ff00, + 0x000000ff), + }}, + {D(ABGR, RGBA8888), + { + A(('R', 'G', 'B', 'A'), LSB, 0xff000000, 0x00ff0000, 0x0000ff00, + 0x000000ff), + A(('A', 'B', 'G', 'R'), MSB, 0x000000ff, 0x0000ff00, 0x00ff0000, + 0xff000000), + }}, + {D(BGRA, ARGB8888), + { + A(('A', 'R', 'G', 'B'), LSB, 0x00ff0000, 0x0000ff00, 0x000000ff, + 0xff000000), + A(('B', 'G', 'R', 'A'), MSB, 0x0000ff00, 0x00ff0000, 0xff000000, + 0x000000ff), + }}, + {D(xRGB, BGRX8888), + { + X(('B', 'G', 'R', 'X'), LSB, 0x0000ff00, 0x00ff0000, 0xff000000), + X(('X', 'R', 'G', 'B'), MSB, 0x00ff0000, 0x0000ff00, 0x000000ff), + }}, + {D(RGBx, XBGR8888), + { + X(('X', 'B', 'G', 'R'), LSB, 0x000000ff, 0x0000ff00, 0x00ff0000), + X(('R', 'G', 'B', 'X'), MSB, 0xff000000, 0x00ff0000, 0x0000ff00), + }}, + {D(xBGR, RGBX8888), + { + X(('R', 'G', 'B', 'X'), LSB, 0xff000000, 0x00ff0000, 0x0000ff00), + X(('X', 'B', 'G', 'R'), MSB, 0x000000ff, 0x0000ff00, 0x00ff0000), + }}, + {D(BGRx, XRGB8888), + { + X(('X', 'R', 'G', 'B'), LSB, 0x00ff0000, 0x0000ff00, 0x000000ff), + X(('B', 'G', 'R', 'X'), MSB, 0x0000ff00, 0x00ff0000, 0xff000000), + }}, +#undef X +#undef A +#undef F +#undef D +}; +/* *INDENT-ON* */ + +gboolean CameraSrcUtils::gst_video_info_from_dma_drm_caps(GstVideoInfo *info, + const GstCaps *caps) { + if (!gst_video_is_dma_drm_caps(caps)) { + if (!gst_video_info_from_caps(info, caps)) { + return FALSE; + } + } else { + GstVideoInfoDmaDrm drm_info; + if (!gst_video_info_dma_drm_from_caps(&drm_info, caps)) { + return FALSE; + } + if (!gst_video_info_dma_drm_to_video_info(&drm_info, info)) { + return FALSE; + } + } + return TRUE; +} + +static struct FormatMap * +get_format_map_from_video_format(GstVideoFormat format) { + long unsigned int i; + + for (i = 0; i < G_N_ELEMENTS(format_map); i++) { + if (format_map[i].format == format) + return &format_map[i]; + } + + return NULL; +} + +static guint gst_va_drm_fourcc_from_video_format(GstVideoFormat format) { + const struct FormatMap *map = get_format_map_from_video_format(format); + + return map ? map->drm_fourcc : 0; +} + +static guint gst_va_chroma_from_video_format(GstVideoFormat format) { + const struct FormatMap *map = get_format_map_from_video_format(format); + + return map ? map->va_rtformat : 0; +} + +static guint gst_va_fourcc_from_video_format(GstVideoFormat format) { + const struct FormatMap *map = get_format_map_from_video_format(format); + + return map ? map->va_format.fourcc : 0; +} + +static gboolean va_destroy_surfaces(GstVaDisplay *display, + VASurfaceID *surfaces, gint num_surfaces) { + VADisplay dpy = gst_va_display_get_va_dpy(display); + VAStatus status; + + g_return_val_if_fail(num_surfaces > 0, FALSE); + + status = vaDestroySurfaces(dpy, surfaces, num_surfaces); + if (status != VA_STATUS_SUCCESS) { + GST_ERROR("vaDestroySurfaces: %s", vaErrorStr(status)); + return FALSE; + } + + return TRUE; +} + +static guint64 gst_va_dmabuf_get_modifier_for_format_for_icamerasrc( + GstVaDisplay *display, GstVideoFormat format, guint usage_hint) { + VADRMPRIMESurfaceDescriptor desc = { + 0, + }; + VASurfaceID surface; + GstVideoInfo info; + + gst_video_info_init(&info); + gst_video_info_set_format(&info, format, 64, 64); + + if (!CameraSrcUtils::_va_create_surface_and_export_to_dmabuf( + display, usage_hint, NULL, 0, &info, &surface, &desc)) + return DRM_FORMAT_MOD_INVALID; + + va_destroy_surfaces(display, &surface, 1); + + return desc.objects[0].drm_format_modifier; +} + +static void gst_icamerasrc_get_supported_modifiers(GstVaDisplay *display, + GstVideoFormat format, + GValue *modifiers) { + guint64 mod = DRM_FORMAT_MOD_INVALID; + GValue gmod = G_VALUE_INIT; + guint usage_hint = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC; + + g_value_init(&gmod, G_TYPE_UINT64); + + mod = gst_va_dmabuf_get_modifier_for_format_for_icamerasrc(display, format, + usage_hint); + if (mod != DRM_FORMAT_MOD_INVALID) { + g_value_set_uint64(&gmod, mod); + gst_value_list_append_value(modifiers, &gmod); + } else { + GST_WARNING("Failed to get modifier %s:0x%016llx", + gst_video_format_to_string(format), DRM_FORMAT_MOD_INVALID); + } + + g_value_unset(&gmod); +} + +static inline gboolean va_format_is_rgb(const VAImageFormat *va_format) { + return va_format->depth != 0; +} + +static inline gboolean va_format_is_same_rgb(const VAImageFormat *fmt1, + const VAImageFormat *fmt2) { + 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); +} + +static inline gboolean va_format_is_same(const VAImageFormat *fmt1, + const VAImageFormat *fmt2) { + if (fmt1->fourcc != fmt2->fourcc) + return FALSE; + if (fmt1->byte_order != VA_NSB_FIRST && fmt2->byte_order != VA_NSB_FIRST && + fmt1->byte_order != fmt2->byte_order) + return FALSE; + return va_format_is_rgb(fmt1) ? va_format_is_same_rgb(fmt1, fmt2) : TRUE; +} + +static GstVideoFormat +find_gst_video_format_in_rgb32_map(VAImageFormat *image_format, + guint *drm_fourcc) { + guint i, j; + + for (i = 0; i < G_N_ELEMENTS(rgb32_format_map); i++) { + for (j = 0; j < G_N_ELEMENTS(rgb32_format_map[i].va_format); j++) { + if (va_format_is_same(&rgb32_format_map[i].va_format[j], image_format)) { + *drm_fourcc = rgb32_format_map[i].drm_fourcc; + return rgb32_format_map[i].format; + } + } + } + + return GST_VIDEO_FORMAT_UNKNOWN; +} + +struct ImageFormatArray { + VAImageFormat *image_formats; + gint len; +}; + +static gpointer fix_map(gpointer data) { + struct ImageFormatArray *args = (struct ImageFormatArray *)data; + GstVideoFormat format; + VAImageFormat *image_format; + struct FormatMap *map; + guint drm_fourcc = 0; + gint i; + + for (i = 0; i < args->len; i++) { + image_format = &args->image_formats[i]; + if (!va_format_is_rgb(image_format)) + continue; + format = find_gst_video_format_in_rgb32_map(image_format, &drm_fourcc); + if (format == GST_VIDEO_FORMAT_UNKNOWN) + continue; + map = get_format_map_from_video_format(format); + if (!map) + continue; + if (va_format_is_same(&map->va_format, image_format)) + continue; + + map->va_format = *image_format; + map->drm_fourcc = drm_fourcc; + + GST_INFO("GST_VIDEO_FORMAT_%s => { fourcc %" GST_FOURCC_FORMAT ", " + "drm fourcc %" GST_FOURCC_FORMAT ", %s, bpp %d, depth %d, " + "R %#010x, G %#010x, B %#010x, A %#010x }", + gst_video_format_to_string(map->format), + GST_FOURCC_ARGS(map->va_format.fourcc), + GST_FOURCC_ARGS(map->drm_fourcc), + (map->va_format.byte_order == 1) ? "LSB" : "MSB", + map->va_format.bits_per_pixel, map->va_format.depth, + map->va_format.red_mask, map->va_format.green_mask, + map->va_format.blue_mask, map->va_format.alpha_mask); + } + + return NULL; +} + +static void gst_va_video_format_fix_map(VAImageFormat *image_formats, + gint num) { + static GOnce once = G_ONCE_INIT; + struct ImageFormatArray args = {image_formats, num}; + + g_once(&once, fix_map, &args); +} + +static void _fix_map(GstVaDisplay *display) { + VAImageFormat *va_formats; + VADisplay dpy; + VAStatus status; + int max, num = 0; + + dpy = gst_va_display_get_va_dpy(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; +} + +gboolean CameraSrcUtils::_dma_fmt_to_dma_drm_fmts(GstVaDisplay *display, + const GstVideoFormat fmt, + GValue *dma_drm_fmts) { + gchar *drm_fmt_str; + guint32 drm_fourcc; + guint64 modifier; + GValue gval = G_VALUE_INIT; + GValue mods = G_VALUE_INIT; + + g_return_val_if_fail(fmt != GST_VIDEO_FORMAT_UNKNOWN, FALSE); + + _fix_map(display); + + 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_icamerasrc_get_supported_modifiers(display, fmt, &mods); + + for (guint 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 _modifier_found(guint64 modifier, guint64 *modifiers, + guint num_modifiers) { + guint i; + + /* user doesn't care the returned modifier */ + if (num_modifiers == 0) + return TRUE; + + for (i = 0; i < num_modifiers; i++) + if (modifier == modifiers[i]) + return TRUE; + return FALSE; +} + +/* +* @brief use libva to create surfaces +* @param is_only_linear_modifier If true, + only create linear dma buffer surfaces, or create others. +* @details If you want to support modifiers instead of linear modifier, + you can just drop is_only_linear_modifier +*/ +static gboolean va_create_surfaces(GstVaDisplay *display, guint rt_format, + guint fourcc, guint width, guint height, + gint usage_hint, guint64 *modifiers, + guint num_modifiers, + VADRMPRIMESurfaceDescriptor *desc, + VASurfaceID *surfaces, guint num_surfaces, gboolean is_only_linear_modifier = TRUE) { + VADisplay dpy = gst_va_display_get_va_dpy(display); + /* *INDENT-OFF* */ + VASurfaceAttrib attrs[6]; + memset(attrs, 0, sizeof(attrs)); + attrs[0].type = VASurfaceAttribUsageHint; + attrs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[0].value.type = VAGenericValueTypeInteger; + attrs[0].value.value.i = usage_hint; + attrs[1].type = VASurfaceAttribMemoryType; + attrs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[1].value.type = VAGenericValueTypeInteger; + attrs[1].value.value.i = (desc && desc->num_objects > 0) + ? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 + : VA_SURFACE_ATTRIB_MEM_TYPE_VA; + VADRMFormatModifierList modifier_list; + modifier_list.num_modifiers = num_modifiers; + modifier_list.modifiers = modifiers; + VASurfaceAttribExternalBuffers extbuf = {0}; + extbuf.width = width; + extbuf.height = height; + extbuf.num_planes = 1; + extbuf.pixel_format = fourcc; + /* *INDENT-ON* */ + VAStatus status; + guint num_attrs = 2; + + g_return_val_if_fail(num_surfaces > 0, FALSE); + /* must have modifiers when num_modifiers > 0 */ + g_return_val_if_fail(num_modifiers == 0 || modifiers, FALSE); + + if (fourcc > 0) { + /* *INDENT-OFF* */ + attrs[num_attrs].type = VASurfaceAttribPixelFormat; + attrs[num_attrs].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[num_attrs].value.type = VAGenericValueTypeInteger; + attrs[num_attrs].value.value.i = fourcc; + num_attrs++; + /* *INDENT-ON* */ + } + + if (desc && desc->num_objects > 0) { + /* *INDENT-OFF* */ + attrs[num_attrs].type = VASurfaceAttribExternalBufferDescriptor; + attrs[num_attrs].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[num_attrs].value.type = VAGenericValueTypePointer; + attrs[num_attrs].value.value.p = desc; + num_attrs++; + /* *INDENT-ON* */ + } else if (is_only_linear_modifier) { + /* HACK(victor): disable tiling for i965 driver for RGB formats */ + /* *INDENT-OFF* */ + attrs[num_attrs].type = VASurfaceAttribExternalBufferDescriptor; + attrs[num_attrs].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[num_attrs].value.type = VAGenericValueTypePointer; + attrs[num_attrs].value.value.p = &extbuf; + num_attrs++; + /* *INDENT-ON* */ + } + + if (num_modifiers > 0 && modifiers) { + /* *INDENT-OFF* */ + attrs[num_attrs].type = VASurfaceAttribDRMFormatModifiers; + attrs[num_attrs].flags = VA_SURFACE_ATTRIB_SETTABLE; + attrs[num_attrs].value.type = VAGenericValueTypePointer; + attrs[num_attrs].value.value.p = &modifier_list; + num_attrs++; + /* *INDENT-ON* */ + } + +retry: + status = vaCreateSurfaces(dpy, rt_format, width, height, surfaces, + num_surfaces, attrs, num_attrs); + + if (status == VA_STATUS_ERROR_ATTR_NOT_SUPPORTED && + attrs[num_attrs - 1].type == VASurfaceAttribDRMFormatModifiers) { + guint i; + + /* if requested modifiers contain linear, let's remove the attribute and + * "hope" the driver will create linear dmabufs */ + for (i = 0; i < num_modifiers; ++i) { + if (modifiers[i] == DRM_FORMAT_MOD_LINEAR) { + num_attrs--; + goto retry; + } + } + } + + if (status != VA_STATUS_SUCCESS) { + GST_ERROR("vaCreateSurfaces: %s", vaErrorStr(status)); + return FALSE; + } + + return TRUE; +} + +static gboolean va_export_surface_to_dmabuf(GstVaDisplay *display, + VASurfaceID surface, guint32 flags, + VADRMPRIMESurfaceDescriptor *desc) { + VADisplay dpy = gst_va_display_get_va_dpy(display); + VAStatus status; + + status = vaExportSurfaceHandle( + dpy, surface, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, flags, desc); + if (status != VA_STATUS_SUCCESS) { + GST_INFO("vaExportSurfaceHandle: %s", vaErrorStr(status)); + return FALSE; + } + + return TRUE; +} + +gboolean CameraSrcUtils::_va_create_surface_and_export_to_dmabuf( + GstVaDisplay *display, guint usage_hint, guint64 *modifiers, + guint num_modifiers, GstVideoInfo *info, VASurfaceID *ret_surface, + VADRMPRIMESurfaceDescriptor *ret_desc) { + VADRMPRIMESurfaceDescriptor desc = { + 0, + }; + guint32 i, fourcc, rt_format, export_flags; + GstVideoFormat format; + VASurfaceID surface; + guint64 prev_modifier = DRM_FORMAT_MOD_INVALID; + + format = GST_VIDEO_INFO_FORMAT(info); + + fourcc = gst_va_fourcc_from_video_format(format); + rt_format = gst_va_chroma_from_video_format(format); + if (fourcc == 0 || rt_format == 0) + return FALSE; + + if (!va_create_surfaces(display, rt_format, fourcc, + GST_VIDEO_INFO_WIDTH(info), + GST_VIDEO_INFO_HEIGHT(info), usage_hint, modifiers, + num_modifiers, NULL, &surface, 1)) + return FALSE; + + /* workaround for missing layered dmabuf formats in i965 */ + if (GST_VA_DISPLAY_IS_IMPLEMENTATION(display, INTEL_I965) && + (fourcc == VA_FOURCC_YUY2 || fourcc == VA_FOURCC_UYVY)) { + /* These are not representable as separate planes */ + export_flags = VA_EXPORT_SURFACE_COMPOSED_LAYERS; + } else { + /* Each layer will contain exactly one plane. For example, an NV12 + * surface will be exported as two layers */ + export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS; + } + + export_flags |= VA_EXPORT_SURFACE_READ_WRITE; + + if (!va_export_surface_to_dmabuf(display, surface, export_flags, &desc)) + goto failed; + + if (GST_VIDEO_INFO_N_PLANES(info) != desc.num_layers) + goto failed; + + /* YUY2 and YUYV are the same. radeonsi returns always YUYV. + * There's no reason to fail if the different fourcc if there're dups. + * https://fourcc.org/pixel-format/yuv-yuy2/ */ + if (fourcc != desc.fourcc) { + GST_INFO("Different fourcc: requested %" GST_FOURCC_FORMAT + " - returned %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS(fourcc), GST_FOURCC_ARGS(desc.fourcc)); + } + + if (desc.num_objects == 0) { + GST_ERROR("Failed to export surface to dmabuf"); + goto failed; + } + + for (i = 0; i < desc.num_objects; i++) { + guint64 modifier = desc.objects[i].drm_format_modifier; + + if (!_modifier_found(modifier, modifiers, num_modifiers)) { + GST_ERROR("driver set a modifier different from allowed list: " + "0x%016" G_GINT64_MODIFIER "x", + modifier); + goto failed; + } + /* XXX: all dmabufs in buffer have to have the same modifier, otherwise the + * drm-format field in caps is ill-designed */ + if (i > 0 && modifier != prev_modifier) { + GST_ERROR("Different objects have different modifier"); + goto failed; + } + + prev_modifier = modifier; + } + + *ret_surface = surface; + if (ret_desc) + *ret_desc = desc; + + return TRUE; + +failed : { + va_destroy_surfaces(display, &surface, 1); + return FALSE; +} +} + +goffset CameraSrcUtils::_get_fd_size(gint fd) { +#ifndef G_OS_WIN32 + return lseek(fd, 0, SEEK_END); +#else + return 0; +#endif +} + +#endif diff --git a/src/utils.h b/src/utils.h index 55d9719..2a938dd 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,6 +1,6 @@ /* * GStreamer - * Copyright (C) 2016-2021 Intel Corporation + * Copyright (C) 2016-2024 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -55,6 +55,15 @@ #include #include +#ifdef GST_DRM_FORMAT +#include +#include +#define GST_USE_UNSTABLE_API +#include +#undef GST_USE_UNSTABLE_API +#include +#endif + using namespace std; #define ALIGN(val, alignment) (((val)+(alignment)-1) & ~((alignment)-1)) @@ -104,7 +113,25 @@ namespace CameraSrcUtils { void get_stream_info_by_caps(GstCaps *caps, const char **format, int *width, int *height); - int get_stream_id_by_pad(map streamMap, GstPad *pad); -} + int get_stream_id_by_pad(map &streamMap, GstPad *pad); + +#ifdef GST_DRM_FORMAT + + gboolean gst_video_info_from_dma_drm_caps(GstVideoInfo *info, + const GstCaps *caps); + + gboolean _dma_fmt_to_dma_drm_fmts(GstVaDisplay *display, + const GstVideoFormat fmt, + GValue *dma_drm_fmts); + + gboolean _va_create_surface_and_export_to_dmabuf( + GstVaDisplay *display, guint usage_hint, guint64 *modifiers, + guint num_modifiers, GstVideoInfo *info, VASurfaceID *ret_surface, + VADRMPRIMESurfaceDescriptor *ret_desc); + + goffset _get_fd_size(gint fd); + +#endif + } // namespace CameraSrcUtils #endif