1169 lines
34 KiB
C++
1169 lines
34 KiB
C++
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*
|
|
* This source code is subject to the terms and conditions defined in below
|
|
* which is part of this source code package.
|
|
*
|
|
* Description: Mediactrlsrc
|
|
*/
|
|
|
|
// Copyright (C) 2019 Amlogic, Inc. All rights reserved.
|
|
//
|
|
// All information contained herein is Amlogic confidential.
|
|
//
|
|
// This software is provided to you pursuant to Software License
|
|
// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
|
|
// used only in accordance with the terms of this agreement.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification is strictly prohibited without prior written permission
|
|
// from Amlogic.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#define _GNU_SOURCE
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdbool.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <pthread.h>
|
|
#include <dlfcn.h>
|
|
#include <poll.h>
|
|
#include <vector>
|
|
#include "mediactrl_common.h"
|
|
#include "mediactrl_log.h"
|
|
|
|
#include "mediactl.h"
|
|
#include "v4l2subdev.h"
|
|
#include "v4l2videodev.h"
|
|
#include "mediaApi.h"
|
|
#include "lens_config.h"
|
|
|
|
#include "staticPipe.h"
|
|
#include "ispMgr.h"
|
|
|
|
// #define PRINT_FPS
|
|
|
|
static int connected_sockfd = -1;
|
|
static int listen_fd = -1;
|
|
static int mFlushFd[2] = {-1, -1};
|
|
|
|
static char *media_device_name = NULL;
|
|
static const char *server_socket = DEFAULT_SERVER_SOCKET0;
|
|
static struct media_device *media_dev = NULL;
|
|
static int camera_num = 1;
|
|
|
|
/* media stream */
|
|
media_stream_t v4l2_media_stream;
|
|
|
|
//#define WDR_ENABLE
|
|
#define V4L2_META_AML_ISP_CONFIG v4l2_fourcc('A', 'C', 'F', 'G') /* Aml isp param config */
|
|
#define V4L2_META_AML_ISP_STATS v4l2_fourcc('A', 'S', 'T', 'S') /* Aml isp statistics */
|
|
|
|
#define DEFAULT_BUFFER_NUM 4
|
|
|
|
typedef struct v4l2buffer_info {
|
|
void *pstart;
|
|
int length;
|
|
} v4l2buffer_info_t;
|
|
|
|
enum MEDIACTRLSRC_STREAM {
|
|
MEDIACTRLSRC_STREAM_OUTPUT0 = 0, /* Not Used */
|
|
MEDIACTRLSRC_STREAM_RAW, /* Not Used */
|
|
MEDIACTRLSRC_STREAM_STATISTICS,
|
|
MEDIACTRLSRC_STREAM_MAX
|
|
};
|
|
pthread_t tid[MEDIACTRLSRC_STREAM_MAX];
|
|
|
|
struct thread_info {
|
|
pthread_t p_tid;
|
|
uint32_t status;
|
|
|
|
/* sem_t p_sem; */
|
|
|
|
/* aml isp algorithm related */
|
|
aisp_calib_info_t calib;
|
|
AML_ALG_CTX_S pstAlgCtx;
|
|
};
|
|
|
|
struct thread_param {
|
|
//v4l2buffer_info_t *buffer_isp_output0[DEFAULT_BUFFER_NUM]; /* reserved */
|
|
v4l2buffer_info_t buffer_isp_stats[DEFAULT_BUFFER_NUM];
|
|
v4l2buffer_info_t buffer_isp_param;
|
|
|
|
struct sensorConfig *sensor_cfg;
|
|
struct lensConfig *lens_cfg;
|
|
|
|
/* format related */
|
|
uint32_t width;
|
|
uint32_t height;
|
|
// uint32_t pixformat;
|
|
uint32_t fmt_code;
|
|
uint32_t wdr_mode;
|
|
|
|
|
|
uint32_t capture_count;
|
|
int fps;
|
|
|
|
pthread_mutex_t mutex;
|
|
pthread_cond_t cond;
|
|
pthread_t process_socket_tid;
|
|
bool streaming;
|
|
|
|
struct thread_info info;
|
|
};
|
|
|
|
int pollDevices(const std::vector<struct media_entity *> &devices,
|
|
std::vector<struct media_entity *> &activeDevices,
|
|
std::vector<struct media_entity *> &inactiveDevices,
|
|
int timeOut, int flushFd = -1,
|
|
int events = POLLPRI | POLLIN | POLLERR);
|
|
|
|
/*
|
|
* definition of tparam (struct thread_param)
|
|
* set default value
|
|
*/
|
|
static struct thread_param tparam = {
|
|
.buffer_isp_stats={0},
|
|
.buffer_isp_param={0},
|
|
.sensor_cfg = NULL,
|
|
.lens_cfg = NULL,
|
|
.width = 3840,
|
|
.height = 1920,
|
|
// .pixformat = V4L2_PIX_FMT_NV12, /* V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_Y12, V4L2_PIX_FMT_SRGGB12 */
|
|
#ifdef WDR_ENABLE
|
|
.fmt_code = MEDIA_BUS_FMT_SBGGR10_1X10, /* MEDIA_BUS_FMT_SRGGB12_1X12 */
|
|
.wdr_mode = WDR_MODE_2To1_FRAME, /* WDR_MODE_2To1_LINE */
|
|
#else
|
|
.fmt_code = MEDIA_BUS_FMT_SBGGR10_1X10, /* MEDIA_BUS_FMT_SRGGB12_1X12 */
|
|
.wdr_mode = WDR_MODE_NONE,
|
|
#endif
|
|
|
|
.capture_count = 0,
|
|
.fps = 0,
|
|
|
|
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
|
.cond = PTHREAD_COND_INITIALIZER,
|
|
.process_socket_tid = 0,
|
|
.streaming = false,
|
|
.info = {0},
|
|
};
|
|
|
|
/*
|
|
* check video device capability
|
|
*/
|
|
static int check_capability(struct media_entity *entity) {
|
|
struct v4l2_capability v4l2_cap;
|
|
memset (&v4l2_cap, 0, sizeof (struct v4l2_capability));
|
|
int ret = v4l2_video_get_capability(entity, &v4l2_cap);
|
|
if (ret < 0) {
|
|
log_error("get entity[%s] -> video[%s] capability failed",
|
|
entity->info.name,
|
|
entity->devname);
|
|
return -1;
|
|
}
|
|
|
|
log_debug("entity[%s] -> video[%s], cap.driver:%s, capabilities:0x%x, device_caps:0x%x",
|
|
entity->info.name,
|
|
entity->devname,
|
|
v4l2_cap.driver,
|
|
v4l2_cap.capabilities,
|
|
v4l2_cap.device_caps);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int media_set_wdr_mode(media_stream_t *stream, uint32_t wdr_mode) {
|
|
int ret = -1;
|
|
media_set_wdrMode(stream, 0);
|
|
ret = media_set_wdrMode(stream, wdr_mode);
|
|
|
|
return ret;
|
|
#if 0
|
|
/* sensor wdr mode */
|
|
if (wdr_mode != ISP_SDR_DCAM_MODE) {
|
|
ret = v4l2_subdev_set_wdr(stream->sensor.entity, wdr_mode);
|
|
if (ret < 0) {
|
|
log_error("set sensor wdr mode failed");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* isp-adapter wdr mode */
|
|
ret = v4l2_subdev_set_wdr(stream->isp_adapter.entity, wdr_mode);
|
|
if (ret < 0) {
|
|
log_error("set isp-adapter wdr mode failed");
|
|
return ret;
|
|
}
|
|
|
|
/* isp-core wdr mode */
|
|
ret = v4l2_subdev_set_wdr(stream->isp_core.entity, wdr_mode);
|
|
if (ret < 0) {
|
|
log_error("set isp-core wdr mode failed");
|
|
return ret;
|
|
}
|
|
|
|
log_debug("set wdr mode successfully");
|
|
return ret;
|
|
#endif
|
|
}
|
|
|
|
static int media_stream_init(media_stream_t *stream,
|
|
struct media_device *media_dev) {
|
|
|
|
mediaStreamInit(stream, media_dev);
|
|
|
|
fetchPipeMaxResolution(
|
|
&v4l2_media_stream,
|
|
&tparam.width,
|
|
&tparam.height
|
|
);
|
|
log_debug("camera num %d", camera_num);
|
|
if (1 == camera_num) {
|
|
tparam.fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12;
|
|
tparam.wdr_mode = WDR_MODE_NONE;
|
|
} else if (2 == camera_num) {
|
|
tparam.fmt_code = MEDIA_BUS_FMT_SRGGB12_1X12;
|
|
tparam.wdr_mode = ISP_SDR_DCAM_MODE;
|
|
} else {
|
|
log_error("only support 1 or 2 camera");
|
|
return 0;
|
|
}
|
|
|
|
/* set wdr mode */
|
|
media_set_wdr_mode(stream, tparam.wdr_mode);
|
|
|
|
/* TODO */
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* set subdev(entity pad) format
|
|
* include sensor, isp-csiphy, isp-adapter, isp-core
|
|
*/
|
|
static int set_subdev_pad_format(media_stream_t *stream,
|
|
stream_configuration_t *cfg) {
|
|
int ret = -1;
|
|
struct v4l2_mbus_framefmt mbus_format;
|
|
enum v4l2_subdev_format_whence which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
|
|
|
mbus_format.width = cfg->format.width;
|
|
mbus_format.height = cfg->format.height;
|
|
mbus_format.code = cfg->format.code;
|
|
|
|
/* sensor source pad[0] format */
|
|
ret = v4l2_subdev_set_format(stream->sensor_ent,
|
|
&mbus_format, 0, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev sensor pad[0] format failed");
|
|
return ret;
|
|
}
|
|
|
|
/* isp-csiphy sink & source pad[0, 1] format */
|
|
ret = v4l2_subdev_set_format(stream->csiphy_ent,
|
|
&mbus_format, 0, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev isp-ciphy pad[0] format failed");
|
|
return ret;
|
|
}
|
|
ret = v4l2_subdev_set_format(stream->csiphy_ent,
|
|
&mbus_format, 1, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev isp-csiphy pad[1] format failed");
|
|
return ret;
|
|
}
|
|
|
|
/* isp-adapter sink & source pad[0, 1] format */
|
|
ret = v4l2_subdev_set_format(stream->adap_ent,
|
|
&mbus_format, 0, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev isp-adapter pad[0] format failed");
|
|
return ret;
|
|
}
|
|
ret = v4l2_subdev_set_format(stream->adap_ent,
|
|
&mbus_format, 1, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev isp-adapter pad[1] format failed");
|
|
return ret;
|
|
}
|
|
|
|
/* isp-core sink pad[0] format */
|
|
ret = v4l2_subdev_set_format(stream->isp_ent,
|
|
&mbus_format, 0, which);
|
|
if (ret < 0) {
|
|
log_error("set subdev isp-core pad[0] format failed");
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* link and activate subdev(entity pad) which
|
|
* includes sensor, isp-csiphy, isp-adapter, isp-core
|
|
*/
|
|
#define SENSOR_SOURCE_PAD_INDEX 0
|
|
#define SINK_PAD_INDEX 0
|
|
#define SOURCE_PAD_INDEX 1
|
|
static int link_and_activate_subdev(media_stream_t *stream) {
|
|
int ret = -1;
|
|
|
|
struct media_pad *sink_pad = NULL;
|
|
struct media_pad *source_pad = NULL;
|
|
int flag = MEDIA_LNK_FL_ENABLED; /* The link is enabled and can be used to transfer media data */
|
|
|
|
/* source pad[0] sensor --> sink pad[0] isp-csiphy */
|
|
source_pad = (struct media_pad*)media_entity_get_pad(stream->sensor_ent, SENSOR_SOURCE_PAD_INDEX);
|
|
if (!source_pad) {
|
|
log_error("get sensor source pad[0] failed");
|
|
return -1;
|
|
}
|
|
sink_pad = (struct media_pad*)media_entity_get_pad(stream->csiphy_ent, SINK_PAD_INDEX);
|
|
if (!sink_pad) {
|
|
log_error("get isp-csiphy sink pad[0] failed");
|
|
return -1;
|
|
}
|
|
ret = media_setup_link(media_dev, source_pad, sink_pad, flag);
|
|
if (ret != 0) {
|
|
log_error("link sensor to isp-csiphy failed");
|
|
return ret;
|
|
}
|
|
|
|
/* source pad[1] isp-csiphy --> sink pad[0] isp-adapter */
|
|
source_pad = (struct media_pad*)media_entity_get_pad(stream->csiphy_ent, SOURCE_PAD_INDEX);
|
|
if (!source_pad) {
|
|
log_error("get isp-csiphy source pad[1] failed");
|
|
return -1;
|
|
}
|
|
sink_pad = (struct media_pad*)media_entity_get_pad(stream->adap_ent, SINK_PAD_INDEX);
|
|
if (!sink_pad) {
|
|
log_error("get isp-adapter sink pad[0] failed");
|
|
return -1;
|
|
}
|
|
ret = media_setup_link(media_dev, source_pad, sink_pad, flag);
|
|
if (ret != 0) {
|
|
log_error("link isp-csiphy to isp-adapter failed");
|
|
return ret;
|
|
}
|
|
|
|
/* source pad[1] isp-adapter --> sink pad[0] isp-core */
|
|
source_pad = (struct media_pad*)media_entity_get_pad(stream->adap_ent, SOURCE_PAD_INDEX);
|
|
if (!source_pad) {
|
|
log_error("get isp-adapter source pad[1] failed");
|
|
return -1;
|
|
}
|
|
sink_pad = (struct media_pad*)media_entity_get_pad(stream->isp_ent, SINK_PAD_INDEX);
|
|
if (!sink_pad) {
|
|
log_error("get isp-core sink pad[0] failed");
|
|
return -1;
|
|
}
|
|
ret = media_setup_link(media_dev, source_pad, sink_pad, flag);
|
|
if (ret != 0) {
|
|
log_error("link isp-adapter to isp-core failed");
|
|
return ret;
|
|
}
|
|
|
|
log_debug("link and activate subdev successfully");
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* media stream config
|
|
* >1. setup necessary subdev's pad format
|
|
* >2. link and activate necessary subdev
|
|
*/
|
|
int media_stream_config(media_stream_t *stream) {
|
|
int ret = -1;
|
|
|
|
stream_configuration_t stream_cfg;
|
|
memset(&stream_cfg, 0, sizeof(stream_configuration_t));
|
|
stream_cfg.format.width = tparam.width;
|
|
stream_cfg.format.height = tparam.height;
|
|
// stream_cfg.format.fourcc = tparam.pixformat;
|
|
stream_cfg.format.code = tparam.fmt_code;;
|
|
stream_cfg.format.nplanes = 1;
|
|
|
|
ret = set_subdev_pad_format(stream, &stream_cfg);
|
|
if (ret < 0) {
|
|
log_error("set subdev format failed");
|
|
return ret;
|
|
}
|
|
|
|
ret = link_and_activate_subdev(stream);
|
|
if (ret < 0) {
|
|
log_error("link and activate subdev failed");
|
|
return ret;
|
|
}
|
|
|
|
log_debug("config media stream successfully");
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* set isp-stats entity format (out: statistics)
|
|
*/
|
|
static int set_isp_stats_fmt(media_stream_t *stream,
|
|
stream_configuration_t *cfg) {
|
|
int ret = -1;
|
|
struct v4l2_format v4l2_fmt;
|
|
|
|
memset (&v4l2_fmt, 0, sizeof (struct v4l2_format));
|
|
|
|
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_fmt.fmt.pix_mp.width = cfg->format.width;
|
|
v4l2_fmt.fmt.pix_mp.height = cfg->format.height;
|
|
v4l2_fmt.fmt.pix_mp.pixelformat = V4L2_META_AML_ISP_STATS;
|
|
v4l2_fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
|
|
|
ret = v4l2_video_set_format(stream->video_stats, &v4l2_fmt);
|
|
if (ret < 0) {
|
|
log_error("set isp-stats fmt failed, ret:%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* set isp-param entity format (in: parameter)
|
|
*/
|
|
static int set_isp_param_fmt(media_stream_t *stream,
|
|
stream_configuration_t *cfg) {
|
|
int ret = -1;
|
|
struct v4l2_format v4l2_fmt;
|
|
|
|
memset (&v4l2_fmt, 0, sizeof (struct v4l2_format));
|
|
|
|
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_fmt.fmt.pix_mp.width = cfg->format.width;
|
|
v4l2_fmt.fmt.pix_mp.height = cfg->format.height;
|
|
v4l2_fmt.fmt.pix_mp.pixelformat = V4L2_META_AML_ISP_CONFIG;
|
|
v4l2_fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
|
|
|
|
ret = v4l2_video_set_format(stream->video_param, &v4l2_fmt);
|
|
if (ret < 0) {
|
|
log_error("set isp-param fmt failed, ret:%d", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* isp algorithm interface */
|
|
struct ispIF isp_alg_iface;
|
|
static int get_isp_alg_interface() {
|
|
void *handle;
|
|
handle = dlopen("/usr/lib/libispaml.so", RTLD_NOW);
|
|
if (!handle) {
|
|
printf("dlopen libispaml.so error: %s\n", dlerror());
|
|
return -1;
|
|
}
|
|
|
|
isp_alg_iface.alg2User = (isp_alg2user)dlsym(handle, "aisp_alg2user");
|
|
isp_alg_iface.alg2Kernel = (isp_alg2kernel)dlsym(handle, "aisp_alg2kernel");
|
|
isp_alg_iface.algEnable = (isp_enable)dlsym(handle, "aisp_enable");
|
|
isp_alg_iface.algDisable = (isp_disable)dlsym(handle, "aisp_disable");
|
|
isp_alg_iface.algFwInterface = (isp_fw_interface)dlsym(handle, "aisp_fw_interface");
|
|
|
|
|
|
printf("alg2User func addr: %p\n", isp_alg_iface.alg2User);
|
|
printf("alg2Kernel func addr: %p\n", isp_alg_iface.alg2Kernel);
|
|
printf("algEnable func addr: %p\n", isp_alg_iface.algEnable);
|
|
printf("algDisable func addr: %p\n", isp_alg_iface.algDisable);
|
|
printf("algFwInterface func addr: %p\n", isp_alg_iface.algFwInterface);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* init isp algorithm thread related parameter
|
|
* >1. set isp-stats and isp-param entity format
|
|
* >2. request and map buffer respectively
|
|
* >3. first queue to clean buffer before streamon
|
|
* >4. streamon
|
|
*/
|
|
static void isp_alg_param_init() {
|
|
int ret = -1;
|
|
|
|
mFlushFd[0] = -1;
|
|
mFlushFd[1] = -1;
|
|
ret = pipe(mFlushFd);
|
|
if (ret < 0) {
|
|
log_error("Failed to create Flush pipe: %s", strerror(errno));
|
|
return;
|
|
}
|
|
/**
|
|
* make the reading end of the pipe non blocking.
|
|
* This helps during flush to read any information left there without
|
|
* blocking
|
|
*/
|
|
ret = fcntl(mFlushFd[0], F_SETFL, O_NONBLOCK);
|
|
if (ret < 0) {
|
|
log_error("Fail to set flush pipe flag: %s", strerror(errno));
|
|
return;
|
|
}
|
|
ret = fcntl(mFlushFd[1], F_SETFL, O_NONBLOCK);
|
|
if (ret < 0) {
|
|
log_error("Fail to set flush pipe flag: %s", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
check_capability(v4l2_media_stream.video_stats);
|
|
check_capability(v4l2_media_stream.video_param);
|
|
|
|
stream_configuration_t common_cfg;
|
|
common_cfg.format.width = 1024;
|
|
common_cfg.format.height = 256;
|
|
common_cfg.format.nplanes = 1;
|
|
set_isp_stats_fmt(&v4l2_media_stream, &common_cfg);
|
|
set_isp_param_fmt(&v4l2_media_stream, &common_cfg);
|
|
|
|
/* isp-stats & isp-param request buffers */
|
|
struct v4l2_requestbuffers v4l2_rb;
|
|
memset (&v4l2_rb, 0, sizeof (struct v4l2_requestbuffers));
|
|
v4l2_rb.count = DEFAULT_BUFFER_NUM;
|
|
v4l2_rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_rb.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_req_bufs(v4l2_media_stream.video_stats, &v4l2_rb);
|
|
if (ret < 0) {
|
|
log_error("isp-stats request buffer error");
|
|
return;
|
|
}
|
|
memset (&v4l2_rb, 0, sizeof (struct v4l2_requestbuffers));
|
|
v4l2_rb.count = 1;
|
|
v4l2_rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_rb.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_req_bufs(v4l2_media_stream.video_param, &v4l2_rb);
|
|
if (ret < 0) {
|
|
log_error("isp-param request buffer error");
|
|
return;
|
|
}
|
|
|
|
|
|
/* map isp-stats & isp-param buffers */
|
|
struct v4l2_buffer v4l2_buf;
|
|
for (int i = 0; i < DEFAULT_BUFFER_NUM; i++) {
|
|
memset (&v4l2_buf, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf.index = i;
|
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_query_buf(v4l2_media_stream.video_stats, &v4l2_buf);
|
|
if (ret < 0) {
|
|
log_error("isp-stats query buffer error, ret: %d", ret);
|
|
return;
|
|
}
|
|
if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
tparam.buffer_isp_stats[i].length = v4l2_buf.length;
|
|
log_debug("isp stats query buffer, length: %u, offset: %d",
|
|
v4l2_buf.length, v4l2_buf.m.offset);
|
|
tparam.buffer_isp_stats[i].pstart = mmap (NULL, v4l2_buf.length,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, v4l2_media_stream.video_stats->fd, v4l2_buf.m.offset);
|
|
if (tparam.buffer_isp_stats[i].pstart == MAP_FAILED) {
|
|
log_error("isp stats map buffer error");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
memset (&v4l2_buf, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf.index = 0;
|
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_query_buf(v4l2_media_stream.video_param, &v4l2_buf);
|
|
if (ret < 0) {
|
|
log_error("isp-param query buffer error, ret: %d", ret);
|
|
return;
|
|
}
|
|
if (v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
tparam.buffer_isp_param.length = v4l2_buf.length;
|
|
log_debug("isp param query buffer, length: %u, offset: %d",
|
|
v4l2_buf.length, v4l2_buf.m.offset);
|
|
tparam.buffer_isp_param.pstart = mmap (NULL, v4l2_buf.length,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED, v4l2_media_stream.video_param->fd, v4l2_buf.m.offset);
|
|
if (tparam.buffer_isp_param.pstart == MAP_FAILED) {
|
|
log_error("isp stats map buffer error");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* TODO:
|
|
* add interface of aml isp algorithm
|
|
*/
|
|
/* Initialize algorithm related */
|
|
char alg_init[256 * 1024];
|
|
|
|
if (-1 == get_isp_alg_interface()) {
|
|
log_error("get isp algorithm interface failed");
|
|
return;
|
|
}
|
|
|
|
tparam.sensor_cfg = matchSensorConfigByStream(&v4l2_media_stream);
|
|
if (NULL == tparam.sensor_cfg) {
|
|
log_error("match sensor config failed");
|
|
return;
|
|
}
|
|
tparam.lens_cfg = matchLensConfigByStream(&v4l2_media_stream);
|
|
if (tparam.lens_cfg != NULL) {
|
|
lens_set_entity(tparam.lens_cfg, v4l2_media_stream.lens_ent);
|
|
lens_control_cb(tparam.lens_cfg, &tparam.info.pstAlgCtx.stLensFunc);
|
|
}
|
|
#ifdef WDR_ENABLE
|
|
cmos_set_sensor_entity(tparam.sensor_cfg, v4l2_media_stream.sensor_ent, 1);
|
|
#else
|
|
cmos_set_sensor_entity(tparam.sensor_cfg, v4l2_media_stream.sensor_ent, 0);
|
|
#endif
|
|
|
|
cmos_sensor_control_cb(tparam.sensor_cfg, &tparam.info.pstAlgCtx.stSnsExp);
|
|
cmos_get_sensor_calibration(tparam.sensor_cfg, v4l2_media_stream.sensor_ent, &tparam.info.calib);
|
|
|
|
|
|
(isp_alg_iface.algEnable)(0, &tparam.info.pstAlgCtx, &tparam.info.calib);
|
|
memset(alg_init, 0, sizeof(alg_init));
|
|
(isp_alg_iface.alg2User)(0, alg_init);
|
|
(isp_alg_iface.alg2Kernel)(0, tparam.buffer_isp_param.pstart);
|
|
|
|
/* first queue isp-stats & isp-param buffers to clean */
|
|
for (int i = 0; i < DEFAULT_BUFFER_NUM; i++) {
|
|
memset (&v4l2_buf, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf.index = i;
|
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_q_buf(v4l2_media_stream.video_stats, &v4l2_buf);
|
|
if (ret < 0) {
|
|
log_error("isp-stats first queue buffer error, ret: %d, index: %d", ret, i);
|
|
return;
|
|
}
|
|
}
|
|
memset (&v4l2_buf, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf.index = 0;
|
|
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_q_buf(v4l2_media_stream.video_param, &v4l2_buf);
|
|
if (ret < 0) {
|
|
log_error("isp-param first queue buffer error, ret: %d", ret);
|
|
return;
|
|
}
|
|
|
|
/* streamon isp-stats & isp-param */
|
|
ret = v4l2_video_stream_on(v4l2_media_stream.video_stats,
|
|
V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
if (ret < 0) {
|
|
log_error("isp-stats streamon error, ret: %d", ret);
|
|
return;
|
|
}
|
|
ret = v4l2_video_stream_on(v4l2_media_stream.video_param,
|
|
V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
if (ret < 0) {
|
|
log_error("isp-stats streamon error, ret: %d", ret);
|
|
return;
|
|
}
|
|
|
|
log_debug("Finish initializing amlgorithm parameter ...");
|
|
}
|
|
|
|
#ifdef PRINT_FPS
|
|
static int64_t get_current_time_msec(void) {
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
|
}
|
|
#endif
|
|
|
|
|
|
/**
|
|
* check fd whether is readable
|
|
**/
|
|
int check_fd(int fd, int timeout_us) {
|
|
if (timeout_us >= 0) {
|
|
struct timeval tv;
|
|
struct timeval *ptv;
|
|
if (timeout_us > 0) {
|
|
tv.tv_sec = timeout_us / 1000000;
|
|
tv.tv_usec = timeout_us % 1000000;
|
|
ptv = &tv;
|
|
} else {
|
|
ptv = NULL;
|
|
}
|
|
fd_set rfds;
|
|
FD_ZERO(&rfds);
|
|
FD_SET(fd, &rfds);
|
|
int retval = select(fd + 1, &rfds, NULL, NULL, ptv);
|
|
if (retval <= 0) {
|
|
log_error("select fail %d, %d %s", retval, errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
if (fd > 0 && FD_ISSET(fd, &rfds)) {
|
|
return 0;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int pollDevices(const std::vector<struct media_entity *> &devices,
|
|
std::vector<struct media_entity *> &activeDevices,
|
|
std::vector<struct media_entity *> &inactiveDevices,
|
|
int timeOut, int flushFd, int events) {
|
|
int numFds = devices.size();
|
|
int totalNumFds = (flushFd != -1) ? numFds + 1 : numFds;
|
|
struct pollfd pollFds[totalNumFds];
|
|
int ret = 0;
|
|
|
|
for (int i = 0; i < numFds; i++) {
|
|
pollFds[i].fd = devices[i]->fd;
|
|
pollFds[i].events = events | POLLERR; // we always poll for errors, asked or not
|
|
pollFds[i].revents = 0;
|
|
}
|
|
|
|
if (flushFd != -1) {
|
|
pollFds[numFds].fd = flushFd;
|
|
pollFds[numFds].events = POLLPRI | POLLIN;
|
|
pollFds[numFds].revents = 0;
|
|
}
|
|
|
|
ret = poll(pollFds, totalNumFds, timeOut);
|
|
if (ret <= 0) {
|
|
for (uint32_t i = 0; i < devices.size(); i++) {
|
|
log_error("Device %s poll failed (%s)", devices[i]->info.name,
|
|
(ret == 0) ? "timeout" : "error");
|
|
if (pollFds[i].revents & POLLERR) {
|
|
log_error("%s: device %s received POLLERR", __FUNCTION__, devices[i]->info.name);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
activeDevices.clear();
|
|
inactiveDevices.clear();
|
|
|
|
//check first the flush
|
|
if (flushFd != -1) {
|
|
if ((pollFds[numFds].revents & POLLIN) || (pollFds[numFds].revents & POLLPRI)) {
|
|
char dummy;
|
|
read(flushFd, &dummy, 1);
|
|
log_debug("%s: Poll returning from flush", __FUNCTION__);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
// check other active devices.
|
|
for (int i = 0; i < numFds; i++) {
|
|
if (pollFds[i].revents & POLLERR) {
|
|
log_error("%s: received POLLERR", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
// return nodes that have data available
|
|
if (pollFds[i].revents & events) {
|
|
activeDevices.push_back(devices[i]);
|
|
} else
|
|
inactiveDevices.push_back(devices[i]);
|
|
}
|
|
return ret;
|
|
}
|
|
/**
|
|
* isp algorithm process one
|
|
**/
|
|
|
|
static void isp_alg_process_one(struct thread_param *tparam) {
|
|
|
|
// log_debug("enter isp_alg_process_one");
|
|
|
|
//polling for q_buf & dq_buf
|
|
int ret = -1;
|
|
int idx = -1;
|
|
std::vector<struct media_entity *> mPollingDevices;
|
|
std::vector<struct media_entity *> mActiveDevices;
|
|
std::vector<struct media_entity *> mInactiveDevices;
|
|
|
|
mPollingDevices.push_back(v4l2_media_stream.video_param);
|
|
mPollingDevices.push_back(v4l2_media_stream.video_stats);
|
|
|
|
do {
|
|
ret = pollDevices(mPollingDevices, mActiveDevices,
|
|
mInactiveDevices, 500, mFlushFd[0]);
|
|
if (mInactiveDevices.size() > 0) {
|
|
mPollingDevices = mInactiveDevices;
|
|
// log_info("not all device is ready, continue polling");
|
|
for (int i = 0; i < mInactiveDevices.size(); ++i)
|
|
// log_info("InactiveDevices %d: %s", i, mInactiveDevices[i]->info.name);
|
|
continue;
|
|
} else if (mActiveDevices.size() > 0 && mInactiveDevices.size() == 0) {
|
|
// log_info("all device is ready");
|
|
} else {
|
|
log_info("return from flush or error");
|
|
return;
|
|
}
|
|
|
|
struct v4l2_buffer v4l2_buf_video_statistics;
|
|
memset (&v4l2_buf_video_statistics, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf_video_statistics.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf_video_statistics.memory = V4L2_MEMORY_MMAP;
|
|
// log_debug("enter v4l2_video_dq_buf video_stats");
|
|
ret = v4l2_video_dq_buf(
|
|
v4l2_media_stream.video_stats,
|
|
&v4l2_buf_video_statistics
|
|
);
|
|
// log_debug("exit v4l2_video_dq_buf video_stats");
|
|
if (ret < 0) {
|
|
log_error("dequeue video statistics buffer failed");
|
|
continue;
|
|
}
|
|
|
|
struct v4l2_buffer v4l2_buf_video_param;
|
|
memset (&v4l2_buf_video_param, 0, sizeof (struct v4l2_buffer));
|
|
v4l2_buf_video_param.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_buf_video_param.memory = V4L2_MEMORY_MMAP;
|
|
// log_debug("enter v4l2_video_dq_buf video_param");
|
|
ret = v4l2_video_dq_buf(
|
|
v4l2_media_stream.video_param,
|
|
&v4l2_buf_video_param
|
|
);
|
|
// log_debug("exit v4l2_video_dq_buf video_param");
|
|
if (ret < 0) {
|
|
log_error("dequeue video param buffer failed");
|
|
continue;
|
|
}
|
|
|
|
idx = v4l2_buf_video_statistics.index;
|
|
(isp_alg_iface.alg2User)(0, tparam->buffer_isp_stats[idx].pstart);
|
|
(isp_alg_iface.alg2Kernel)(0, tparam->buffer_isp_param.pstart);
|
|
ret = v4l2_video_q_buf(
|
|
v4l2_media_stream.video_stats,
|
|
&v4l2_buf_video_statistics
|
|
);
|
|
// log_debug("exit v4l2_video_q_buf video_stats");
|
|
if (ret < 0) {
|
|
log_error("queue video statistics buffer failed");
|
|
break;
|
|
}
|
|
// log_debug("enter v4l2_video_q_buf video_param");
|
|
ret = v4l2_video_q_buf(
|
|
v4l2_media_stream.video_param,
|
|
&v4l2_buf_video_param
|
|
);
|
|
// log_debug("exit v4l2_video_q_buf video_param");
|
|
if (ret < 0) {
|
|
log_error("queue video param buffer failed");
|
|
break;
|
|
}
|
|
break;
|
|
} while(1);
|
|
// log_debug("exit isp_alg_process_one");
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* isp algorithm thread
|
|
**/
|
|
static void *isp_alg_thread(void *arg) {
|
|
struct thread_param *tparam = (struct thread_param *)arg;
|
|
/**
|
|
* use isp algorithm to process
|
|
**/
|
|
log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
pthread_mutex_lock(&tparam->mutex);
|
|
if (!tparam->streaming) {
|
|
pthread_cond_wait(&tparam->cond, &tparam->mutex);
|
|
}
|
|
// log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
pthread_mutex_unlock(&tparam->mutex);
|
|
// log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
|
|
while (true) {
|
|
pthread_mutex_lock(&tparam->mutex);
|
|
// log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
if (tparam->streaming) {
|
|
pthread_mutex_unlock(&tparam->mutex);
|
|
// log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
isp_alg_process_one(tparam);
|
|
// log_debug("tparam->streaming = %s", tparam->streaming ? "true" : "false");
|
|
} else {
|
|
pthread_mutex_unlock(&tparam->mutex);
|
|
log_debug("streamoff ...");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* streamoff and unmap isp-stats & isp-param buffers */
|
|
int ret = -1;
|
|
ret = v4l2_video_stream_off(v4l2_media_stream.video_stats,V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
if (ret < 0) {
|
|
log_error("[stats] error: streamoff");
|
|
return NULL;
|
|
}
|
|
log_debug("v4l2_video_stream_off video_stats");
|
|
|
|
ret = v4l2_video_stream_off(v4l2_media_stream.video_param,V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
if (ret < 0) {
|
|
log_error("[video_param] error: streamoff");
|
|
return NULL;
|
|
}
|
|
log_debug("enter v4l2_video_stream_off video_param");
|
|
|
|
(isp_alg_iface.algDisable)(0);
|
|
|
|
/* isp-stats & isp-param request buffers */
|
|
struct v4l2_requestbuffers v4l2_rb;
|
|
memset (&v4l2_rb, 0, sizeof (struct v4l2_requestbuffers));
|
|
v4l2_rb.count = 0;
|
|
v4l2_rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_rb.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_req_bufs(v4l2_media_stream.video_stats, &v4l2_rb);
|
|
if (ret < 0) {
|
|
log_error("[stats] error: request buffer.");
|
|
return NULL;
|
|
}
|
|
for (int i = 0; i < DEFAULT_BUFFER_NUM; i++) {
|
|
munmap(tparam->buffer_isp_stats[i].pstart,
|
|
tparam->buffer_isp_stats[i].length);
|
|
}
|
|
|
|
memset (&v4l2_rb, 0, sizeof (struct v4l2_requestbuffers));
|
|
v4l2_rb.count = 0;
|
|
v4l2_rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
v4l2_rb.memory = V4L2_MEMORY_MMAP;
|
|
ret = v4l2_video_req_bufs(v4l2_media_stream.video_param, &v4l2_rb);
|
|
if (ret < 0) {
|
|
log_error("[video_param] error: request buffer.");
|
|
return NULL;
|
|
}
|
|
munmap(tparam->buffer_isp_param.pstart,
|
|
tparam->buffer_isp_param.length);
|
|
|
|
log_debug("exit isp_alg_thread");
|
|
return NULL;
|
|
}
|
|
|
|
static void *process_socket_thread(void *arg) {
|
|
struct thread_param *tparam = (struct thread_param *)arg;
|
|
int r;
|
|
char recv_buffer[32] = {0};
|
|
|
|
while (true) {
|
|
if (check_fd(connected_sockfd, 0) == 0) {
|
|
r = TEMP_FAILURE_RETRY(recv(connected_sockfd, recv_buffer, sizeof(recv_buffer), 0));
|
|
log_debug("recv_buffer:%s",recv_buffer);
|
|
if ((r == 0) || (r == -1L) || (strcmp("streamoff", recv_buffer) == 0)) {
|
|
pthread_mutex_lock(&tparam->mutex);
|
|
tparam->streaming = false;
|
|
pthread_cond_signal(&tparam->cond);
|
|
pthread_mutex_unlock(&tparam->mutex);
|
|
char dummy = 'x';
|
|
write(mFlushFd[1], &dummy, 1);
|
|
log_debug("receive streamoff notification or TEMP_FAILURE_RETRY 0/-1L :%d",r);
|
|
break;
|
|
}
|
|
if (strcmp("streamon", recv_buffer) == 0) {
|
|
pthread_mutex_lock(&tparam->mutex);
|
|
tparam->streaming = true;
|
|
pthread_cond_signal(&tparam->cond);
|
|
pthread_mutex_unlock(&tparam->mutex);
|
|
log_debug("receive streamon notification");
|
|
} else {
|
|
log_warn("not supported message ...");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
log_debug("exit process_socket_thread");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void parse_opt(int argc, char *argv[]) {
|
|
int opt;
|
|
while ((opt = getopt(argc, argv, "m:c:t:s:")) != -1) {
|
|
switch (opt) {
|
|
case 'm': /* media device name (/dev/media0) */
|
|
media_device_name = optarg;
|
|
// if (strstr(media_device_name, "media0")) {
|
|
// server_socket = DEFAULT_SERVER_SOCKET0;
|
|
// } else if (strstr(media_device_name, "media1")) {
|
|
// server_socket = DEFAULT_SERVER_SOCKET1;
|
|
// }
|
|
log_debug("media device name: %s", media_device_name);
|
|
break;
|
|
case 'c': /* camera number (0,1) */
|
|
camera_num = atoi(optarg);
|
|
break;
|
|
case 't':
|
|
break;
|
|
case 's':
|
|
server_socket = optarg;
|
|
log_debug("Server socket: %s",server_socket);
|
|
break;
|
|
default:
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Signalhandler(int sig)
|
|
{
|
|
log_debug("enter camctrl Signalhandler: %d",sig);
|
|
|
|
char streamoff_buffer[32] = {0};
|
|
strcpy(streamoff_buffer, "streamoff_done");
|
|
int r = TEMP_FAILURE_RETRY(send(connected_sockfd, streamoff_buffer, strlen(streamoff_buffer), 0));
|
|
if (r < 0) {
|
|
log_error("send streamoff_buffer, failed");
|
|
}
|
|
|
|
close(listen_fd);
|
|
close(connected_sockfd);
|
|
unlink(server_socket);
|
|
|
|
if (mFlushFd[1] != -1 || mFlushFd[0] != -1) {
|
|
close(mFlushFd[0]);
|
|
close(mFlushFd[1]);
|
|
mFlushFd[0] = -1;
|
|
mFlushFd[1] = -1;
|
|
}
|
|
|
|
log_debug("exit camctrl Signalhandler: %d",sig);
|
|
exit(0);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
signal(SIGINT, SIG_IGN); // Ignore the SIGINT signal
|
|
// signal(SIGTERM, Signalhandler);
|
|
// signal(SIGTERM, SIG_IGN); // Ignore the SIGTERM signal
|
|
|
|
log_debug("[%s:%s:%d]\n", __FILE__, __func__, __LINE__);
|
|
|
|
parse_opt(argc, argv);
|
|
|
|
/**
|
|
* media ctrl progress:
|
|
* open media device and enumerate entities (In general: /dev/media0)
|
|
* get video device name through entity name
|
|
*
|
|
**/
|
|
media_dev = media_device_new(media_device_name);
|
|
if (NULL == media_dev) {
|
|
log_debug("new media device error");
|
|
return -1;
|
|
}
|
|
if (0 != media_device_enumerate(media_dev)) {
|
|
log_error("media device enumerate failed");
|
|
return -1;
|
|
}
|
|
|
|
media_stream_init(&v4l2_media_stream, media_dev);
|
|
media_stream_config(&v4l2_media_stream);
|
|
log_debug("open media success, fd %d", media_dev->fd);
|
|
isp_alg_param_init();
|
|
|
|
/**
|
|
* Unix Socket Operation:
|
|
* [Progress] send video device name
|
|
*
|
|
**/
|
|
struct sockaddr_un server_unix, client_unix;
|
|
socklen_t client_unix_len;
|
|
int size;
|
|
|
|
if ((listen_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
log_error("socket error");
|
|
exit(1);
|
|
}
|
|
|
|
memset(&server_unix, 0, sizeof(server_unix));
|
|
server_unix.sun_family = AF_UNIX;
|
|
strcpy(server_unix.sun_path, server_socket);
|
|
size = offsetof(struct sockaddr_un, sun_path) + strlen(server_unix.sun_path);
|
|
unlink(server_socket);
|
|
if (bind(listen_fd, (struct sockaddr *)&server_unix, size) < 0) {
|
|
log_error("bind error");
|
|
exit(1);
|
|
}
|
|
log_debug("UNIX domain socket bound");
|
|
|
|
if (listen(listen_fd, 16) < 0) {
|
|
log_error("listen error");
|
|
exit(1);
|
|
}
|
|
log_debug("Accepting connections ...");
|
|
|
|
client_unix_len = sizeof(client_unix);
|
|
if ((connected_sockfd = accept(listen_fd, (struct sockaddr *)&client_unix, &client_unix_len)) < 0) {
|
|
log_error("accept error");
|
|
return -1;
|
|
}
|
|
log_debug("connected_sockfd: %d", connected_sockfd);
|
|
|
|
char video_dev_name[32] = {0};
|
|
strcpy(video_dev_name, v4l2_media_stream.video_ent0->devname);
|
|
log_debug("video_dev_name: %s", video_dev_name);
|
|
int r = TEMP_FAILURE_RETRY(send(connected_sockfd, video_dev_name, strlen(video_dev_name), 0));
|
|
if (r < 0) {
|
|
log_error("send video_dev_name, failed");
|
|
}
|
|
|
|
int err;
|
|
err = pthread_create(&tparam.process_socket_tid, NULL, &process_socket_thread, &tparam);
|
|
if (err != 0) {
|
|
log_error("can't create process_socket_thread");
|
|
exit(1);
|
|
}
|
|
err = pthread_create(&tid[MEDIACTRLSRC_STREAM_STATISTICS], NULL, &isp_alg_thread, &tparam);
|
|
if (err != 0) {
|
|
log_error("can't create isp_alg_thread");
|
|
exit(1);
|
|
}
|
|
|
|
pthread_join(tparam.process_socket_tid, NULL);
|
|
|
|
pthread_join(tid[MEDIACTRLSRC_STREAM_STATISTICS], NULL);
|
|
|
|
char streamoff_buffer[32] = {0};
|
|
strcpy(streamoff_buffer, "streamoff_done");
|
|
int m = TEMP_FAILURE_RETRY(send(connected_sockfd, streamoff_buffer, strlen(streamoff_buffer), 0));
|
|
if (m < 0) {
|
|
log_error("send streamoff_buffer, failed");
|
|
}
|
|
|
|
close(listen_fd);
|
|
close(connected_sockfd);
|
|
unlink(server_socket);
|
|
|
|
if (mFlushFd[1] != -1 || mFlushFd[0] != -1) {
|
|
close(mFlushFd[0]);
|
|
close(mFlushFd[1]);
|
|
mFlushFd[0] = -1;
|
|
mFlushFd[1] = -1;
|
|
}
|
|
|
|
if (media_dev != NULL) {
|
|
log_debug("media reset links, fd %d", media_dev->fd);
|
|
media_reset_links(media_dev);
|
|
}
|
|
|
|
log_debug("camctrl exit");
|
|
return 0;
|
|
}
|