blob: 21b38d8da587ed16b566b55c2ee3a585e55bf203 [file] [log] [blame]
/*
* gstxcamfilter.cpp -gst xcamfilter plugin
*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Yinhang Liu <yinhangx.liu@intel.com>
*/
#include "gstxcamfilter.h"
#include "gstxcambuffermeta.h"
#include <gst/gstmeta.h>
#include <gst/allocators/gstdmabuf.h>
using namespace XCam;
using namespace GstXCam;
#define DEFAULT_SMART_ANALYSIS_LIB_DIR "/usr/lib/xcam/plugins/smart"
#define DEFAULT_DELAY_BUFFER_NUM 2
#define DEFAULT_PROP_BUFFERCOUNT 8
#define DEFAULT_PROP_COPY_MODE COPY_MODE_CPU
#define DEFAULT_PROP_DEFOG_MODE DEFOG_NONE
#define DEFAULT_PROP_WAVELET_MODE NONE_WAVELET
#define DEFAULT_PROP_3D_DENOISE_MODE DENOISE_3D_NONE
#define DEFAULT_PROP_ENABLE_WIREFRAME FALSE
#define DEFAULT_PROP_ENABLE_IMAGE_WARP FALSE
#define DEFAULT_PROP_ENABLE_IMAGE_STITCH FALSE
#define DEFAULT_PROP_STITCH_ENABLE_SEAM FALSE
#define DEFAULT_PROP_STITCH_SCALE_MODE CLBlenderScaleLocal
#define DEFAULT_PROP_STITCH_FISHEYE_MAP FALSE
#define DEFAULT_PROP_STITCH_LSC FALSE
#define DEFAULT_PROP_STITCH_FM_OCL FALSE
#define DEFAULT_PROP_STITCH_RES_MODE StitchRes1080P
XCAM_BEGIN_DECLARE
enum {
PROP_0,
PROP_BUFFERCOUNT,
PROP_COPY_MODE,
PROP_DEFOG_MODE,
PROP_WAVELET_MODE,
PROP_DENOISE_3D_MODE,
PROP_ENABLE_WIREFRAME,
PROP_ENABLE_IMAGE_WARP,
PROP_ENABLE_IMAGE_STITCH,
PROP_STITCH_ENABLE_SEAM,
PROP_STITCH_SCALE_MODE,
PROP_STITCH_FISHEYE_MAP,
PROP_STITCH_LSC,
PROP_STITCH_FM_OCL,
PROP_STITCH_RES_MODE
};
#define GST_TYPE_XCAM_FILTER_COPY_MODE (gst_xcam_filter_copy_mode_get_type ())
static GType
gst_xcam_filter_copy_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue copy_mode_types[] = {
{COPY_MODE_CPU, "Copy buffer with CPU", "cpu"},
{COPY_MODE_DMA, "Copy buffer with DMA", "dma"},
{0, NULL, NULL}
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilterCopyModeType", copy_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
#define GST_TYPE_XCAM_FILTER_DEFOG_MODE (gst_xcam_filter_defog_mode_get_type ())
static GType
gst_xcam_filter_defog_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue defog_mode_types [] = {
{DEFOG_NONE, "Defog disabled", "none"},
{DEFOG_RETINEX, "Defog retinex", "retinex"},
{DEFOG_DCP, "Defog dark channel prior", "dcp"},
{0, NULL, NULL}
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilterDefogModeType", defog_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
#define GST_TYPE_XCAM_FILTER_WAVELET_MODE (gst_xcam_filter_wavelet_mode_get_type ())
static GType
gst_xcam_filter_wavelet_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue wavelet_mode_types[] = {
{NONE_WAVELET, "Wavelet disabled", "none"},
{HAT_WAVELET_Y, "Hat wavelet Y", "hat Y"},
{HAT_WAVELET_UV, "Hat wavelet UV", "hat UV"},
{HARR_WAVELET_Y, "Haar wavelet Y", "haar Y"},
{HARR_WAVELET_UV, "Haar wavelet UV", "haar UV"},
{HARR_WAVELET_YUV, "Haar wavelet YUV", "haar YUV"},
{HARR_WAVELET_BAYES, "Haar wavelet bayes shrink", "haar Bayes"},
{0, NULL, NULL},
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilterWaveletModeType", wavelet_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
#define GST_TYPE_XCAM_FILTER_3D_DENOISE_MODE (gst_xcam_filter_3d_denoise_mode_get_type ())
static GType
gst_xcam_filter_3d_denoise_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue denoise_3d_mode_types [] = {
{DENOISE_3D_NONE, "3D Denoise disabled", "none"},
{DENOISE_3D_YUV, "3D Denoise yuv", "yuv"},
{DENOISE_3D_UV, "3D Denoise uv", "uv"},
{0, NULL, NULL}
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilter3DDenoiseModeType", denoise_3d_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
#define GST_TYPE_XCAM_FILTER_STITCH_SCALE_MODE (gst_xcam_filter_stitch_scale_mode_get_type ())
static GType
gst_xcam_filter_stitch_scale_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue stitch_scale_mode_types [] = {
{CLBlenderScaleLocal, "Image stitch local scale", "local"},
{CLBlenderScaleGlobal, "Image stitch glocal scale", "global"},
{0, NULL, NULL}
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilterStitchScaleModeType", stitch_scale_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
#define GST_TYPE_XCAM_FILTER_STITCH_RES_MODE (gst_xcam_filter_stitch_res_mode_get_type ())
static GType
gst_xcam_filter_stitch_res_mode_get_type (void)
{
static GType g_type = 0;
static const GEnumValue stitch_res_mode_types [] = {
{StitchRes1080P, "Image stitch 1080P mode", "1080p"},
{StitchRes4K, "Image stitch 4K mode", "4k"},
{0, NULL, NULL}
};
if (g_once_init_enter (&g_type)) {
const GType type =
g_enum_register_static ("GstXCamFilterStitchResModeType", stitch_res_mode_types);
g_once_init_leave (&g_type, type);
}
return g_type;
}
static GstStaticPadTemplate gst_xcam_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12 }")));
static GstStaticPadTemplate gst_xcam_src_factory =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ NV12 }")));
GST_DEBUG_CATEGORY (gst_xcam_filter_debug);
#define GST_CAT_DEFAULT gst_xcam_filter_debug
#define gst_xcam_filter_parent_class parent_class
G_DEFINE_TYPE (GstXCamFilter, gst_xcam_filter, GST_TYPE_BASE_TRANSFORM);
static void gst_xcam_filter_finalize (GObject * object);
static void gst_xcam_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_xcam_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static gboolean gst_xcam_filter_start (GstBaseTransform *trans);
static GstCaps *gst_xcam_filter_transform_caps (
GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter);
static gboolean gst_xcam_filter_set_caps (GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps);
static gboolean gst_xcam_filter_stop (GstBaseTransform *trans);
static void gst_xcam_filter_before_transform (GstBaseTransform *trans, GstBuffer *buffer);
static GstFlowReturn gst_xcam_filter_prepare_output_buffer (GstBaseTransform * trans, GstBuffer *input, GstBuffer **outbuf);
static GstFlowReturn gst_xcam_filter_transform (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf);
XCAM_END_DECLARE
static void
gst_xcam_filter_class_init (GstXCamFilterClass *class_self)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstBaseTransformClass *basetrans_class;
gobject_class = (GObjectClass *) class_self;
element_class = (GstElementClass *) class_self;
basetrans_class = (GstBaseTransformClass *) class_self;
GST_DEBUG_CATEGORY_INIT (gst_xcam_filter_debug, "xcamfilter", 0, "LibXCam filter plugin");
gobject_class->finalize = gst_xcam_filter_finalize;
gobject_class->set_property = gst_xcam_filter_set_property;
gobject_class->get_property = gst_xcam_filter_get_property;
g_object_class_install_property (
gobject_class, PROP_BUFFERCOUNT,
g_param_spec_int ("buffercount", "buffer count", "Buffer count",
0, G_MAXINT, DEFAULT_PROP_BUFFERCOUNT,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_COPY_MODE,
g_param_spec_enum ("copy-mode", "copy mode", "Copy Mode",
GST_TYPE_XCAM_FILTER_COPY_MODE, DEFAULT_PROP_COPY_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_DEFOG_MODE,
g_param_spec_enum ("defog-mode", "defog mode", "Defog mode",
GST_TYPE_XCAM_FILTER_DEFOG_MODE, DEFAULT_PROP_DEFOG_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_WAVELET_MODE,
g_param_spec_enum ("wavelet-mode", "wavelet mode", "Wavelet Mode",
GST_TYPE_XCAM_FILTER_WAVELET_MODE, DEFAULT_PROP_WAVELET_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_DENOISE_3D_MODE,
g_param_spec_enum ("denoise-3d", "3D Denoise mode", "3D Denoise mode",
GST_TYPE_XCAM_FILTER_3D_DENOISE_MODE, DEFAULT_PROP_3D_DENOISE_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_ENABLE_WIREFRAME,
g_param_spec_boolean ("enable-wireframe", "enable wire frame", "Enable wire frame",
DEFAULT_PROP_ENABLE_WIREFRAME, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_ENABLE_IMAGE_WARP,
g_param_spec_boolean ("enable-warp", "enable image warp", "Enable Image Warp",
DEFAULT_PROP_ENABLE_IMAGE_WARP, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_ENABLE_IMAGE_STITCH,
g_param_spec_boolean ("enable-stitch", "enable image stitch", "Enable Image Stitch",
DEFAULT_PROP_ENABLE_IMAGE_STITCH, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_STITCH_ENABLE_SEAM,
g_param_spec_boolean ("stitch-seam", "enable seam just for stitch", "Enable Seam Just For Stitch",
DEFAULT_PROP_STITCH_ENABLE_SEAM, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_STITCH_SCALE_MODE,
g_param_spec_enum ("stitch-scale", "stitch scale mode", "Stitch Scale Mode",
GST_TYPE_XCAM_FILTER_STITCH_SCALE_MODE, DEFAULT_PROP_STITCH_SCALE_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_STITCH_FISHEYE_MAP,
g_param_spec_boolean ("stitch-fisheye-map", "stitch fisheye map", "Enable fisheye map for stitch",
DEFAULT_PROP_STITCH_FISHEYE_MAP, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (
gobject_class, PROP_STITCH_LSC,
g_param_spec_boolean ("stitch-lsc", "stitch enable lens shading correction", "Enable Lens Shading Correction",
DEFAULT_PROP_STITCH_LSC, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
#if HAVE_OPENCV
g_object_class_install_property (
gobject_class, PROP_STITCH_FM_OCL,
g_param_spec_boolean ("stitch-fm-ocl", "stitch enable ocl for feature match", "Enable ocl for feature match",
DEFAULT_PROP_STITCH_FM_OCL, (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
#endif
g_object_class_install_property (
gobject_class, PROP_STITCH_RES_MODE,
g_param_spec_enum ("stitch-res-mode", "stitch resolution mode", "Stitch Resolution Mode",
GST_TYPE_XCAM_FILTER_STITCH_RES_MODE, DEFAULT_PROP_STITCH_RES_MODE,
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
gst_element_class_set_details_simple (element_class,
"Libxcam Filter",
"Filter/Effect/Video",
"Process NV12 stream using xcam library",
"Wind Yuan <feng.yuan@intel.com> & Yinhang Liu <yinhangx.liu@intel.com>");
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_xcam_src_factory));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_xcam_sink_factory));
basetrans_class->start = GST_DEBUG_FUNCPTR (gst_xcam_filter_start);
basetrans_class->stop = GST_DEBUG_FUNCPTR (gst_xcam_filter_stop);
basetrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_xcam_filter_transform_caps);
basetrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_xcam_filter_set_caps);
basetrans_class->before_transform = GST_DEBUG_FUNCPTR (gst_xcam_filter_before_transform);
basetrans_class->prepare_output_buffer = GST_DEBUG_FUNCPTR (gst_xcam_filter_prepare_output_buffer);
basetrans_class->transform = GST_DEBUG_FUNCPTR (gst_xcam_filter_transform);
}
static void
gst_xcam_filter_init (GstXCamFilter *xcamfilter)
{
xcamfilter->buf_count = DEFAULT_PROP_BUFFERCOUNT;
xcamfilter->copy_mode = DEFAULT_PROP_COPY_MODE;
xcamfilter->defog_mode = DEFAULT_PROP_DEFOG_MODE;
xcamfilter->wavelet_mode = DEFAULT_PROP_WAVELET_MODE;
xcamfilter->denoise_3d_mode = DEFAULT_PROP_3D_DENOISE_MODE;
xcamfilter->denoise_3d_ref_count = 2;
xcamfilter->enable_wireframe = DEFAULT_PROP_ENABLE_WIREFRAME;
xcamfilter->enable_image_warp = DEFAULT_PROP_ENABLE_IMAGE_WARP;
xcamfilter->enable_stitch = DEFAULT_PROP_ENABLE_IMAGE_STITCH;
xcamfilter->stitch_enable_seam = DEFAULT_PROP_STITCH_ENABLE_SEAM;
xcamfilter->stitch_fisheye_map = DEFAULT_PROP_STITCH_FISHEYE_MAP;
xcamfilter->stitch_lsc = DEFAULT_PROP_STITCH_LSC;
xcamfilter->stitch_fm_ocl = DEFAULT_PROP_STITCH_FM_OCL;
xcamfilter->stitch_scale_mode = DEFAULT_PROP_STITCH_SCALE_MODE;
xcamfilter->stitch_res_mode = DEFAULT_PROP_STITCH_RES_MODE;
xcamfilter->delay_buf_num = DEFAULT_DELAY_BUFFER_NUM;
xcamfilter->cached_buf_num = 0;
XCAM_CONSTRUCTOR (xcamfilter->pipe_manager, SmartPtr<MainPipeManager>);
xcamfilter->pipe_manager = new MainPipeManager;
XCAM_ASSERT (xcamfilter->pipe_manager.ptr ());
}
static void
gst_xcam_filter_finalize (GObject *object)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object);
if (xcamfilter->allocator)
gst_object_unref (xcamfilter->allocator);
xcamfilter->pipe_manager.release ();
XCAM_DESTRUCTOR (xcamfilter->pipe_manager, SmartPtr<MainPipeManager>);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_xcam_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object);
switch (prop_id) {
case PROP_BUFFERCOUNT:
xcamfilter->buf_count = g_value_get_int (value);
break;
case PROP_COPY_MODE:
xcamfilter->copy_mode = (CopyMode) g_value_get_enum (value);
break;
case PROP_DEFOG_MODE:
xcamfilter->defog_mode = (DefogModeType) g_value_get_enum (value);
break;
case PROP_WAVELET_MODE:
xcamfilter->wavelet_mode = (WaveletModeType) g_value_get_enum (value);
break;
case PROP_DENOISE_3D_MODE:
xcamfilter->denoise_3d_mode = (Denoise3DModeType) g_value_get_enum (value);
break;
case PROP_ENABLE_WIREFRAME:
xcamfilter->enable_wireframe = g_value_get_boolean (value);
break;
case PROP_ENABLE_IMAGE_WARP:
xcamfilter->enable_image_warp = g_value_get_boolean (value);
break;
case PROP_ENABLE_IMAGE_STITCH:
xcamfilter->enable_stitch = g_value_get_boolean (value);
break;
case PROP_STITCH_ENABLE_SEAM:
xcamfilter->stitch_enable_seam = g_value_get_boolean (value);
break;
case PROP_STITCH_SCALE_MODE:
xcamfilter->stitch_scale_mode = (CLBlenderScaleMode) g_value_get_enum (value);
break;
case PROP_STITCH_FISHEYE_MAP:
xcamfilter->stitch_fisheye_map = g_value_get_boolean (value);
break;
case PROP_STITCH_LSC:
xcamfilter->stitch_lsc = g_value_get_boolean (value);
break;
#if HAVE_OPENCV
case PROP_STITCH_FM_OCL:
xcamfilter->stitch_fm_ocl = g_value_get_boolean (value);
break;
#endif
case PROP_STITCH_RES_MODE:
xcamfilter->stitch_res_mode = (StitchResMode) g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_xcam_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (object);
switch (prop_id) {
case PROP_BUFFERCOUNT:
g_value_set_int (value, xcamfilter->buf_count);
break;
case PROP_COPY_MODE:
g_value_set_enum (value, xcamfilter->copy_mode);
break;
case PROP_DEFOG_MODE:
g_value_set_enum (value, xcamfilter->defog_mode);
break;
case PROP_WAVELET_MODE:
g_value_set_enum (value, xcamfilter->wavelet_mode);
break;
case PROP_DENOISE_3D_MODE:
g_value_set_enum (value, xcamfilter->denoise_3d_mode);
break;
case PROP_ENABLE_WIREFRAME:
g_value_set_boolean (value, xcamfilter->enable_wireframe);
break;
case PROP_ENABLE_IMAGE_WARP:
g_value_set_boolean (value, xcamfilter->enable_image_warp);
break;
case PROP_ENABLE_IMAGE_STITCH:
g_value_set_boolean (value, xcamfilter->enable_stitch);
break;
case PROP_STITCH_ENABLE_SEAM:
g_value_set_boolean (value, xcamfilter->stitch_enable_seam);
break;
case PROP_STITCH_SCALE_MODE:
g_value_set_enum (value, xcamfilter->stitch_scale_mode);
break;
case PROP_STITCH_FISHEYE_MAP:
g_value_set_boolean (value, xcamfilter->stitch_fisheye_map);
break;
case PROP_STITCH_LSC:
g_value_set_boolean (value, xcamfilter->stitch_lsc);
break;
#if HAVE_OPENCV
case PROP_STITCH_FM_OCL:
g_value_set_boolean (value, xcamfilter->stitch_fm_ocl);
break;
#endif
case PROP_STITCH_RES_MODE:
g_value_set_enum (value, xcamfilter->stitch_res_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_xcam_filter_start (GstBaseTransform *trans)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
if (xcamfilter->buf_count <= xcamfilter->delay_buf_num) {
XCAM_LOG_ERROR (
"buffer count (%d) should be greater than delayed buffer number (%d)",
xcamfilter->buf_count,
xcamfilter->delay_buf_num);
return false;
}
SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
SmartPtr<SmartAnalyzer> smart_analyzer;
SmartPtr<CLPostImageProcessor> image_processor;
SmartHandlerList smart_handlers = SmartAnalyzerLoader::load_smart_handlers (DEFAULT_SMART_ANALYSIS_LIB_DIR);
if (!smart_handlers.empty ()) {
smart_analyzer = new SmartAnalyzer ();
if (smart_analyzer.ptr ()) {
SmartHandlerList::iterator i_handler = smart_handlers.begin ();
for (; i_handler != smart_handlers.end (); ++i_handler)
{
XCAM_ASSERT ((*i_handler).ptr ());
smart_analyzer->add_handler (*i_handler);
}
if (smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_WARNING ("analyzer(%s) prepare handlers failed", smart_analyzer->get_name ());
return false;
}
pipe_manager->set_smart_analyzer (smart_analyzer);
} else {
XCAM_LOG_WARNING ("load smart analyzer(%s) failed, please check.", DEFAULT_SMART_ANALYSIS_LIB_DIR);
}
}
image_processor = new CLPostImageProcessor ();
XCAM_ASSERT (image_processor.ptr ());
image_processor->set_stats_callback (pipe_manager);
image_processor->set_defog_mode ((CLPostImageProcessor::CLDefogMode) xcamfilter->defog_mode);
if (NONE_WAVELET != xcamfilter->wavelet_mode) {
if (HAT_WAVELET_Y == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_Y, false);
} else if (HAT_WAVELET_UV == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAT, CL_IMAGE_CHANNEL_UV, false);
} else if (HARR_WAVELET_Y == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_Y, false);
} else if (HARR_WAVELET_UV == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV, false);
} else if (HARR_WAVELET_YUV == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, false);
} else if (HARR_WAVELET_BAYES == xcamfilter->wavelet_mode) {
image_processor->set_wavelet (CL_WAVELET_HAAR, CL_IMAGE_CHANNEL_UV | CL_IMAGE_CHANNEL_Y, true);
} else {
image_processor->set_wavelet (CL_WAVELET_DISABLED, CL_IMAGE_CHANNEL_UV, false);
}
}
image_processor->set_3ddenoise_mode (
(CLPostImageProcessor::CL3DDenoiseMode) xcamfilter->denoise_3d_mode, xcamfilter->denoise_3d_ref_count);
image_processor->set_wireframe (xcamfilter->enable_wireframe);
image_processor->set_image_warp (xcamfilter->enable_image_warp);
if (smart_analyzer.ptr ()) {
if (xcamfilter->enable_wireframe)
image_processor->set_scaler (true);
if (xcamfilter->enable_image_warp) {
image_processor->set_scaler (true);
xcamfilter->delay_buf_num = DEFAULT_DELAY_BUFFER_NUM + 16;
}
}
pipe_manager->add_image_processor (image_processor);
pipe_manager->set_image_processor (image_processor);
xcamfilter->buf_pool = new CLVideoBufferPool ();
XCAM_ASSERT (xcamfilter->buf_pool.ptr ());
if (xcamfilter->copy_mode == COPY_MODE_DMA) {
XCAM_LOG_WARNING ("CLVideoBuffer doesn't support DMA copy mode, switch to CPU copy mode");
xcamfilter->copy_mode = COPY_MODE_CPU;
}
if (xcamfilter->copy_mode == COPY_MODE_DMA) {
xcamfilter->allocator = gst_dmabuf_allocator_new ();
if (!xcamfilter->allocator) {
GST_WARNING ("xcamfilter get allocator failed");
return false;
}
}
return true;
}
static gboolean
gst_xcam_filter_stop (GstBaseTransform *trans)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool;
if (buf_pool.ptr ())
buf_pool->stop ();
SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
if (pipe_manager.ptr ())
pipe_manager->stop ();
return true;
}
static GstCaps *
gst_xcam_filter_transform_caps (
GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
GstCaps *src_caps, *peer_caps, *intersect_caps;
GstStructure *sink_struct, *src_struct;
GstPad *peer_pad;
gint sink_width, sink_height, src_width, src_height;
gboolean is_sink_width = false;
gboolean is_sink_height = false;
src_caps = gst_pad_get_pad_template_caps (trans->srcpad);
if (direction == GST_PAD_SRC || !gst_caps_is_fixed (caps))
goto filtering;
sink_struct = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (sink_struct, "width", &sink_width) ||
!gst_structure_get_int (sink_struct, "height", &sink_height))
goto filtering;
peer_pad = gst_pad_get_peer (trans->srcpad);
peer_caps = gst_pad_query_caps (peer_pad, src_caps);
if (!peer_pad || gst_caps_is_empty (peer_caps)) {
if (xcamfilter->enable_stitch) {
src_height = XCAM_ALIGN_UP (sink_width / 2, 16);
if (src_height * 2 != sink_width) {
gst_caps_unref (src_caps);
gst_caps_unref (peer_caps);
XCAM_LOG_ERROR ("xcamfilter stitch incorrect size, sink-width(%d) / 2 should be aligned with 16",
sink_width);
return NULL;
}
src_width = sink_width;
gst_caps_unref (src_caps);
src_caps = gst_caps_copy (caps);
src_struct = gst_caps_get_structure (src_caps, 0);
gst_structure_set (src_struct, "width", G_TYPE_INT, src_width,
"height", G_TYPE_INT, src_height, NULL);
}
gst_caps_unref (peer_caps);
goto filtering;
}
intersect_caps = gst_caps_intersect_full (peer_caps, src_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (src_caps);
src_caps = intersect_caps;
src_struct = gst_caps_get_structure (src_caps, 0);
if (!gst_structure_get_int (src_struct, "width", &src_width)) {
is_sink_width = true;
src_width = sink_width;
}
if (!gst_structure_get_int (src_struct, "height", &src_height)) {
is_sink_height = true;
src_height = sink_height;
}
if (xcamfilter->enable_stitch) {
if (is_sink_width && is_sink_height)
src_height = XCAM_ALIGN_UP (src_width / 2, 16);
if (src_width != src_height * 2) {
XCAM_LOG_ERROR ("xcamfilter incorrect stitch size width:%d height:%d", src_width, src_height);
gst_caps_unref (src_caps);
return NULL;
}
}
gint fps_n, fps_d;
if (!gst_structure_get_fraction (src_struct, "framerate", &fps_n, &fps_d) &&
!gst_structure_get_fraction (sink_struct, "framerate", &fps_n, &fps_d)) {
fps_n = 25;
fps_d = 1;
}
gst_structure_set (src_struct, "width", G_TYPE_INT, src_width,
"height", G_TYPE_INT, src_height,
"framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
filtering:
if (filter) {
intersect_caps = gst_caps_intersect_full (filter, src_caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (src_caps);
src_caps = intersect_caps;
}
return src_caps;
}
static gboolean
gst_xcam_filter_set_caps (GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
GstVideoInfo in_info, out_info;
if (!gst_video_info_from_caps (&in_info, incaps) ||
!gst_video_info_from_caps (&out_info, outcaps)) {
XCAM_LOG_WARNING ("fail to parse incaps or outcaps");
return false;
}
XCAM_FAIL_RETURN (
ERROR,
GST_VIDEO_INFO_FORMAT (&in_info) == GST_VIDEO_FORMAT_NV12 ||
GST_VIDEO_INFO_FORMAT (&out_info) == GST_VIDEO_FORMAT_NV12,
false,
"xcamfilter only support NV12 stream");
xcamfilter->gst_sink_video_info = in_info;
xcamfilter->gst_src_video_info = out_info;
SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
SmartPtr<CLPostImageProcessor> processor = pipe_manager->get_image_processor();
XCAM_ASSERT (pipe_manager.ptr () && processor.ptr ());
if (!processor->set_output_format (V4L2_PIX_FMT_NV12))
return false;
if (processor->is_scaled ())
processor->set_scaler_factor (640.0 / GST_VIDEO_INFO_WIDTH (&in_info));
//processor->set_scaler_factor (0.5f);
if (xcamfilter->enable_stitch) {
processor->set_image_stitch (
xcamfilter->enable_stitch, xcamfilter->stitch_enable_seam, xcamfilter->stitch_scale_mode,
xcamfilter->stitch_fisheye_map, xcamfilter->stitch_lsc, xcamfilter->stitch_fm_ocl,
GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info), (uint32_t) xcamfilter->stitch_res_mode);
XCAM_LOG_INFO ("xcamfilter stitch output size width:%d height:%d",
GST_VIDEO_INFO_WIDTH (&out_info), GST_VIDEO_INFO_HEIGHT (&out_info));
}
if (pipe_manager->start () != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_ERROR ("pipe manager start failed");
return false;
}
VideoBufferInfo buf_info;
buf_info.init (
V4L2_PIX_FMT_NV12,
GST_VIDEO_INFO_WIDTH (&in_info),
GST_VIDEO_INFO_HEIGHT (&in_info),
XCAM_ALIGN_UP (GST_VIDEO_INFO_WIDTH (&in_info), 16),
XCAM_ALIGN_UP (GST_VIDEO_INFO_HEIGHT (&in_info), 16));
SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool;
XCAM_ASSERT (buf_pool.ptr ());
if (!buf_pool->set_video_info (buf_info) ||
!buf_pool->reserve (xcamfilter->buf_count)) {
XCAM_LOG_ERROR ("init buffer pool failed");
return false;
}
return true;
}
static GstFlowReturn
copy_gstbuf_to_xcambuf (GstVideoInfo gstinfo, GstBuffer *gstbuf, SmartPtr<VideoBuffer> xcambuf)
{
GstMapInfo mapinfo;
VideoBufferPlanarInfo planar;
const VideoBufferInfo xcaminfo = xcambuf->get_video_info ();
uint8_t *memory = xcambuf->map ();
gboolean ret = gst_buffer_map (gstbuf, &mapinfo, GST_MAP_READ);
if (!memory || !ret) {
XCAM_LOG_WARNING ("xcamfilter map buffer failed");
return GST_FLOW_ERROR;
}
uint8_t *src = NULL;
uint8_t *dest = NULL;
for (uint32_t index = 0; index < xcaminfo.components; index++) {
xcaminfo.get_planar_info (planar, index);
src = mapinfo.data + GST_VIDEO_INFO_PLANE_OFFSET (&gstinfo, index);
dest = memory + xcaminfo.offsets [index];
for (uint32_t i = 0; i < planar.height; i++) {
memcpy (dest, src, GST_VIDEO_INFO_WIDTH (&gstinfo));
src += GST_VIDEO_INFO_PLANE_STRIDE (&gstinfo, index);
dest += xcaminfo.strides [index];
}
}
gst_buffer_unmap (gstbuf, &mapinfo);
xcambuf->unmap ();
return GST_FLOW_OK;
}
static GstFlowReturn
copy_xcambuf_to_gstbuf (GstVideoInfo gstinfo, SmartPtr<VideoBuffer> xcambuf, GstBuffer **gstbuf)
{
GstMapInfo mapinfo;
VideoBufferPlanarInfo planar;
const VideoBufferInfo xcaminfo = xcambuf->get_video_info ();
GstBuffer *tmpbuf = gst_buffer_new_allocate (NULL, GST_VIDEO_INFO_SIZE (&gstinfo), NULL);
if (!tmpbuf) {
XCAM_LOG_ERROR ("xcamfilter allocate buffer failed");
return GST_FLOW_ERROR;
}
uint8_t *memory = xcambuf->map ();
gboolean ret = gst_buffer_map (tmpbuf, &mapinfo, GST_MAP_WRITE);
if (!memory || !ret) {
XCAM_LOG_WARNING ("xcamfilter map buffer failed");
return GST_FLOW_ERROR;
}
uint8_t *src = NULL;
uint8_t *dest = NULL;
for (uint32_t index = 0; index < GST_VIDEO_INFO_N_PLANES (&gstinfo); index++) {
xcaminfo.get_planar_info (planar, index);
src = memory + xcaminfo.offsets [index];
dest = mapinfo.data + GST_VIDEO_INFO_PLANE_OFFSET (&gstinfo, index);
for (uint32_t i = 0; i < planar.height; i++) {
memcpy (dest, src, planar.width);
src += xcaminfo.strides [index];
dest += GST_VIDEO_INFO_PLANE_STRIDE (&gstinfo, index);
}
}
gst_buffer_unmap (tmpbuf, &mapinfo);
xcambuf->unmap ();
*gstbuf = tmpbuf;
return GST_FLOW_OK;
}
static GstFlowReturn
append_xcambuf_to_gstbuf (GstAllocator *allocator, SmartPtr<VideoBuffer> xcambuf, GstBuffer **gstbuf)
{
gsize offsets [XCAM_VIDEO_MAX_COMPONENTS];
VideoBufferInfo xcaminfo = xcambuf->get_video_info ();
for (int i = 0; i < XCAM_VIDEO_MAX_COMPONENTS; i++) {
offsets [i] = xcaminfo.offsets [i];
}
GstBuffer *tmpbuf = gst_buffer_new ();
GstMemory *mem = gst_dmabuf_allocator_alloc (allocator, dup (xcambuf->get_fd ()), xcambuf->get_size ());
XCAM_ASSERT (mem);
gst_buffer_append_memory (tmpbuf, mem);
gst_buffer_add_video_meta_full (
tmpbuf,
GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_FORMAT_NV12,
xcaminfo.width,
xcaminfo.height,
xcaminfo.components,
offsets,
(gint *) (xcaminfo.strides));
*gstbuf = tmpbuf;
return GST_FLOW_OK;
}
static gint
get_dmabuf_fd (GstBuffer *buffer)
{
GstMemory *mem = gst_buffer_peek_memory (buffer, 0);
if (!gst_is_dmabuf_memory (mem)) {
return -1;
}
return gst_dmabuf_memory_get_fd (mem);
}
static void
gst_xcam_filter_before_transform (GstBaseTransform *trans, GstBuffer *buffer)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
SmartPtr<BufferPool> buf_pool = xcamfilter->buf_pool;
SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
XCAM_ASSERT (buf_pool.ptr () && pipe_manager.ptr ());
if (xcamfilter->cached_buf_num > xcamfilter->delay_buf_num)
return;
SmartPtr<VideoBuffer> video_buf;
gint dma_fd = get_dmabuf_fd (buffer);
if (dma_fd >= 0) {
#if HAVE_LIBDRM
SmartPtr<DrmBoBufferPool> bo_buf_pool = buf_pool.dynamic_cast_ptr<DrmBoBufferPool> ();
SmartPtr<DrmDisplay> display = bo_buf_pool->get_drm_display ();
VideoBufferInfo info = bo_buf_pool->get_video_info ();
SmartPtr<VideoBuffer> dma_buf = new DmaGstBuffer (info, dma_fd, buffer);
video_buf = display->convert_to_drm_bo_buf (display, dma_buf);
#endif
if (!video_buf.ptr ()) {
XCAM_LOG_ERROR ("xcamfilter convert to drm bo buffer failed");
return;
}
} else {
video_buf = buf_pool->get_buffer (buf_pool);
if (!buf_pool.ptr ()) {
XCAM_LOG_ERROR ("xcamfilter sink-pad get buffer failed");
return;
}
copy_gstbuf_to_xcambuf (xcamfilter->gst_sink_video_info, buffer, video_buf);
}
if (pipe_manager->push_buffer (video_buf) != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_ERROR ("xcamfilter push buffer failed");
return;
}
xcamfilter->cached_buf_num++;
}
static GstFlowReturn
gst_xcam_filter_prepare_output_buffer (GstBaseTransform *trans, GstBuffer *input, GstBuffer **outbuf)
{
GstXCamFilter *xcamfilter = GST_XCAM_FILTER (trans);
GstFlowReturn ret = GST_FLOW_OK;
SmartPtr<MainPipeManager> pipe_manager = xcamfilter->pipe_manager;
SmartPtr<VideoBuffer> video_buf;
if (xcamfilter->cached_buf_num > xcamfilter->buf_count)
return GST_FLOW_ERROR;
int32_t timeout = -1;
if (xcamfilter->cached_buf_num <= xcamfilter->delay_buf_num)
timeout = 0;
video_buf = pipe_manager->dequeue_buffer (timeout);
if (!video_buf.ptr ()) {
XCAM_LOG_WARNING ("xcamfilter dequeue buffer failed");
*outbuf = NULL;
return GST_FLOW_OK;
}
if (xcamfilter->copy_mode == COPY_MODE_CPU) {
ret = copy_xcambuf_to_gstbuf (xcamfilter->gst_src_video_info, video_buf, outbuf);
} else if (xcamfilter->copy_mode == COPY_MODE_DMA) {
GstAllocator *allocator = xcamfilter->allocator;
ret = append_xcambuf_to_gstbuf (allocator, video_buf, outbuf);
}
if (ret == GST_FLOW_OK) {
xcamfilter->cached_buf_num--;
GST_BUFFER_TIMESTAMP (*outbuf) = GST_BUFFER_TIMESTAMP (input);
}
return ret;
}
static GstFlowReturn
gst_xcam_filter_transform (GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
{
XCAM_UNUSED (trans);
XCAM_UNUSED (inbuf);
if (!outbuf) {
XCAM_LOG_ERROR ("transform failed with null outbufer");
return GST_FLOW_ERROR;
}
XCAM_STATIC_FPS_CALCULATION (gstxcamfilter, XCAM_OBJ_DUR_FRAME_NUM);
return GST_FLOW_OK;
}
static gboolean
gst_xcam_filter_plugin_init (GstPlugin *xcamfilter)
{
return gst_element_register (xcamfilter, "xcamfilter", GST_RANK_NONE,
GST_TYPE_XCAM_FILTER);
}
#ifndef PACKAGE
#define PACKAGE "libxam"
#endif
GST_PLUGIN_DEFINE (
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
xcamfilter,
"Libxcam filter plugin",
gst_xcam_filter_plugin_init,
VERSION,
GST_LICENSE_UNKNOWN,
"libxcamfilter",
"https://github.com/01org/libxcam"
)