/* * Copyright (C) 2019 Rockchip Electronics Co., Ltd. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL), available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "camera_control.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uvc_log.h" #if EPTZ_ENABLE #include "eptz_control.h" #endif #if USE_RKMEDIA #include #include #include #include #include #endif #if USE_ROCKIT #include #include #include #include #endif #ifdef __cplusplus extern "C" { #endif extern void uvc_read_camera_buffer(void *cam_buf, struct MPP_ENC_INFO *info, void *extra_data, size_t extra_size); #ifdef __cplusplus } #endif #if USE_RK_AISERVER #include "uvc_ipc_ext.h" #include "uvc_data.pb.h" #endif struct Camera_Stream { int width; int height; int fps; int format; int eptz; pthread_mutex_t record_mutex; pthread_cond_t record_cond; #if USE_ROCKIT RTUVCGraph *uvc_graph; volatile int pthread_run; #endif #if USE_RKMEDIA std::shared_ptr input; std::shared_ptr uvc_flow; volatile int pthread_run; RK_U32 uvc_flow_output; #endif pthread_t record_id; int deviceid; }; #if USE_RKMEDIA static bool do_uvc(easymedia::Flow *f, easymedia::MediaBufferVector &input_vector); class UVCJoinFlow : public easymedia::Flow { public: UVCJoinFlow(uint32_t id); virtual ~UVCJoinFlow() { StopAllThread(); } private: uint32_t id; friend bool do_uvc(easymedia::Flow *f, easymedia::MediaBufferVector &input_vector); }; UVCJoinFlow::UVCJoinFlow(uint32_t id) : id(20) { easymedia::SlotMap sm; sm.thread_model = easymedia::Model::ASYNCCOMMON; sm.mode_when_full = easymedia::InputMode::DROPFRONT; sm.input_slots.push_back(0); sm.input_maxcachenum.push_back(2); sm.fetch_block.push_back(true); if (true) { sm.input_slots.push_back(1); sm.input_maxcachenum.push_back(1); sm.fetch_block.push_back(false); } sm.process = do_uvc; if (!InstallSlotMap(sm, "uvc_extract", -1)) { LOG_ERROR( "Fail to InstallSlotMap, %s\n", "uvc_join"); SetError(-EINVAL); return; } } #endif #define RT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) static struct Camera_Stream *stream_list = NULL; static pthread_rwlock_t notelock = PTHREAD_RWLOCK_INITIALIZER; static std::list record_id_list; #if USE_RKMEDIA bool do_uvc(easymedia::Flow *f, easymedia::MediaBufferVector &input_vector) { UVCJoinFlow *flow = (UVCJoinFlow *)f; auto img_buf = input_vector[0]; if (!img_buf || img_buf->GetType() != Type::Image) return false; auto img = std::static_pointer_cast(img_buf); struct MPP_ENC_INFO info; info.fd = img_buf->GetFD(); info.size = img_buf->GetValidSize(); #if UVC_DYNAMIC_DEBUG_USE_TIME if (uvc_debug_info.first_frm || !access(UVC_DYNAMIC_DEBUG_USE_TIME_CHECK, 0)) { int32_t use_time_us, now_time_us; info.pts =img_buf->GetUSTimeStamp(); uvc_debug_info.first_frm = false; struct timespec now_tm = {0, 0}; clock_gettime(CLOCK_MONOTONIC, &now_tm); now_time_us = now_tm.tv_sec * 1000000LL + now_tm.tv_nsec / 1000; use_time_us = now_time_us - info.pts; LOG_INFO("isp->rkmedia->uvc latency time:%d us, %d ms\n", use_time_us, use_time_us / 1000); if (uvc_debug_info.first_frm) { use_time_us = now_time_us - uvc_debug_info.stream_on_pts; LOG_INFO("streamon->isp->rkmedia->uvc latency time:%d us, %d ms\n", use_time_us, use_time_us / 1000); } } #endif #if UVC_DYNAMIC_DEBUG_FPS if (!access(UVC_DYNAMIC_DEBUG_ISP_FPS_CHECK, 0)) { uvc_debug_info.debug_isp_fps = true; } else if (!access(UVC_DYNAMIC_DEBUG_IPC_FPS_CHECK, 0)) { uvc_debug_info.debug_ipc_fps = true; uvc_debug_info.debug_isp_fps = false; } else { uvc_debug_info.debug_isp_fps = false; uvc_debug_info.debug_ipc_fps = false; } if (uvc_debug_info.debug_isp_fps || uvc_debug_info.debug_ipc_fps) { ++uvc_debug_info.isp_frm; if (uvc_debug_info.isp_frm == 100) { struct timeval now_time; gettimeofday(&now_time, NULL); int64_t use_timems = (now_time.tv_sec * 1000 + now_time.tv_usec / 1000) - (uvc_debug_info.enter_time.tv_sec * 1000 + uvc_debug_info.enter_time.tv_usec / 1000); uvc_debug_info.enter_time.tv_sec = now_time.tv_sec; uvc_debug_info.enter_time.tv_usec = now_time.tv_usec; uvc_debug_info.fps = (1000.0 * uvc_debug_info.isp_frm) / use_timems; uvc_debug_info.isp_frm = 0; LOG_INFO("%s fps:%0.1f\n", uvc_debug_info.debug_isp_fps ? "isp" : "ipc", uvc_debug_info.fps); } } if (!uvc_debug_info.debug_isp_fps) #endif { uvc_read_camera_buffer(img_buf->GetPtr(), &info, NULL, 0); } return true; } #endif #if (USE_RKMEDIA || USE_ROCKIT) static void camera_control_wait(struct Camera_Stream *stream) { pthread_mutex_lock(&stream->record_mutex); if (stream->pthread_run) pthread_cond_wait(&stream->record_cond, &stream->record_mutex); pthread_mutex_unlock(&stream->record_mutex); } #endif #if USE_ROCKIT static RT_RET emitted_buffer_to_uvc(RTMediaBuffer *buffer) { struct MPP_ENC_INFO info; info.fd = buffer->getFd(); info.size = buffer->getLength(); #if UVC_DYNAMIC_DEBUG_USE_TIME if (uvc_debug_info.first_frm || !access(UVC_DYNAMIC_DEBUG_USE_TIME_CHECK, 0)) { int32_t use_time_us, now_time_us; long long int pts; buffer->getMetaData()->findInt64(kKeyFramePts, &pts); info.pts = pts; uvc_debug_info.first_frm = false; struct timespec now_tm = {0, 0}; clock_gettime(CLOCK_MONOTONIC, &now_tm); now_time_us = now_tm.tv_sec * 1000000LL + now_tm.tv_nsec / 1000; use_time_us = now_time_us - info.pts; LOG_INFO("isp->rockit->uvc latency time:%d us, %d ms\n", use_time_us, use_time_us / 1000); if (uvc_debug_info.first_frm) { use_time_us = now_time_us - uvc_debug_info.stream_on_pts; LOG_INFO("streamon->isp->rockit->uvc latency time:%d us, %d ms\n", use_time_us, use_time_us / 1000); } //LOG_INFO("isp:0x%x , uvc:0x%x \n", info.pts, now_time_us); } #endif #if UVC_DYNAMIC_DEBUG_FPS if (!access(UVC_DYNAMIC_DEBUG_ISP_FPS_CHECK, 0)) { uvc_debug_info.debug_isp_fps = true; } else if (!access(UVC_DYNAMIC_DEBUG_IPC_FPS_CHECK, 0)) { uvc_debug_info.debug_ipc_fps = true; uvc_debug_info.debug_isp_fps = false; } else { uvc_debug_info.debug_isp_fps = false; uvc_debug_info.debug_ipc_fps = false; } if (uvc_debug_info.debug_isp_fps || uvc_debug_info.debug_ipc_fps) { ++uvc_debug_info.isp_frm; if (uvc_debug_info.isp_frm == 100) { struct timeval now_time; gettimeofday(&now_time, NULL); int64_t use_timems = (now_time.tv_sec * 1000 + now_time.tv_usec / 1000) - (uvc_debug_info.enter_time.tv_sec * 1000 + uvc_debug_info.enter_time.tv_usec / 1000); uvc_debug_info.enter_time.tv_sec = now_time.tv_sec; uvc_debug_info.enter_time.tv_usec = now_time.tv_usec; uvc_debug_info.fps = (1000.0 * uvc_debug_info.isp_frm) / use_timems; uvc_debug_info.isp_frm = 0; LOG_INFO("%s fps:%0.1f\n", uvc_debug_info.debug_isp_fps ? "isp" : "ipc", uvc_debug_info.fps); } } if (!uvc_debug_info.debug_isp_fps) #endif { uvc_read_camera_buffer(buffer->getData(), &info, NULL, 0); } buffer->release(); return RT_OK; } #endif void video_record_signal(struct Camera_Stream *stream) { pthread_mutex_lock(&stream->record_mutex); #if USE_ROCKIT stream->uvc_graph->closeUVC(); LOG_INFO("closeUVC ok\n"); #endif #if USE_ROCKIT || USE_RKMEDIA stream->pthread_run = 0; pthread_cond_signal(&stream->record_cond); #endif pthread_mutex_unlock(&stream->record_mutex); } static struct Camera_Stream *getfastvideo(void) { return stream_list; } static void camera_stop(struct Camera_Stream *stream) { LOG_INFO("%s \n", __func__); } static void *uvc_camera(void *arg) { struct Camera_Stream *stream = (struct Camera_Stream *)arg; prctl(PR_SET_NAME, "uvc_camera", 0, 0, 0); #if 0 #if USE_RK_AISERVER int needEPTZ = 0; int eptzWidth = 0; int eptzHeight = 0; char *enableEptz = getenv("ENABLE_EPTZ"); LOG_INFO("enableEptz=%s", enableEptz); if (enableEptz) { LOG_INFO("%s :uvc eptz use evn setting \n", __FUNCTION__); needEPTZ = atoi(enableEptz); } int need_full_range = 1; char *full_range = getenv("ENABLE_FULL_RANGE"); if (full_range) { need_full_range = atoi(full_range); LOG_INFO("uvc full_range use env setting:%d \n", need_full_range); } if (needEPTZ) uvc_ipc_event(UVC_IPC_EVENT_ENABLE_ETPTZ, (void *)&needEPTZ); CAMERA_INFO camera_info; camera_info.width = stream->width; camera_info.height = stream->height; camera_info.vir_width = stream->width; camera_info.vir_height = stream->height; camera_info.buf_size = stream->width * stream->height * 2; camera_info.range = need_full_range; uvc_ipc_event(UVC_IPC_EVENT_CONFIG_CAMERA, (void *)&camera_info); uvc_ipc_event(UVC_IPC_EVENT_START, NULL); //after the camera config //int val = 12; // for test //uvc_ipc_event(UVC_IPC_EVENT_SET_ZOOM, (void *)&val); // for test #endif #else #if USE_ROCKIT int needEPTZ = 0; int eptzWidth = 0; int eptzHeight = 0; char* enableEptz = getenv("ENABLE_EPTZ"); printf("enableEptz=%s", enableEptz); if (enableEptz){ LOG_INFO("uvc eptz use evn setting \n"); needEPTZ = atoi(enableEptz); } else if (stream->eptz){ LOG_INFO("uvc eptz use xu setting:%d\n", stream->eptz); needEPTZ = stream->eptz; } int need_full_range = 1; char* full_range = getenv("ENABLE_FULL_RANGE"); if (full_range) { need_full_range = atoi(full_range); LOG_INFO("uvc full_range use env setting:%d \n",need_full_range); } if (needEPTZ) { stream->uvc_graph = new RTUVCGraph("eptz"); } else { stream->uvc_graph = new RTUVCGraph("uvc"); } stream->uvc_graph->observeUVCOutputStream(&emitted_buffer_to_uvc); RtMetaData cameraParams; cameraParams.setInt32("opt_width", stream->width); cameraParams.setInt32("opt_height", stream->height); cameraParams.setInt32("opt_vir_width", stream->width); cameraParams.setInt32("opt_vir_height", stream->height); cameraParams.setInt32("node_buff_size", stream->width * stream->height * 2); if ((stream->format == V4L2_PIX_FMT_H264) && (need_full_range == 0)) { LOG_INFO("stream->format:V4L2_PIX_FMT_H264,use V4L2_QUANTIZATION_LIM_RANGE!!"); cameraParams.setInt32("opt_quantization", V4L2_QUANTIZATION_LIM_RANGE); } stream->uvc_graph->updateCameraParams(&cameraParams); stream->uvc_graph->prepare(); stream->uvc_graph->openUVC(); stream->uvc_graph->enableEPTZ(needEPTZ); while (stream->pthread_run) { #if CAMERA_CONTROL_PAN_TILT_ZOOM_DEBUG char check_test[20] = {0}; int test_val; sleep(1); if (!access(CAMERA_CONTROL_PAN_LEFT_DEBUG_CHECK, 0)) { sprintf(check_test, "rm %s", CAMERA_CONTROL_PAN_LEFT_DEBUG_CHECK); system(check_test); camera_control_set_pan(-1); } else if (!access(CAMERA_CONTROL_PAN_RIGHT_DEBUG_CHECK, 0)) { sprintf(check_test, "rm %s", CAMERA_CONTROL_PAN_RIGHT_DEBUG_CHECK); system(check_test); camera_control_set_pan(1); } else if (!access(CAMERA_CONTROL_PAN_RANDOM_DEBUG_CHECK, 0)) { sprintf(check_test, "rm %s", CAMERA_CONTROL_PAN_RANDOM_DEBUG_CHECK); system(check_test); test_val = (random() % 21) - 10; camera_control_set_pan(test_val); } else if (!access(CAMERA_CONTROL_TILT_RANDOM_DEBUG_CHECK, 0)) { sprintf(check_test, "rm %s", CAMERA_CONTROL_TILT_RANDOM_DEBUG_CHECK); system(check_test); test_val = (random() % 21) - 10; camera_control_set_tilt(test_val); } else if (!access(CAMERA_CONTROL_ZOOM_RANDOM_DEBUG_CHECK, 0)) { sprintf(check_test, "rm %s", CAMERA_CONTROL_ZOOM_RANDOM_DEBUG_CHECK); system(check_test); test_val = ((random() % 5) + 1) * 10; camera_control_set_zoom(test_val); } #else camera_control_wait(stream); #endif } goto record_exit; #endif #if USE_RKMEDIA int needEPTZ = 0; int eptz_width = 0; int eptz_height = 0; int needRGA = 0; int rga_width = 0; int rga_height = 0; needEPTZ = stream->eptz; char* enable_eptz = getenv("ENABLE_EPTZ"); if(enable_eptz && !needEPTZ){ LOG_INFO("%s :uvc eptz use env setting \n",enable_eptz); needEPTZ = atoi(enable_eptz); } if(stream->height < 480 && !needEPTZ){ LOG_INFO("usb RGA for isp resolusion \n"); rga_width = stream->width; rga_height = stream->height; stream->height = 720; stream->width = 1280; needRGA = 1; } LOG_INFO("uvc width:%d,height:%d, needEPTZ %d, needRGA %d \n",stream->width,stream->height, needEPTZ, needRGA); #if EPTZ_ENABLE if(needEPTZ && !needRGA){ eptz_width = stream->width; eptz_height = stream->height; if(eptz_width > 1920 || eptz_height > 1080){ needEPTZ = 0; LOG_ERROR("needEPTZ, not support this width(>1920) and height(>1080) \n"); }else if(eptz_width == 1920){ char* max_width = getenv("CAMERA_MAX_WIDTH"); char* max_height = getenv("CAMERA_MAX_HEIGHT"); if(max_width && max_height){ int tmp_width = atoi(max_width); int tmp_height = atoi(max_height); LOG_INFO("needEPTZ, camera max resolutio [%d %d] \n", tmp_width, tmp_height); if(tmp_width > 1920 && tmp_height > 1080){ stream->width = tmp_width; stream->height = tmp_height; }else{ needEPTZ = 0; LOG_ERROR("needEPTZ, but camera max resolutio not support! error \n"); } }else{ stream->width = 2560; stream->height = 1440; } }else if(eptz_width <= 1280 && eptz_width >120 ){ stream->width = eptz_width * 1.5; stream->height = eptz_height * 1.5; }else { needEPTZ = 0; LOG_ERROR("needEPTZ, match fail \n"); } if(needEPTZ) LOG_INFO("needEPTZ uvc width:%d,height:%d \n",stream->width,stream->height); } #endif std::shared_ptr video_rga_flow=NULL; std::shared_ptr video_save_flow=NULL; // std::string input_path = "/dev/video0"; std::string input_path = "rkispp_scale0";//"/dev/video0"; //isp main path std::string input_format = IMAGE_NV12; int need_full_range = 1; char* full_range = getenv("ENABLE_FULL_RANGE"); if (full_range) { need_full_range = atoi(full_range); LOG_INFO("uvc full_range use env setting:%d \n",need_full_range); } //Reading yuv from camera std::string flow_name = "source_stream"; std::string flow_param = ""; PARAM_STRING_APPEND(flow_param, KEY_NAME, "v4l2_capture_stream"); PARAM_STRING_APPEND(flow_param, KEK_THREAD_SYNC_MODEL, KEY_SYNC); PARAM_STRING_APPEND(flow_param, KEK_INPUT_MODEL, KEY_DROPFRONT); PARAM_STRING_APPEND_TO(flow_param, KEY_INPUT_CACHE_NUM, 5); std::string stream_param = ""; PARAM_STRING_APPEND_TO(stream_param, KEY_USE_LIBV4L2, 1); PARAM_STRING_APPEND(stream_param, KEY_DEVICE, input_path); // PARAM_STRING_APPEND(param, KEY_SUB_DEVICE, sub_input_path); PARAM_STRING_APPEND(stream_param, KEY_V4L2_CAP_TYPE, KEY_V4L2_C_TYPE(VIDEO_CAPTURE)); PARAM_STRING_APPEND(stream_param, KEY_V4L2_MEM_TYPE, KEY_V4L2_M_TYPE(MEMORY_DMABUF)); PARAM_STRING_APPEND_TO(stream_param, KEY_FRAMES, 3); // if not set, default is 2 PARAM_STRING_APPEND(stream_param, KEY_OUTPUTDATATYPE, input_format); if ((stream->format == V4L2_PIX_FMT_H264) && (need_full_range == 0)) { LOG_INFO("stream->format:V4L2_PIX_FMT_H264,use V4L2_QUANTIZATION_LIM_RANGE!!"); PARAM_STRING_APPEND_TO(stream_param, KEY_V4L2_QUANTIZATION, V4L2_QUANTIZATION_LIM_RANGE); } PARAM_STRING_APPEND_TO(stream_param, KEY_BUFFER_WIDTH, stream->width); PARAM_STRING_APPEND_TO(stream_param, KEY_BUFFER_HEIGHT, stream->height); PARAM_STRING_APPEND_TO(stream_param, KEY_BUFFER_VIR_WIDTH, stream->width); PARAM_STRING_APPEND_TO(stream_param, KEY_BUFFER_VIR_HEIGHT, stream->height); flow_param = easymedia::JoinFlowParam(flow_param, 1, stream_param); LOG_INFO("\n#VideoCapture flow param:\n%s\n", flow_param.c_str()); stream->input = easymedia::REFLECTOR(Flow)::Create( flow_name.c_str(), flow_param.c_str()); if (!stream->input) { LOG_ERROR( "Create flow %s failed\n", flow_name.c_str()); goto record_exit; } mpi_get_env_u32("uvc_flow_output", &stream->uvc_flow_output, 0); if (stream->uvc_flow_output) { // test dump std::string output_path = "/data/uvc_flow_output_nv12.yuv"; flow_name = "file_write_flow"; flow_param = ""; PARAM_STRING_APPEND(flow_param, KEY_PATH, output_path.c_str()); PARAM_STRING_APPEND(flow_param, KEY_OPEN_MODE, "w+"); // read and close-on-exec LOG_INFO("\n#FileWrite:\n%s\n", flow_param.c_str()); video_save_flow = easymedia::REFLECTOR(Flow)::Create( flow_name.c_str(), flow_param.c_str()); if (!video_save_flow) { LOG_ERROR( "Create flow video_save_flow failed\n"); goto record_exit; } stream->input->AddDownFlow(video_save_flow, 0, 0); } else { stream->uvc_flow = std::make_shared(stream->deviceid); if (!stream->uvc_flow) { LOG_ERROR( "Create flow UVCJoinFlow failed\n"); goto record_exit; } if(needRGA) { flow_name = "filter"; flow_param = ""; PARAM_STRING_APPEND(flow_param, KEY_NAME, "rkrga"); PARAM_STRING_APPEND(flow_param, KEY_INPUTDATATYPE, input_format); //Set output buffer type. PARAM_STRING_APPEND(flow_param, KEY_OUTPUTDATATYPE, input_format); //Set output buffer size. PARAM_STRING_APPEND_TO(flow_param, KEY_BUFFER_WIDTH, rga_width); PARAM_STRING_APPEND_TO(flow_param, KEY_BUFFER_HEIGHT, rga_height); PARAM_STRING_APPEND_TO(flow_param, KEY_BUFFER_VIR_WIDTH, rga_width); PARAM_STRING_APPEND_TO(flow_param, KEY_BUFFER_VIR_HEIGHT, rga_height); std::string filter_param = ""; ImageRect src_rect = {0, 0, stream->width, stream->height}; ImageRect dst_rect = {0, 0, rga_width, rga_height}; std::vector rect_vect; rect_vect.push_back(src_rect); rect_vect.push_back(dst_rect); PARAM_STRING_APPEND(filter_param, KEY_BUFFER_RECT, easymedia::TwoImageRectToString(rect_vect).c_str()); PARAM_STRING_APPEND_TO(filter_param, KEY_BUFFER_ROTATE, 0); flow_param = easymedia::JoinFlowParam(flow_param, 1, filter_param); LOG_INFO("\n#Rkrga Filter flow param:\n%s\n", flow_param.c_str()); video_rga_flow = easymedia::REFLECTOR(Flow)::Create( flow_name.c_str(), flow_param.c_str()); if (!video_rga_flow) { LOG_ERROR( "Create flow %s failed\n", flow_name.c_str()); goto record_exit; } video_rga_flow->AddDownFlow(stream->uvc_flow, 0, 0); stream->input->AddDownFlow(video_rga_flow, 0, 0); } else { if(needEPTZ){ #if EPTZ_ENABLE int ret = eptz_config(stream->width, stream->height, eptz_width, eptz_height); if( ret == -1){ LOG_ERROR( "eptz_config failed\n"); goto record_exit; } dclip->AddDownFlow(stream->uvc_flow, 0, 0); stream->input->AddDownFlow(dclip, 0, 0); eptz_source->AddDownFlow(rknn, 0, 0); #endif }else{ #if EPTZ_ENABLE int ret = zoom_config(stream->width, stream->height); if( ret == -1){ LOG_ERROR( "zoom_config failed\n"); goto record_exit; } zoom->AddDownFlow(stream->uvc_flow, 0, 0); stream->input->AddDownFlow(zoom, 0, 0); #else stream->input->AddDownFlow(stream->uvc_flow, 0, 0); #endif } } } LOG_INFO("start,uvc_flow_output=%d\n", stream->uvc_flow_output); //system("mediaserver -d -c /oem/usr/share/mediaserver/camera_nv12_rga_nn_link.conf &"); while (stream->pthread_run) { camera_control_wait(stream); } goto record_exit; #endif #endif record_exit: LOG_INFO("%s exit\n", __func__); pthread_rwlock_wrlock(¬elock); //system("killall -9 mediaserver"); //usleep(500000);//rkisp requst the stream without init aiq close first! #if USE_RKMEDIA if (stream->uvc_flow_output) { if (stream->input) { if (video_save_flow) stream->input->RemoveDownFlow(video_save_flow); stream->input.reset(); } if (video_save_flow) video_save_flow.reset(); } if (stream->input) { if (stream->uvc_flow) { if (needRGA) { stream->input->RemoveDownFlow(video_rga_flow); stream->input.reset(); video_rga_flow->RemoveDownFlow(stream->uvc_flow); video_rga_flow.reset(); } else if (needEPTZ){ #if EPTZ_ENABLE if(eptz_source){ if(rknn) eptz_source->RemoveDownFlow(rknn); eptz_source.reset(); } if(rknn) rknn.reset(); if(dclip) stream->input->RemoveDownFlow(dclip); stream->input.reset(); if(dclip){ dclip->RemoveDownFlow(stream->uvc_flow); dclip.reset(); } #endif } else { #if EPTZ_ENABLE stream->input->RemoveDownFlow(zoom); stream->input.reset(); zoom->RemoveDownFlow(stream->uvc_flow); zoom.reset(); #else stream->input->RemoveDownFlow(stream->uvc_flow); stream->input.reset(); #endif } } stream->uvc_flow.reset(); } #endif #if USE_ROCKIT if (stream->uvc_graph) { delete(stream->uvc_graph); } #endif pthread_mutex_destroy(&stream->record_mutex); pthread_cond_destroy(&stream->record_cond); if (stream) free(stream); pthread_rwlock_unlock(¬elock); //camera_stop(stream); usleep(500000);//make sure rkispp deint stream = NULL; if(stream_list) stream_list = NULL; pthread_exit(NULL); } extern "C" int camera_control_start(int id, int width, int height, int fps, int format, int eptz) { struct Camera_Stream *stream; int ret = 0; if (id < 0) return -1; LOG_INFO("%s!\n", __func__); pthread_rwlock_wrlock(¬elock); stream = (struct Camera_Stream *)calloc(1, sizeof(struct Camera_Stream)); if (!stream) { LOG_ERROR("no memory!\n"); goto addvideo_exit; } pthread_mutex_init(&stream->record_mutex, NULL); pthread_cond_init(&stream->record_cond, NULL); #if USE_ROCKIT stream->pthread_run = 1; #endif #if USE_RKMEDIA stream->pthread_run = 1; stream->input = NULL; stream->uvc_flow = NULL; #endif stream->fps = fps; stream->width = width; stream->height = height; stream->format = format; stream->deviceid = id; stream->eptz = eptz; LOG_DEBUG("stream%d is uvc video device\n", stream->deviceid); while (stream_list) { LOG_DEBUG("%s wait for release stream_list!\n", __func__); usleep(100000);//wait for next } stream_list = stream; if (pthread_create(&stream->record_id, NULL, uvc_camera, stream)) { LOG_ERROR("%s pthread create err!\n", __func__); goto addvideo_exit; } record_id_list.push_back(stream->record_id); ret = 0; goto addvideo_ret; addvideo_exit: if (stream) { #if USE_RKMEDIA if (stream->input) { if (stream->uvc_flow) stream->input->RemoveDownFlow(stream->uvc_flow); stream->input.reset(); } if (stream->uvc_flow) stream->uvc_flow.reset(); #endif pthread_mutex_destroy(&stream->record_mutex); pthread_cond_destroy(&stream->record_cond); #if USE_RKMEDIA stream->input = NULL; stream->uvc_flow = NULL; #endif free(stream); stream = NULL; } LOG_DEBUG("stream%d exit!\n", id); ret = -1; addvideo_ret: LOG_INFO("%s!end\n", __func__); pthread_rwlock_unlock(¬elock); return ret; } extern "C" int camera_control_stop(int deviceid) { struct Camera_Stream *stream; stream = getfastvideo(); if(!stream) usleep(200000);//wait for stream on over pthread_rwlock_rdlock(¬elock); while (stream) { if (stream->deviceid == deviceid) { video_record_signal(stream); break; } } pthread_rwlock_unlock(¬elock); return 0; } extern "C" void camera_control_init() { //todo } extern "C" void camera_control_set_eptz(int val){ if (val > 0) val = 1; else val = 0; #if USE_RK_AISERVER uvc_ipc_event(UVC_IPC_EVENT_ENABLE_ETPTZ, (void *)&val); #endif #if USE_ROCKIT if (stream_list) { if (stream_list->uvc_graph) { stream_list->uvc_graph->enableEPTZ(val); } } #endif } extern "C" void camera_control_set_zoom(int val) { LOG_INFO("set_zoom:%d\n",val); #if USE_ROCKIT if (stream_list) { if (stream_list->uvc_graph) { stream_list->uvc_graph->setZoom((float)val/10); } } #else #if EPTZ_ENABLE set_zoom((float)val/10); #endif #endif #if USE_RK_AISERVER uvc_ipc_event(UVC_IPC_EVENT_SET_ZOOM, (void *)&val); #endif } extern "C" void camera_control_set_pan(int val) { LOG_INFO("set_pan:%d\n",val); #if USE_ROCKIT if (stream_list) { if (stream_list->uvc_graph) { stream_list->uvc_graph->setEptz(RT_EPTZ_PAN, val); } } #endif #if USE_RK_AISERVER uvc_ipc_event(UVC_IPC_EVENT_SET_EPTZ_PAN, (void *)&val); #endif } extern "C" void camera_control_set_tilt(int val) { LOG_INFO("set_tilt:%d\n",val); #if USE_ROCKIT if (stream_list) { if (stream_list->uvc_graph) { stream_list->uvc_graph->setEptz(RT_EPTZ_TILT, val); } } #endif #if USE_RK_AISERVER uvc_ipc_event(UVC_IPC_EVENT_SET_EPTZ_TILT, (void *)&val); #endif } extern "C" void camera_control_set_roll(int val) { LOG_INFO("set_roll:%d\n",val); //todo } extern "C" void camera_control_deinit() { LOG_INFO("%s!start\n", __func__); struct Camera_Stream *stream; std::list save_list; pthread_rwlock_wrlock(¬elock); stream = getfastvideo(); while (stream) { video_record_signal(stream); break; } save_list.clear(); for (std::list::iterator it = record_id_list.begin(); it != record_id_list.end(); ++it) save_list.push_back(*it); record_id_list.clear(); pthread_rwlock_unlock(¬elock); for (std::list::iterator it = save_list.begin(); it != save_list.end(); ++it) { LOG_INFO("pthread_join record id: %lu\n", *it); pthread_join(*it, NULL); } save_list.clear(); LOG_INFO("%s!end\n", __func__); }