2024-03-13 11:40:55 +08:00
|
|
|
#include "VideoInput.h"
|
|
|
|
#include "BoostLog.h"
|
2024-03-13 18:01:36 +08:00
|
|
|
#include "DetectAlgorithm.h"
|
2024-03-13 11:40:55 +08:00
|
|
|
#include "rw_mpp_api.h"
|
|
|
|
#include <chrono>
|
|
|
|
|
2024-03-13 18:01:36 +08:00
|
|
|
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<DetectAlgorithm> 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<DetectAlgorithm>();
|
2024-03-13 11:40:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
VideoInput::~VideoInput() {
|
|
|
|
if (isStarted()) {
|
|
|
|
stop();
|
|
|
|
}
|
2024-03-13 18:01:36 +08:00
|
|
|
rw_mpp__vdec_finalize();
|
2024-03-13 11:40:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2024-03-13 18:01:36 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2024-03-13 11:40:55 +08:00
|
|
|
m_vid = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoInput::isStarted() const {
|
|
|
|
return !m_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VideoInput::startEncode() {
|
2024-03-13 18:01:36 +08:00
|
|
|
m_d->encodeChannel = 0;
|
2024-03-13 11:40:55 +08:00
|
|
|
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;
|
2024-03-13 18:01:36 +08:00
|
|
|
int status = rw_mpp__venc_start(m_d->encodeChannel, &config, -1);
|
2024-03-13 11:40:55 +08:00
|
|
|
if (status != 0) {
|
|
|
|
LOG(error) << "rw_mpp__venc_start() failed, status: " << status;
|
|
|
|
} else {
|
|
|
|
m_encodeThread = std::thread(&VideoInput::encodeRun, this);
|
|
|
|
}
|
2024-03-13 18:01:36 +08:00
|
|
|
|
|
|
|
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<std::ifstream>(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);
|
|
|
|
}
|
2024-03-13 11:40:55 +08:00
|
|
|
return status == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VideoInput::setPacketHandler(const PacketHandler &hanlder) {
|
|
|
|
m_handler = hanlder;
|
|
|
|
}
|
|
|
|
|
2024-03-13 18:01:36 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 11:40:55 +08:00
|
|
|
void VideoInput::run() {
|
|
|
|
using namespace std::chrono_literals;
|
2024-03-13 18:01:36 +08:00
|
|
|
S_mpp_img image;
|
2024-03-13 11:40:55 +08:00
|
|
|
while (!m_exit) {
|
2024-03-13 18:01:36 +08:00
|
|
|
int status = rw_mpp__video_recv(m_vid, &image, 2000);
|
2024-03-13 11:40:55 +08:00
|
|
|
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;
|
2024-03-13 18:01:36 +08:00
|
|
|
m_d->processFrame(image);
|
|
|
|
status = rw_mpp__video_free(m_vid, &image);
|
2024-03-13 11:40:55 +08:00
|
|
|
if (status != 0) {
|
|
|
|
LOG(error) << "rw_mpp__video_free() failed, status: " << status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-13 18:01:36 +08:00
|
|
|
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<uint8_t *>(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<milliseconds>(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<std::ifstream>(m_path, std::ifstream::binary);
|
|
|
|
rw_mpp__vdec_send_end(0);
|
|
|
|
}
|
|
|
|
if (buffer != nullptr) delete buffer;
|
|
|
|
}
|
|
|
|
|
2024-03-13 11:40:55 +08:00
|
|
|
void VideoInput::encodeRun() {
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
S_mpp_venc_frame frame;
|
|
|
|
while (!m_exit) {
|
2024-03-13 18:01:36 +08:00
|
|
|
int status = rw_mpp__venc_recv(m_d->encodeChannel, &frame, 1000);
|
2024-03-13 11:40:55 +08:00
|
|
|
if (status != 0) {
|
|
|
|
std::this_thread::sleep_for(500ms);
|
|
|
|
LOG(error) << "rw_mpp__venc_recv() failed, status: " << status;
|
|
|
|
continue;
|
|
|
|
}
|
2024-03-13 18:01:36 +08:00
|
|
|
// LOG(info) << "encode frame data size: " << frame.len << ", is key frame: " << frame.is_key_frame;
|
2024-03-13 11:40:55 +08:00
|
|
|
if (m_handler) {
|
|
|
|
m_handler(frame.data, frame.len);
|
|
|
|
}
|
2024-03-13 18:01:36 +08:00
|
|
|
status = rw_mpp__venc_free(m_d->encodeChannel, &frame);
|
2024-03-13 11:40:55 +08:00
|
|
|
if (status != 0) {
|
|
|
|
LOG(error) << "rw_mpp__venc_free() failed, status: " << status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|