#include "VideoInput.h" #include "BoostLog.h" #include "DetectAlgorithm.h" #include "rw_mpp_api.h" #include class VideoInputPrivate { public: void processFrame(S_mpp_img &image); void processImage(S_mpp_img &image, S_mpp_img &detectImage, uint64_t frameIndex); int32_t encodeChannel = -1; int32_t scaleChannel = -1; S_vdec_config decoderConfig; std::shared_ptr m_detector; }; VideoInput::VideoInput(int32_t width, int32_t height) : m_d(new VideoInputPrivate()), m_width(width), m_height(height) { int status = rw_mpp__vdec_init(); if (status != 0) { LOG(error) << "rw_mpp__vdec_init() failed, status: " << status; } m_d->m_detector = std::make_shared(); } VideoInput::~VideoInput() { if (isStarted()) { stop(); } rw_mpp__vdec_finalize(); } bool VideoInput::start() { if (!m_exit) { LOG(warning) << "camera already started..."; return false; } S_video_cfg vcfg; vcfg.sns_w = -1; vcfg.sns_h = -1; vcfg.img_w = m_width; vcfg.img_h = m_height; m_vid = 0; m_exit = false; int status = rw_mpp__video_start(m_vid, &vcfg); if (status != 0) { LOG(error) << "rw_mpp__video_start() failed, status: " << status; m_vid = -1; } else { m_thread = std::thread(&VideoInput::run, this); } return status == 0; } void VideoInput::stop() { m_exit = true; if (m_encodeThread.joinable()) { m_encodeThread.join(); } if (m_thread.joinable()) { m_thread.join(); } rw_mpp__video_stop(m_vid); if (m_decodeChannel >= 0) { rw_mpp__vdec_stop(m_decodeChannel); m_decodeChannel = -1; } if (m_d->scaleChannel >= 0) { rw_mpp__vscale_stop(m_d->scaleChannel); m_d->scaleChannel = -1; } if (m_d->encodeChannel >= 0) { rw_mpp__venc_stop(m_d->encodeChannel); m_d->encodeChannel = -1; } m_vid = -1; } bool VideoInput::isStarted() const { return !m_exit; } bool VideoInput::startEncode() { m_d->encodeChannel = 0; S_venc_config config; memset(&config, 0, sizeof(S_venc_config)); config.codec = CODEC_H264; config.profile = H264_main; config.raw_max_width = 2960; config.raw_max_height = 1664; config.width = 1280; config.height = 720; config.gop = 15; config.framerate = 15; config.rc_type = RC_VBR; S_venc_rc_vbr vbr; memset(&vbr, 0, sizeof(S_venc_rc_vbr)); vbr.max_bitrate = 1024; vbr.stats_time = 1; config.rc_param = &vbr; int status = rw_mpp__venc_start(m_d->encodeChannel, &config, -1); if (status != 0) { LOG(error) << "rw_mpp__venc_start() failed, status: " << status; } else { m_encodeThread = std::thread(&VideoInput::encodeRun, this); } m_d->scaleChannel = 0; S_vscale_cfg scaleConfig = {2960, 1664, DetectAlgorithm::DetectWidth, DetectAlgorithm::DetectHeight}; status = rw_mpp__vscale_start(m_d->scaleChannel, &scaleConfig); if (status != 0) { LOG(error) << "rw_mpp__vscale_start() failed, status: " << status; } return status == 0; } bool VideoInput::startFileInput(const std::string &path, int32_t width, int32_t height) { m_width = width; m_height = height; m_path = path; m_ifs = std::make_shared(path, std::ifstream::binary); m_exit = false; m_decodeChannel = 0; memset(&m_d->decoderConfig, 0, sizeof(S_vdec_config)); m_d->decoderConfig.send_mode = VDEC_SEND__STREAM; m_d->decoderConfig.codec = CODEC_H264; m_d->decoderConfig.raw_max_width = 2960; m_d->decoderConfig.raw_max_height = 1664; m_d->decoderConfig.width = width; m_d->decoderConfig.height = height; int status = rw_mpp__vdec_start(m_decodeChannel, &m_d->decoderConfig); if (status != 0) { LOG(error) << "rw_mpp__vdec_start() failed, status: " << status; } else { m_thread = std::thread(&VideoInput::fakeRun, this); } return status == 0; } void VideoInput::setPacketHandler(const PacketHandler &hanlder) { m_handler = hanlder; } void VideoInputPrivate::processImage(S_mpp_img &image, S_mpp_img &detectImage, uint64_t frameIndex) { m_detector->detect(detectImage.nv21, frameIndex); } void VideoInputPrivate::processFrame(S_mpp_img &image) { static uint64_t frameIndex = 0; S_mpp_img detectImage; memset(&detectImage, 0, sizeof(S_mpp_img)); int status = rw_mpp__vscale_exec(scaleChannel, &image, &detectImage); if (status == 0) { frameIndex++; processImage(image, detectImage, frameIndex); status = rw_mpp__vscale_free(scaleChannel, &detectImage); } else { LOG(warning) << "rw_mpp__vscale_exec() failed, status: " << status; } if (encodeChannel >= 0) { rw_mpp__venc_send(encodeChannel, &image); } } void VideoInput::run() { using namespace std::chrono_literals; S_mpp_img image; while (!m_exit) { int status = rw_mpp__video_recv(m_vid, &image, 2000); if (status != 0) { LOG(error) << "rw_mpp__video_recv() failed, status: " << status; std::this_thread::sleep_for(500ms); continue; } // LOG(info) << "camera frame size: " << img.width << "x" << img.height; m_d->processFrame(image); status = rw_mpp__video_free(m_vid, &image); if (status != 0) { LOG(error) << "rw_mpp__video_free() failed, status: " << status; } } } void VideoInput::fakeRun() { using namespace std::chrono; using namespace std::chrono_literals; S_mpp_vdec_frame frame; S_mpp_img image; int bufferSize = m_width * m_height * 3 / 2; if (bufferSize > 1024 * 64) bufferSize = 1024 * 64; char *buffer = new char[bufferSize]; std::chrono::system_clock::time_point last; while (!m_exit) { while (m_ifs->read(buffer, bufferSize) && !m_exit) { int readSize = m_ifs->gcount(); frame.data = reinterpret_cast(buffer); frame.len = readSize; int status = rw_mpp__vdec_send(m_decodeChannel, &frame); if (status != 0) { LOG(error) << "rw_mpp__vdec_send() failed, status: " << status; std::this_thread::sleep_for(10ms); continue; } int receiveStatus = 0; while (receiveStatus == 0) { receiveStatus = rw_mpp__vdec_recv(m_decodeChannel, &image, 20); if (receiveStatus != 0) { std::this_thread::sleep_for(10ms); break; } else { m_d->processFrame(image); rw_mpp__vdec_free(m_decodeChannel, &image); } auto now = std::chrono::system_clock::now(); auto elapsed = duration_cast(now - last); last = now; // LOG(info) << "process, elapsed: " << elapsed.count(); if (elapsed <= milliseconds(69)) { std::this_thread::sleep_for(69ms - elapsed); } } } m_ifs = std::make_shared(m_path, std::ifstream::binary); rw_mpp__vdec_send_end(0); } if (buffer != nullptr) delete buffer; } void VideoInput::encodeRun() { using namespace std::chrono_literals; S_mpp_venc_frame frame; while (!m_exit) { int status = rw_mpp__venc_recv(m_d->encodeChannel, &frame, 1000); if (status != 0) { std::this_thread::sleep_for(500ms); LOG(error) << "rw_mpp__venc_recv() failed, status: " << status; continue; } // LOG(info) << "encode frame data size: " << frame.len << ", is key frame: " << frame.is_key_frame; if (m_handler) { m_handler(frame.data, frame.len); } status = rw_mpp__venc_free(m_d->encodeChannel, &frame); if (status != 0) { LOG(error) << "rw_mpp__venc_free() failed, status: " << status; } } }