/* * Copyright (c) 2019 Rockchip 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. * */ #include #include "Isp20PollThread.h" #include "Isp20StatsBuffer.h" #include "rkisp2-config.h" #include "SensorHw.h" #include "LensHw.h" #include "Isp20_module_dbg.h" #include #ifndef DIV_ROUND_UP #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #endif #ifdef ANDROID_OS #define DEFAULT_CAPTURE_RAW_PATH "/data/capture_image" #define CAPTURE_CNT_FILENAME "/data/.capture_cnt" #else #define DEFAULT_CAPTURE_RAW_PATH "/tmp/capture_image" #define CAPTURE_CNT_FILENAME "/tmp/.capture_cnt" #endif #define WRITE_RAW_FILE_HEADER /* * #define WRITE_ISP_REG * #define WRITE_ISPP_REG */ #define ISP_REGS_BASE 0xffb50000 #define ISPP_REGS_BASE 0xffb60000 #define RAW_FILE_IDENT 0x8080 #define HEADER_LEN 128U /* * Raw file structure: * +------------+-----------------+-------------+-----------------+---------------------------+ | ITEM | PARAMETER | DATA TYPE | LENGTH(Bytes) | DESCRIPTION | +------------+-----------------+-------------+-----------------+---------------------------+ | | Identifier | uint16_t | 2 | fixed 0x8080 | | +-----------------+-------------+-----------------+---------------------------+ | | Header length | uint16_t | 2 | fixed 128U | | +-----------------+-------------+-----------------+---------------------------+ | | Frame index | uint32_t | 4 | | | +-----------------+-------------+-----------------+---------------------------+ | | Width | uint16_t | 2 | image width | | +-----------------+-------------+-----------------+---------------------------+ | | Height | uint16_t | 2 | image height | | +-----------------+-------------+-----------------+---------------------------+ | | Bit depth | uint8_t | 1 | image bit depth | | +-----------------+-------------+-----------------+---------------------------+ | | | | | 0: BGGR; 1: GBRG; | | | Bayer format | uint8_t | 1 | 2: GRBG; 3: RGGB; | | +-----------------+-------------+-----------------+---------------------------+ | | | | | 1: linear | | FRAME | Number of HDR | | | 2: long + short | | HEADER | frame | uint8_t | 1 | 3: long + mid + short | | +-----------------+-------------+-----------------+---------------------------+ | | | | | 1: short | | | Current frame | | | 2: mid | | | type | uint8_t | 1 | 3: long | | +-----------------+-------------+-----------------+---------------------------+ | | Storage type | uint8_t | 1 | 0: packed; 1: unpacked | | +-----------------+-------------+-----------------+---------------------------+ | | Line stride | uint16_t | 2 | In bytes | | +-----------------+-------------+-----------------+---------------------------+ | | Effective | | | | | | line stride | uint16_t | 2 | In bytes | | +-----------------+-------------+-----------------+---------------------------+ | | Reserved | uint8_t | 107 | | +------------+-----------------+-------------+-----------------+---------------------------+ | | | | | | | RAW DATA | RAW DATA | RAW | W * H * bpp | RAW DATA | | | | | | | +------------+-----------------+-------------+-----------------+---------------------------+ */ /* * the structure of measuure parameters from isp in meta_data file: * * "frame%08d-l_m_s-gain[%08.5f_%08.5f_%08.5f]-time[%08.5f_%08.5f_%08.5f]-awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]" * */ namespace RkCam { const struct capture_fmt Isp20PollThread::csirx_fmts[] = { /* raw */ { .fourcc = V4L2_PIX_FMT_SRGGB8, .bayer_fmt = 3, .pcpp = 1, .bpp = { 8 }, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .bayer_fmt = 2, .pcpp = 1, .bpp = { 8 }, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .bayer_fmt = 1, .pcpp = 1, .bpp = { 8 }, }, { .fourcc = V4L2_PIX_FMT_SBGGR8, .bayer_fmt = 0, .pcpp = 1, .bpp = { 8 }, }, { .fourcc = V4L2_PIX_FMT_SRGGB10, .bayer_fmt = 3, .pcpp = 4, .bpp = { 10 }, }, { .fourcc = V4L2_PIX_FMT_SGRBG10, .bayer_fmt = 2, .pcpp = 4, .bpp = { 10 }, }, { .fourcc = V4L2_PIX_FMT_SGBRG10, .bayer_fmt = 1, .pcpp = 4, .bpp = { 10 }, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, .bayer_fmt = 0, .pcpp = 4, .bpp = { 10 }, }, { .fourcc = V4L2_PIX_FMT_SRGGB12, .bayer_fmt = 3, .pcpp = 2, .bpp = { 12 }, }, { .fourcc = V4L2_PIX_FMT_SGRBG12, .bayer_fmt = 2, .pcpp = 2, .bpp = { 12 }, }, { .fourcc = V4L2_PIX_FMT_SGBRG12, .bayer_fmt = 1, .pcpp = 2, .bpp = { 12 }, }, { .fourcc = V4L2_PIX_FMT_SBGGR12, .bayer_fmt = 0, .pcpp = 2, .bpp = { 12 }, }, }; const char* Isp20PollThread::mipi_poll_type_to_str[ISP_POLL_MIPI_MAX] = { "mipi_tx_poll", "mipi_rx_poll", }; class MipiPollThread : public Thread { public: MipiPollThread (Isp20PollThread*poll, int type, int dev_index) : Thread (Isp20PollThread::mipi_poll_type_to_str[type]) , _poll (poll) , _type (type) , _dev_index (dev_index) {} protected: virtual bool loop () { XCamReturn ret = _poll->mipi_poll_buffer_loop (_type, _dev_index); if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT || XCAM_RETURN_BYPASS) return true; return false; } private: Isp20PollThread *_poll; int _type; int _dev_index; }; bool Isp20PollThread::get_value_from_file(const char* path, int& value, uint32_t& frameId) { const char *delim = " "; char buffer[16] = {0}; int fp; fp = open(path, O_RDONLY | O_SYNC); if (fp != -1) { if (read(fp, buffer, sizeof(buffer)) <= 0) { LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "%s read %s failed!\n", __func__, path); } else { char *p = nullptr; p = strtok(buffer, delim); if (p != nullptr) { value = atoi(p); p = strtok(nullptr, delim); if (p != nullptr) frameId = atoi(p); } } close(fp); LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "value: %d, frameId: %d\n", value, frameId); return true; } return false; } bool Isp20PollThread::set_value_to_file(const char* path, int value, uint32_t sequence) { char buffer[16] = {0}; int fp; fp = open(path, O_CREAT | O_RDWR | O_SYNC, S_IRWXU | S_IRUSR | S_IXUSR | S_IROTH | S_IXOTH); if (fp != -1) { ftruncate(fp, 0); lseek(fp, 0, SEEK_SET); snprintf(buffer, sizeof(buffer), "%3d %8d\n", _capture_raw_num, sequence); if (write(fp, buffer, sizeof(buffer)) <= 0) LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s write %s failed!\n", __func__, path); close(fp); return true; } return false; } SmartPtr Isp20PollThread::new_video_buffer(SmartPtr buf, SmartPtr dev, int type) { ENTER_CAMHW_FUNCTION(); SmartPtr video_buf = nullptr; if (type == ISP_POLL_3A_STATS) { rkisp_effect_params_v20 ispParams = {0}; SmartPtr expParams = nullptr; SmartPtr irisParams = nullptr; SmartPtr afParams = nullptr; //get exp params _event_handle_dev->getEffectiveExpParams(expParams, buf->get_buf().sequence); if (_focus_handle_dev.ptr()) { _focus_handle_dev->getAfInfoParams(afParams, buf->get_buf().sequence); _focus_handle_dev->getIrisInfoParams(irisParams, buf->get_buf().sequence); } if (mCamHw) { if (mCamHw->getEffectiveIspParams(ispParams, buf->get_buf().sequence) != XCAM_RETURN_NO_ERROR) LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "sequence(%d), get ispparams failed!!!\n", buf->get_buf().sequence); } video_buf = new Isp20StatsBuffer(buf, dev, _event_handle_dev, mCamHw, afParams, irisParams); // write metadata && isp/ispp reg for debug if (_capture_metadata_num > 0) { char file_name[32] = {0}; int capture_cnt = 0; uint32_t rawFrmId = 0; snprintf(file_name, sizeof(file_name), "%s", CAPTURE_CNT_FILENAME); get_value_from_file(file_name, capture_cnt, rawFrmId); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "rawFrmId: %d, sequence: %d, _capture_metadata_num: %d\n", rawFrmId, buf->get_buf().sequence, _capture_metadata_num); if (_is_raw_dir_exist && buf->get_buf().sequence >= rawFrmId && \ expParams.ptr()) #ifdef WRITE_ISP_REG write_reg_to_file(ISP_REGS_BASE, 0x0, 0x6000, buf->get_buf().sequence); #endif #ifdef WRITE_ISPP_REG write_reg_to_file(ISPP_REGS_BASE, 0x0, 0xc94, buf->get_buf().sequence); #endif write_metadata_to_file(raw_dir_path, buf->get_buf().sequence, ispMeasParams, expParams, afParams); _capture_metadata_num--; if (!_capture_metadata_num) { _is_raw_dir_exist = false; if (_capture_raw_type == CAPTURE_RAW_SYNC) { _capture_image_mutex.lock(); _capture_image_cond.broadcast(); _capture_image_mutex.unlock(); } LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "stop capturing raw!\n"); } } } else return PollThread::new_video_buffer(buf, dev, type); EXIT_CAMHW_FUNCTION(); return video_buf; } XCamReturn Isp20PollThread::notify_sof (uint64_t time, int frameid) { ENTER_CAMHW_FUNCTION(); XCamReturn ret = XCAM_RETURN_NO_ERROR; XCAM_ASSERT(_event_handle_dev.ptr()); ret = _event_handle_dev->handle_sof(time, frameid); if (get_rkaiq_runtime_dbg() > 0) { XCAM_STATIC_FPS_CALCULATION(SOF_FPS, 60); } if (_focus_handle_dev.ptr()) _focus_handle_dev->handle_sof(time, frameid); _sof_map_mutex.lock(); while (_sof_timestamp_map.size() > 8) _sof_timestamp_map.erase(_sof_timestamp_map.begin()); _sof_timestamp_map[frameid] = time; _sof_map_mutex.unlock(); EXIT_CAMHW_FUNCTION(); return ret; } bool Isp20PollThread::set_event_handle_dev(SmartPtr &dev) { ENTER_CAMHW_FUNCTION(); XCAM_ASSERT (dev.ptr()); _event_handle_dev = dev; rk_aiq_exposure_sensor_descriptor sns_des; dev->get_format(&sns_des); sns_width = sns_des.sensor_output_width; sns_height = sns_des.sensor_output_height; pixelformat = sns_des.sensor_pixelformat; if (!_linked_to_isp) { XCamReturn ret = XCAM_RETURN_NO_ERROR; // get sensor crop bounds struct v4l2_subdev_selection sns_sd_sel; memset(&sns_sd_sel, 0, sizeof(sns_sd_sel)); ret = dev->get_selection(0, V4L2_SEL_TGT_CROP_BOUNDS, sns_sd_sel); if (ret) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "get_selection failed !\n"); } else { if (sns_width != sns_sd_sel.r.width || sns_height != sns_sd_sel.r.height) { sns_width = sns_sd_sel.r.width; sns_height = sns_sd_sel.r.height; } } } EXIT_CAMHW_FUNCTION(); return true; } bool Isp20PollThread::set_focus_handle_dev(SmartPtr &dev) { ENTER_CAMHW_FUNCTION(); XCAM_ASSERT (dev.ptr()); _focus_handle_dev = dev; EXIT_CAMHW_FUNCTION(); return true; } bool Isp20PollThread::setCamHw(ICamHw *dev) { ENTER_CAMHW_FUNCTION(); XCAM_ASSERT (dev); mCamHw = dev; EXIT_CAMHW_FUNCTION(); return true; } Isp20PollThread::Isp20PollThread() : PollThread() , _first_trigger(true) , sns_width(0) , sns_height(0) , _is_raw_dir_exist(false) , _is_capture_raw(false) , _capture_raw_num(0) , _capture_metadata_num(0) , _capture_image_mutex(false) , _capture_image_cond(false) , _capture_raw_type(CAPTURE_RAW_ASYNC) , _is_multi_cam_conc(false) , _skip_num(0) , _skip_to_seq(0) , _need_luma_rd_info(true) { for (int i = 0; i < 3; i++) { SmartPtr mipi_poll = new MipiPollThread(this, ISP_POLL_MIPI_TX, i); XCAM_ASSERT (mipi_poll.ptr ()); _isp_mipi_tx_infos[i].loop = mipi_poll; mipi_poll = new MipiPollThread(this, ISP_POLL_MIPI_RX, i); XCAM_ASSERT (mipi_poll.ptr ()); _isp_mipi_rx_infos[i].loop = mipi_poll; _isp_mipi_tx_infos[i].stop_fds[0] = -1; _isp_mipi_tx_infos[i].stop_fds[1] = -1; _isp_mipi_rx_infos[i].stop_fds[0] = -1; _isp_mipi_rx_infos[i].stop_fds[1] = -1; } LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "Isp20PollThread constructed"); } Isp20PollThread::~Isp20PollThread() { stop(); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "~Isp20PollThread destructed"); } XCamReturn Isp20PollThread::start () { if (create_stop_fds_mipi()) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "create mipi stop fds failed !"); return XCAM_RETURN_ERROR_UNKNOWN; } for (int i = 0; i < _mipi_dev_max; i++) { _isp_mipi_tx_infos[i].loop->start (); _isp_mipi_rx_infos[i].loop->start (); } return PollThread::start (); } XCamReturn Isp20PollThread::stop () { for (int i = 0; i < _mipi_dev_max; i++) { if (_isp_mipi_tx_infos[i].dev.ptr ()) { if (_isp_mipi_tx_infos[i].stop_fds[1] != -1) { char buf = 0xf; // random value to write to flush fd. unsigned int size = write(_isp_mipi_tx_infos[i].stop_fds[1], &buf, sizeof(char)); if (size != sizeof(char)) LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "Flush write not completed"); } _isp_mipi_tx_infos[i].loop->stop (); /* _isp_mipi_tx_infos[i].buf_list.clear (); */ /* _isp_mipi_tx_infos[i].cache_list.clear (); */ } if (_isp_mipi_rx_infos[i].dev.ptr ()) { if (_isp_mipi_rx_infos[i].stop_fds[1] != -1) { char buf = 0xf; // random value to write to flush fd. unsigned int size = write(_isp_mipi_rx_infos[i].stop_fds[1], &buf, sizeof(char)); if (size != sizeof(char)) LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "Flush write not completed"); } _isp_mipi_rx_infos[i].loop->stop (); /* _isp_mipi_rx_infos[i].buf_list.clear (); */ /* _isp_mipi_rx_infos[i].cache_list.clear (); */ } } for (int i = 0; i < _mipi_dev_max; i++) { if (_isp_mipi_tx_infos[i].dev.ptr ()) { _isp_mipi_tx_infos[i].buf_list.clear (); _isp_mipi_tx_infos[i].cache_list.clear (); } if (_isp_mipi_rx_infos[i].dev.ptr ()) { _isp_mipi_rx_infos[i].buf_list.clear (); _isp_mipi_rx_infos[i].cache_list.clear (); } } _mipi_trigger_mutex.lock(); _isp_hdr_fid2times_map.clear(); _isp_hdr_fid2ready_map.clear(); _hdr_global_tmo_state_map.clear(); _mipi_trigger_mutex.unlock(); _sof_map_mutex.lock(); _sof_timestamp_map.clear(); _sof_map_mutex.unlock(); destroy_stop_fds_mipi (); _skip_num = 0; return PollThread::stop (); } void Isp20PollThread::set_working_mode(int mode, bool linked_to_isp, bool nordbk) { _working_mode = mode; _linked_to_isp = linked_to_isp; switch (_working_mode) { case RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR: case RK_AIQ_ISP_HDR_MODE_3_LINE_HDR: _mipi_dev_max = 3; break; case RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR: case RK_AIQ_ISP_HDR_MODE_2_LINE_HDR: _mipi_dev_max = 2; break; default: _mipi_dev_max = 1; } if (nordbk) _mipi_dev_max = 0; } void Isp20PollThread::set_mipi_devs(SmartPtr mipi_tx_devs[3], SmartPtr mipi_rx_devs[3], SmartPtr isp_dev) { _isp_core_dev = isp_dev; for (int i = 0; i < 3; i++) { _isp_mipi_tx_infos[i].dev = mipi_tx_devs[i]; _isp_mipi_rx_infos[i].dev = mipi_rx_devs[i]; } } void Isp20PollThread::set_hdr_frame_readback_infos(rk_aiq_luma_params_t luma_params) { _mipi_trigger_mutex.lock(); _isp_hdr_fid2times_map[luma_params.frame_id] = luma_params; LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "rdtimes seq %d \n", luma_params.frame_id); _mipi_trigger_mutex.unlock(); trigger_readback(); } XCamReturn Isp20PollThread::create_stop_fds_mipi () { int i, status = 0; XCamReturn ret = XCAM_RETURN_NO_ERROR; destroy_stop_fds_mipi(); for (i = 0; i < _mipi_dev_max; i++) { status = pipe(_isp_mipi_tx_infos[i].stop_fds); if (status < 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Failed to create mipi tx:%d poll stop pipe: %s", i, strerror(errno)); ret = XCAM_RETURN_ERROR_UNKNOWN; goto exit_error; } status = fcntl(_isp_mipi_tx_infos[0].stop_fds[0], F_SETFL, O_NONBLOCK); if (status < 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Fail to set event mipi tx:%d stop pipe flag: %s", i, strerror(errno)); goto exit_error; } status = pipe(_isp_mipi_rx_infos[i].stop_fds); if (status < 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Failed to create mipi rx:%d poll stop pipe: %s", i, strerror(errno)); ret = XCAM_RETURN_ERROR_UNKNOWN; goto exit_error; } status = fcntl(_isp_mipi_rx_infos[0].stop_fds[0], F_SETFL, O_NONBLOCK); if (status < 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Fail to set event mipi rx:%d stop pipe flag: %s", i, strerror(errno)); goto exit_error; } } return XCAM_RETURN_NO_ERROR; exit_error: destroy_stop_fds_mipi(); return ret; } void Isp20PollThread::destroy_stop_fds_mipi () { for (int i = 0; i < 3; i++) { if (_isp_mipi_tx_infos[i].stop_fds[0] != -1 || _isp_mipi_tx_infos[i].stop_fds[1] != -1) { close(_isp_mipi_tx_infos[i].stop_fds[0]); close(_isp_mipi_tx_infos[i].stop_fds[1]); _isp_mipi_tx_infos[i].stop_fds[0] = -1; _isp_mipi_tx_infos[i].stop_fds[1] = -1; } if (_isp_mipi_rx_infos[i].stop_fds[0] != -1 || _isp_mipi_rx_infos[i].stop_fds[1] != -1) { close(_isp_mipi_rx_infos[i].stop_fds[0]); close(_isp_mipi_rx_infos[i].stop_fds[1]); _isp_mipi_rx_infos[i].stop_fds[0] = -1; _isp_mipi_rx_infos[i].stop_fds[1] = -1; } } } XCamReturn Isp20PollThread::mipi_poll_buffer_loop (int type, int dev_index) { XCamReturn ret = XCAM_RETURN_NO_ERROR; int poll_ret = 0; SmartPtr buf; SmartPtr dev; int stop_fd = -1; if (type == ISP_POLL_MIPI_TX) { dev = _isp_mipi_tx_infos[dev_index].dev; stop_fd = _isp_mipi_tx_infos[dev_index].stop_fds[0]; } else if (type == ISP_POLL_MIPI_RX) { dev = _isp_mipi_rx_infos[dev_index].dev; stop_fd = _isp_mipi_rx_infos[dev_index].stop_fds[0]; } else return XCAM_RETURN_ERROR_UNKNOWN; poll_ret = dev->poll_event (PollThread::default_poll_timeout, stop_fd); if (poll_ret == POLL_STOP_RET) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "poll %s buffer stop success !", mipi_poll_type_to_str[type]); // stop success, return error to stop the poll thread return XCAM_RETURN_ERROR_UNKNOWN; } if (poll_ret <= 0) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "mipi_dev_index %d poll %s buffer event got error(0x%x) but continue\n", dev_index, mipi_poll_type_to_str[type], poll_ret); ::usleep (10000); // 10ms return XCAM_RETURN_ERROR_TIMEOUT; } ret = dev->dequeue_buffer (buf); if (ret != XCAM_RETURN_NO_ERROR) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "dequeue %s buffer failed", mipi_poll_type_to_str[type]); return ret; } SmartPtr buf_proxy = new V4l2BufferProxy(buf, dev); if (type == ISP_POLL_MIPI_TX) { handle_tx_buf(buf_proxy, dev_index); } else if (type == ISP_POLL_MIPI_RX) { _event_handle_dev->on_dqueue(dev_index, buf_proxy); handle_rx_buf(buf_proxy, dev_index); } return ret; } void Isp20PollThread::handle_rx_buf(SmartPtr &rx_buf, int dev_index) { if (!_isp_mipi_rx_infos[dev_index].buf_list.is_empty()) { SmartPtr buf = _isp_mipi_rx_infos[dev_index].buf_list.pop(-1); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "%s dev_index:%d index:%d fd:%d\n", __func__, dev_index, buf->get_v4l2_buf_index(), buf->get_expbuf_fd()); } } void Isp20PollThread::sync_tx_buf() { SmartPtr buf_s, buf_m, buf_l; uint32_t sequence_s = -1, sequence_m = -1, sequence_l = -1; _mipi_buf_mutex.lock(); for (int i = 0; i < _mipi_dev_max; i++) { if (_isp_mipi_tx_infos[i].buf_list.is_empty()) { _mipi_buf_mutex.unlock(); return; } } buf_l = _isp_mipi_tx_infos[ISP_MIPI_HDR_L].buf_list.front(); if (buf_l.ptr()) sequence_l = buf_l->get_sequence(); buf_m = _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.front(); if (buf_m.ptr()) sequence_m = buf_m->get_sequence(); buf_s = _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.front(); if (buf_s.ptr()) { sequence_s = buf_s->get_sequence(); if ((_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) && buf_m.ptr() && buf_l.ptr() && buf_s.ptr() && sequence_l == sequence_s && sequence_m == sequence_s) { _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.erase(buf_m); _isp_mipi_tx_infos[ISP_MIPI_HDR_L].buf_list.erase(buf_l); if (check_skip_frame(sequence_s)) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); goto end; } _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); _isp_mipi_rx_infos[ISP_MIPI_HDR_M].cache_list.push(buf_m); _isp_mipi_rx_infos[ISP_MIPI_HDR_L].cache_list.push(buf_l); _mipi_trigger_mutex.lock(); _isp_hdr_fid2ready_map[sequence_s] = true; _mipi_trigger_mutex.unlock(); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); trigger_readback(); } else if ((_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) && buf_m.ptr() && buf_s.ptr() && sequence_m == sequence_s) { _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); _isp_mipi_tx_infos[ISP_MIPI_HDR_M].buf_list.erase(buf_m); if (check_skip_frame(sequence_s)) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); goto end; } _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); _isp_mipi_rx_infos[ISP_MIPI_HDR_M].cache_list.push(buf_m); _mipi_trigger_mutex.lock(); _isp_hdr_fid2ready_map[sequence_s] = true; _mipi_trigger_mutex.unlock(); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); trigger_readback(); } else if (_working_mode == RK_AIQ_WORKING_MODE_NORMAL) { _isp_mipi_tx_infos[ISP_MIPI_HDR_S].buf_list.erase(buf_s); if (check_skip_frame(sequence_s)) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "skip frame %d", sequence_s); goto end; } _isp_mipi_rx_infos[ISP_MIPI_HDR_S].cache_list.push(buf_s); _mipi_trigger_mutex.lock(); _isp_hdr_fid2ready_map[sequence_s] = true; _mipi_trigger_mutex.unlock(); LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "trigger readback %d", sequence_s); trigger_readback(); } else { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "do nothing, sequence not match l: %d, s: %d, m: %d !!!", sequence_l, sequence_s, sequence_m); } } end: _mipi_buf_mutex.unlock(); } void Isp20PollThread::handle_tx_buf(SmartPtr &tx_buf, int dev_index) { LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "%s dev_index:%d sequence:%d\n", __func__, dev_index, tx_buf->get_sequence()); _isp_mipi_tx_infos[dev_index].buf_list.push(tx_buf); sync_tx_buf(); } void Isp20PollThread::trigger_readback() { std::map::iterator it_ready; SmartPtr v4l2buf[3]; SmartPtr buf_proxy; uint32_t sequence = -1; sint32_t additional_times = -1; bool isHdrGlobalTmo = false; bool isDhazEn = false, isTmoEn = false; u64 ispModuleEns = 0x0; _mipi_trigger_mutex.lock(); if (!_first_trigger && _cache_tx_data) { /* * The hdrtmo needs to get the luma in advance, * so cache a frame of tx data. */ if (_isp_hdr_fid2ready_map.size() < 2) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s buf not ready(%d) !", __func__, _isp_hdr_fid2ready_map.size()); _mipi_trigger_mutex.unlock(); return; } } else { if (_isp_hdr_fid2ready_map.size() == 0) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s buf not ready(%d) !", __func__, _isp_hdr_fid2ready_map.size()); _mipi_trigger_mutex.unlock(); return; } } it_ready = _isp_hdr_fid2ready_map.begin(); sequence = it_ready->first; if (!_event_handle_dev->is_virtual_sensor()) { match_lumadetect_map(sequence, additional_times); if (additional_times == -1) { LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "%s rdtimes not ready for seq %d !", __func__, sequence); _mipi_trigger_mutex.unlock(); return; } } match_globaltmostate_map(sequence, isHdrGlobalTmo); _isp_hdr_fid2ready_map.erase(it_ready); if (mCamHw) { int ret = XCAM_RETURN_NO_ERROR; if (ret != XCAM_RETURN_NO_ERROR) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "%s frame[%d] set isp params failed, don't read back!\n", __func__, sequence); // drop frame, return buf to tx for (int i = 0; i < _mipi_dev_max; i++) { _isp_mipi_rx_infos[i].cache_list.pop(-1); } goto out; } else { // whether to start capturing raw files char file_name[32] = {0}; snprintf(file_name, sizeof(file_name), "%s", CAPTURE_CNT_FILENAME); detect_capture_raw_status(file_name, sequence); for (int i = 0; i < _mipi_dev_max; i++) { ret = _isp_mipi_rx_infos[i].dev->get_buffer(v4l2buf[i], _isp_mipi_rx_infos[i].cache_list.front()->get_v4l2_buf_index()); if (ret != XCAM_RETURN_NO_ERROR) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Rx[%d] can not get buffer\n", i); goto out; } else { buf_proxy = _isp_mipi_rx_infos[i].cache_list.pop(-1); #if 0 if (_first_trigger) { u8 *buf = (u8 *)buf_proxy->get_v4l2_userptr(); struct v4l2_format format = v4l2buf[i]->get_format(); u32 bytesperline = format.fmt.pix_mp.plane_fmt[0].bytesperline; if (buf) { for (u32 k = 0; k < 16; k++) { for (u32 j = 0; j < bytesperline / 2; j++) *buf++ += (k + j) % 16; buf += bytesperline / 2; } } } #endif _isp_mipi_rx_infos[i].buf_list.push(buf_proxy); if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_USERPTR) v4l2buf[i]->set_expbuf_usrptr(buf_proxy->get_v4l2_userptr()); else if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_DMABUF){ v4l2buf[i]->set_expbuf_fd(buf_proxy->get_expbuf_fd()); }else if (_isp_mipi_rx_infos[i].dev->get_mem_type() == V4L2_MEMORY_MMAP) { if (_isp_mipi_tx_infos[i].dev->get_use_type() == 1) { memcpy((void*)v4l2buf[i]->get_expbuf_usrptr(),(void*)buf_proxy->get_v4l2_userptr(),v4l2buf[i]->get_buf().m.planes[0].length); v4l2buf[i]->set_reserved(buf_proxy->get_v4l2_userptr()); } } dynamic_capture_raw(i, sequence, buf_proxy, v4l2buf[i]); } } for (int i = 0; i < _mipi_dev_max; i++) { ret = _isp_mipi_rx_infos[i].dev->queue_buffer(v4l2buf[i]); if (ret != XCAM_RETURN_NO_ERROR) { _isp_mipi_rx_infos[i].buf_list.pop(-1); LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "Rx[%d] queue buffer failed\n", i); break; } } struct isp2x_csi_trigger tg = { .sof_timestamp = 0, .frame_timestamp = 0, .frame_id = sequence, .times = 0, .mode = _mipi_dev_max == 1 ? T_START_X1 : _mipi_dev_max == 2 ? T_START_X2 : T_START_X3, /* .mode = T_START_X2, */ }; ispModuleEns = mCamHw->getIspModuleEnState(); if (ispModuleEns & (1LL << RK_ISP2X_HDRTMO_ID)) isTmoEn = true; if (ispModuleEns & (1LL << RK_ISP2X_DHAZ_ID)) isDhazEn = true; /* In the case of multiple sensors, read back at least twice * if dhaz or tmo enable */ if (_is_multi_cam_conc && (isTmoEn || isDhazEn)) tg.times = 1; /* Fixed read back once: * 1. global TMO and dhaz is off * 2. tmo && dhaz is off */ if (isTmoEn && isHdrGlobalTmo && !isDhazEn) additional_times = 0; else if (!isTmoEn && !isDhazEn) additional_times = 0; tg.times += additional_times; if (_first_trigger) tg.times = 1; else if (tg.times > 2) tg.times = 2; uint64_t sof_timestamp; match_sof_timestamp_map(tg.frame_id, sof_timestamp); tg.sof_timestamp = sof_timestamp; tg.frame_timestamp = buf_proxy->get_timestamp () * 1000; // tg.times = 1;//fixed to three times readback LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "frame[%d]: sof_ts %" PRId64 "ms, frame_ts %" PRId64 "ms, globalTmo(%d), readback(%d)\n", sequence, tg.sof_timestamp / 1000 / 1000, tg.frame_timestamp / 1000 / 1000, isHdrGlobalTmo, tg.times); if (ret == XCAM_RETURN_NO_ERROR) _isp_core_dev->io_control(RKISP_CMD_TRIGGER_READ_BACK, &tg); else LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "%s frame[%d] queue failed, don't read back!\n", __func__, sequence); update_capture_raw_status(file_name); } } _first_trigger = false; out: _mipi_trigger_mutex.unlock(); } XCamReturn Isp20PollThread::getEffectiveLumaParams(int frame_id, rk_aiq_luma_params_t& luma_params) { ENTER_CAMHW_FUNCTION(); std::map::iterator it; uint32_t search_id = frame_id < 0 ? 0 : frame_id; if (_isp_hdr_fid2times_map.size() == 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "can't search id %d, _effecting_exp_mapsize is %d\n", frame_id, _isp_hdr_fid2times_map.size()); return XCAM_RETURN_ERROR_PARAM; } it = _isp_hdr_fid2times_map.find(search_id); // havn't found if (it == _isp_hdr_fid2times_map.end()) { std::map::reverse_iterator rit; rit = _isp_hdr_fid2times_map.rbegin(); do { if (search_id >= rit->first) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "exp-sync: can't find id %d, get latest id %d in _isp_hdr_fid2times_map\n", search_id, rit->first); break; } } while (++rit != _isp_hdr_fid2times_map.rend()); if (rit == _isp_hdr_fid2times_map.rend()) { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "can't find the latest effecting exposure for id %d, impossible case !", frame_id); return XCAM_RETURN_ERROR_PARAM; } luma_params = rit->second; } else { luma_params = it->second; } while (_isp_hdr_fid2times_map.size() > 4) _isp_hdr_fid2times_map.erase(_isp_hdr_fid2times_map.begin()); EXIT_CAMHW_FUNCTION(); return XCAM_RETURN_NO_ERROR; } void Isp20PollThread::match_lumadetect_map(uint32_t sequence, sint32_t &additional_times) { uint32_t frame_id, target_id; if (!_need_luma_rd_info) { additional_times = 0; return ; } if (_isp_hdr_fid2times_map.empty()) LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "luma map is empty"); while (_isp_hdr_fid2times_map.size() > 4) _isp_hdr_fid2times_map.erase(_isp_hdr_fid2times_map.begin()); std::map::iterator iter, it_times_del; for (iter = _isp_hdr_fid2times_map.begin(); iter != _isp_hdr_fid2times_map.end();) { if (_cache_tx_data) { /* * The hdrtmo needs to get the luma in advance, * so match the luma of previous frame in Lumadetect. */ target_id = iter->first - 1; } else { target_id = iter->first; } if (target_id < sequence && iter->first != 0) { it_times_del = iter++; LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_times_del->first); // _isp_hdr_fid2times_map.erase(it_times_del); } else if (target_id == sequence || iter->first == 0) { additional_times = iter->second.hdrProcessCnt; frame_id = iter->first; it_times_del = iter++; LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "find luma id(%d)-seq id(%d)", frame_id, sequence); // _isp_hdr_fid2times_map.erase(it_times_del); break; } else { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s missing rdtimes for buf_seq %d, min rdtimes_seq %d !", __func__, sequence, iter->first); additional_times = 0; break; } } } void Isp20PollThread::match_globaltmostate_map(uint32_t sequence, bool &isHdrGlobalTmo) { std::map::iterator it_del; for (std::map::iterator iter = _hdr_global_tmo_state_map.begin(); iter != _hdr_global_tmo_state_map.end();) { if (iter->first < sequence) { it_del = iter++; LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_del->first); _hdr_global_tmo_state_map.erase(it_del); } else if (iter->first == sequence) { isHdrGlobalTmo = iter->second; it_del = iter++; LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "del seq %d", it_del->first); _hdr_global_tmo_state_map.erase(it_del); break; } else { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "%s missing tmo state for buf_seq %d, min rdtimes_seq %d !", __func__, sequence, iter->first); break; } } } XCamReturn Isp20PollThread::match_sof_timestamp_map(sint32_t sequence, uint64_t ×tamp) { XCamReturn ret = XCAM_RETURN_NO_ERROR; std::map::iterator it; sint32_t search_id = sequence < 0 ? 0 : sequence; _sof_map_mutex.lock(); it = _sof_timestamp_map.find(search_id); if (it != _sof_timestamp_map.end()) { timestamp = it->second; _sof_timestamp_map.erase(it); } else { LOGW_CAMHW_SUBM(ISP20POLL_SUBM, "can't find frameid(%d), get sof timestamp failed!\n", sequence); ret = XCAM_RETURN_ERROR_FAILED; } _sof_map_mutex.unlock(); return ret; } void Isp20PollThread::write_metadata_to_file(const char* dir_path, int frame_id, rkisp_effect_params_v20& ispParams, SmartPtr& expParams, SmartPtr& afParams) { #if 0 // TODO Merge FILE *fp = nullptr; char file_name[64] = {0}; char buffer[256] = {0}; int32_t focusCode = 0; int32_t zoomCode = 0; snprintf(file_name, sizeof(file_name), "%s/meta_data", dir_path); if(afParams.ptr()) { focusCode = afParams->data()->focusCode; zoomCode = afParams->data()->zoomCode; } fp = fopen(file_name, "ab+"); if (fp != nullptr) { if (_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || \ _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) { snprintf(buffer, sizeof(buffer), "frame%08d-l_m_s-gain[%08.5f_%08.5f_%08.5f]-time[%08.5f_%08.5f_%08.5f]-" "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", frame_id, expParams->data()->aecExpInfo.HdrExp[2].exp_real_params.analog_gain, expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.analog_gain, expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.analog_gain, expParams->data()->aecExpInfo.HdrExp[2].exp_real_params.integration_time, expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.integration_time, expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.integration_time, ispParams->data()->awb_gain.rgain, ispParams->data()->awb_gain.grgain, ispParams->data()->awb_gain.gbgain, ispParams->data()->awb_gain.bgain, 1, focusCode, zoomCode); } else if (_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || \ _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) { snprintf(buffer, sizeof(buffer), "frame%08d-l_s-gain[%08.5f_%08.5f]-time[%08.5f_%08.5f]-" "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", frame_id, expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.analog_gain, expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.analog_gain, expParams->data()->aecExpInfo.HdrExp[1].exp_real_params.integration_time, expParams->data()->aecExpInfo.HdrExp[0].exp_real_params.integration_time, ispParams->data()->awb_gain.rgain, ispParams->data()->awb_gain.grgain, ispParams->data()->awb_gain.gbgain, ispParams->data()->awb_gain.bgain, 1, focusCode, zoomCode); } else { snprintf(buffer, sizeof(buffer), "frame%08d-gain[%08.5f]-time[%08.5f]-" "awbGain[%08.4f_%08.4f_%08.4f_%08.4f]-dgain[%08d]-afcode[%08d_%08d]\n", frame_id, expParams->data()->aecExpInfo.LinearExp.exp_real_params.analog_gain, expParams->data()->aecExpInfo.LinearExp.exp_real_params.integration_time, ispParams->data()->awb_gain.rgain, ispParams->data()->awb_gain.grgain, ispParams->data()->awb_gain.gbgain, ispParams->data()->awb_gain.bgain, 1, focusCode, zoomCode); } fwrite((void *)buffer, strlen(buffer), 1, fp); fflush(fp); fclose(fp); } #endif } const struct capture_fmt* Isp20PollThread::find_fmt(const uint32_t pixelformat) { const struct capture_fmt *fmt; unsigned int i; for (i = 0; i < sizeof(csirx_fmts); i++) { fmt = &csirx_fmts[i]; if (fmt->fourcc == pixelformat) return fmt; } return NULL; } int Isp20PollThread::detect_capture_raw_status(const char* file_name, uint32_t sequence) { if (!_is_capture_raw) { uint32_t rawFrmId = 0; get_value_from_file(file_name, _capture_raw_num, rawFrmId); if (_capture_raw_num > 0) { set_value_to_file(file_name, _capture_raw_num, sequence); _is_capture_raw = true; _capture_metadata_num = _capture_raw_num; if (_first_trigger) ++_capture_metadata_num; } } return 0; } int Isp20PollThread::update_capture_raw_status(const char* file_name) { if (_is_capture_raw && !_first_trigger) { if (_capture_raw_type == CAPTURE_RAW_AND_YUV_SYNC) { _capture_image_mutex.lock(); _capture_image_cond.timedwait(_capture_image_mutex, 3000000); _capture_image_mutex.unlock(); } if (!--_capture_raw_num) { set_value_to_file(file_name, _capture_raw_num); _is_capture_raw = false; } } return 0; } int Isp20PollThread::dynamic_capture_raw(int i, uint32_t sequence, SmartPtr buf_proxy, SmartPtr &v4l2buf) { if (_is_capture_raw && _capture_raw_num > 0) { if (!_is_raw_dir_exist) { if (_capture_raw_type == CAPTURE_RAW_SYNC) creat_raw_dir(user_set_raw_dir); else creat_raw_dir(DEFAULT_CAPTURE_RAW_PATH); } if (_is_raw_dir_exist) { char raw_name[128] = {0}; FILE *fp = nullptr; XCAM_STATIC_PROFILING_START(write_raw); memset(raw_name, 0, sizeof(raw_name)); if (_mipi_dev_max == 1) snprintf(raw_name, sizeof(raw_name), "%s/frame%d_%dx%d_%s.raw", raw_dir_path, sequence, sns_width, sns_height, "normal"); else if (_mipi_dev_max == 2) snprintf(raw_name, sizeof(raw_name), "%s/frame%d_%dx%d_%s.raw", raw_dir_path, sequence, sns_width, sns_height, i == 0 ? "short" : "long"); else snprintf(raw_name, sizeof(raw_name), "%s/frame%d_%dx%d_%s.raw", raw_dir_path, sequence, sns_width, sns_height, i == 0 ? "short" : i == 1 ? "middle" : "long"); fp = fopen(raw_name, "wb+"); if (fp != nullptr) { int size = 0; #ifdef WRITE_RAW_FILE_HEADER write_frame_header_to_raw(fp, i, sequence); #endif #if 0 size = v4l2buf->get_buf().m.planes[0].length; #else /* raw image size compatible with ISP expansion line mode */ size = _stride_perline * sns_height; #endif write_raw_to_file(fp, i, sequence, (void *)(buf_proxy->get_v4l2_userptr()), size); fclose(fp); } XCAM_STATIC_PROFILING_END(write_raw, 0); } } return 0; } int Isp20PollThread::calculate_stride_per_line(const struct capture_fmt& fmt, uint32_t& bytesPerLine) { uint32_t pixelsPerLine = 0, stridePerLine = 0; /* The actual size stored in the memory */ uint32_t actualBytesPerLine = 0; bytesPerLine = sns_width * fmt.bpp[0] / 8; pixelsPerLine = fmt.pcpp * DIV_ROUND_UP(sns_width, fmt.pcpp); actualBytesPerLine = pixelsPerLine * fmt.bpp[0] / 8; #if 0 /* mipi wc(Word count) must be 4 byte aligned */ stridePerLine = 256 * DIV_ROUND_UP(actualBytesPerLine, 256); #else struct v4l2_format format; memset(&format, 0, sizeof(format)); _isp_mipi_tx_infos[0].dev->get_format(format); stridePerLine = format.fmt.pix_mp.plane_fmt[0].bytesperline; #endif LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "sns_width: %d, pixelsPerLine: %d, bytesPerLine: %d, stridePerLine: %d\n", sns_width, pixelsPerLine, bytesPerLine, stridePerLine); return stridePerLine; } /* * Refer to "Raw file structure" in the header of this file */ XCamReturn Isp20PollThread::write_frame_header_to_raw(FILE *fp, int dev_index, int sequence) { uint8_t buffer[128] = {0}; uint32_t stridePerLine = 0, bytesPerLine = 0; const struct capture_fmt* fmt = nullptr; uint8_t mode = 0; uint8_t frame_type = 0, storage_type = 0; if (fp == nullptr) return XCAM_RETURN_ERROR_PARAM; if ((fmt = find_fmt(pixelformat))) stridePerLine = calculate_stride_per_line(*fmt, bytesPerLine); if (_working_mode == RK_AIQ_ISP_HDR_MODE_3_FRAME_HDR || \ _working_mode == RK_AIQ_ISP_HDR_MODE_3_LINE_HDR) { mode = 3; frame_type = dev_index == 0 ? 1 : dev_index == 1 ? 2 : 3; } else if (_working_mode == RK_AIQ_ISP_HDR_MODE_2_FRAME_HDR || \ _working_mode == RK_AIQ_ISP_HDR_MODE_2_LINE_HDR) { mode = 2; frame_type = dev_index == 0 ? 1 : 3; } else { mode = 1; } _stride_perline = stridePerLine; *((uint16_t* )buffer) = RAW_FILE_IDENT; // Identifier *((uint16_t* )(buffer + 2)) = HEADER_LEN; // Header length *((uint32_t* )(buffer + 4)) = sequence; // Frame number *((uint16_t* )(buffer + 8)) = sns_width; // Image width *((uint16_t* )(buffer + 10)) = sns_height; // Image height *(buffer + 12) = fmt->bpp[0]; // Bit depth *(buffer + 13) = fmt->bayer_fmt; // Bayer format *(buffer + 14) = mode; // Number of HDR frame *(buffer + 15) = frame_type; // Current frame type *(buffer + 16) = storage_type; // Storage type *((uint16_t* )(buffer + 17)) = stridePerLine; // Line stride *((uint16_t* )(buffer + 19)) = bytesPerLine; // Effective line stride fwrite(buffer, sizeof(buffer), 1, fp); fflush(fp); LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "frame%d: image rect: %dx%d, %d bit depth, Bayer fmt: %d, " "hdr frame number: %d, frame type: %d, Storage type: %d, " "line stride: %d, Effective line stride: %d\n", sequence, sns_width, sns_height, fmt->bpp[0], fmt->bayer_fmt, mode, frame_type, storage_type, stridePerLine, bytesPerLine); return XCAM_RETURN_NO_ERROR; } XCamReturn Isp20PollThread::write_raw_to_file(FILE* fp, int dev_index, int sequence, void* userptr, int size) { if (fp == nullptr) return XCAM_RETURN_ERROR_PARAM; fwrite(userptr, size, 1, fp); fflush(fp); if (!dev_index) { for (int i = 0; i < _capture_raw_num; i++) printf(">"); printf("\n"); LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "write frame%d raw\n", sequence); } return XCAM_RETURN_NO_ERROR; } void Isp20PollThread::write_reg_to_file(uint32_t base_addr, uint32_t offset_addr, int len, int sequence) { } XCamReturn Isp20PollThread::creat_raw_dir(const char* path) { time_t now; struct tm* timenow; if (!path) return XCAM_RETURN_ERROR_FAILED; time(&now); timenow = localtime(&now); if (access(path, W_OK) == -1) { if (mkdir(path, 0755) < 0) LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s error(%s)!\n", path, strerror(errno)); return XCAM_RETURN_ERROR_PARAM; } snprintf(raw_dir_path, sizeof(raw_dir_path), "%s/raw_%04d-%02d-%02d_%02d-%02d-%02d", path, timenow->tm_year + 1900, timenow->tm_mon + 1, timenow->tm_mday, timenow->tm_hour, timenow->tm_min, timenow->tm_sec); LOGV_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s for capturing %d frames raw!\n", raw_dir_path, _capture_raw_num); if(mkdir(raw_dir_path, 0755) < 0) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "mkdir %s error(%s)!!!\n", raw_dir_path, strerror(errno)); return XCAM_RETURN_ERROR_PARAM; } _is_raw_dir_exist = true; return XCAM_RETURN_ERROR_PARAM; } XCamReturn Isp20PollThread::notify_capture_raw() { SmartLock locker(_capture_image_mutex); _capture_image_cond.broadcast(); return XCAM_RETURN_NO_ERROR; } XCamReturn Isp20PollThread::capture_raw_ctl(capture_raw_t type, int count, const char* capture_dir, char* output_dir) { XCamReturn ret = XCAM_RETURN_NO_ERROR; _capture_raw_type = type; if (_capture_raw_type == CAPTURE_RAW_SYNC) { if (capture_dir != nullptr) snprintf(user_set_raw_dir, sizeof( user_set_raw_dir), "%s/capture_image", capture_dir); else strcpy(user_set_raw_dir, DEFAULT_CAPTURE_RAW_PATH); char cmd_buffer[32] = {0}; snprintf(cmd_buffer, sizeof(cmd_buffer), "echo %d > %s", count, CAPTURE_CNT_FILENAME); system(cmd_buffer); _capture_image_mutex.lock(); if (_capture_image_cond.timedwait(_capture_image_mutex, 30000000) != 0) ret = XCAM_RETURN_ERROR_TIMEOUT; else strncpy(output_dir, raw_dir_path, strlen(raw_dir_path)); _capture_image_mutex.unlock(); } else if (_capture_raw_type == CAPTURE_RAW_AND_YUV_SYNC) { LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "capture raw and yuv images simultaneously!"); } return ret; } void Isp20PollThread::set_hdr_global_tmo_mode(int frame_id, bool mode) { _mipi_trigger_mutex.lock(); _hdr_global_tmo_state_map[frame_id] = mode; _mipi_trigger_mutex.unlock(); } void Isp20PollThread::skip_frames(int skip_num, int32_t skip_seq) { _mipi_trigger_mutex.lock(); _skip_num = skip_num; _skip_to_seq = skip_seq + _skip_num; _mipi_trigger_mutex.unlock(); } bool Isp20PollThread::check_skip_frame(int32_t buf_seq) { _mipi_trigger_mutex.lock(); #if 0 // ts if (_skip_num > 0) { int64_t skip_ts_ms = _skip_start_ts / 1000 / 1000; int64_t buf_ts_ms = buf_ts / 1000; LOGD_CAMHW_SUBM(ISP20POLL_SUBM, "skip num %d, start from %" PRId64 " ms, buf ts %" PRId64 " ms", _skip_num, skip_ts_ms, buf_ts_ms); if (buf_ts_ms > skip_ts_ms) { _skip_num--; _mipi_trigger_mutex.unlock(); return true; } } #else if ((_skip_num > 0) && (buf_seq < _skip_to_seq)) { LOGE_CAMHW_SUBM(ISP20POLL_SUBM, "skip num %d, skip seq %d, dest seq %d", _skip_num, buf_seq, _skip_to_seq); _skip_num--; _mipi_trigger_mutex.unlock(); return true; } #endif _mipi_trigger_mutex.unlock(); return false; } }; //namspace RkCam