Type: Official Firmware
Filename: AIO-RV1126-JD4-BE-45_Debian_v2.2.5b_221025.img
Download Address: AIO-RV1126-JD4-BE-45_Debian_v2.2.5b_221025.img
Log: out.zip
Hi, I am using the firmware above. I wrote a C++ code that reads frames from a USB camera with ffmpeg library. But the problem is CPU usage. The process is consuming CPU around between %50-60. This is too much for a frame reading task. What should I do for this?
#include <iostream>
#include <chrono>
#include <cstddef>
#include <unistd.h>
#include <string.h>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libavutil/avutil.h>
#include <libavutil/pixdesc.h>
#include <libswscale/swscale.h>
}
#include "opencv2/opencv.hpp"
#include "zmq.hpp"
#include "nlohmann/json.hpp"
#include <opencv2/highgui.hpp>
using json = nlohmann::json;
#define WIDTH (640)
#define HEIGHT (480)
#define VIDM_COEFF (7)
void int2array(u_char* output_array, uint64_t num, uint8_t digit);
void combine_arrays(u_char* main_array, int id_size, int data_size, u_char* array_1, u_char* array_2);
int main(){
std::ifstream cfg_file("config.json");
json cfg = json::parse(cfg_file);
zmq::context_t ctx;
zmq::socket_t publisher(ctx, ZMQ_PUB);
publisher.bind("ipc:///frames_socket.ipc");
const char* infile = "/dev/video25";
// initialize FFmpeg library
avcodec_register_all();
avdevice_register_all();
av_register_all();
// av_log_set_level(AV_LOG_DEBUG);
AVInputFormat *inputFormat =av_find_input_format("v4l2");
AVDictionary *options = NULL;
av_dict_set(&options, "input_format", "mjpeg", 0);
av_dict_set(&options, "framerate", "15", 0);
av_dict_set(&options, "aspect", "4:3", 0);
av_dict_set(&options, "video_size", "640x480", 0);
//AVFormatContext *pAVFormatContext = NULL;
int ret;
// open input file context
AVFormatContext* inctx = nullptr;
ret = avformat_open_input(&inctx, infile, inputFormat, &options);
if (ret < 0) {
std::cerr << "fail to avforamt_open_input(\"" << infile << "\"): ret=" << ret;
return 2;
}
// retrive input stream information
ret = avformat_find_stream_info(inctx, nullptr);
if (ret < 0) {
std::cerr << "fail to avformat_find_stream_info: ret=" << ret;
return 2;
}
// find primary video stream
AVCodec* vcodec = nullptr;
ret = av_find_best_stream(inctx, AVMEDIA_TYPE_VIDEO, -1, -1, &vcodec, 0);
if (ret < 0) {
std::cerr << "fail to av_find_best_stream: ret=" << ret;
return 2;
}
const int vstrm_idx = ret;
AVStream* vstrm = inctx->streams[vstrm_idx];
// open video decoder context
ret = avcodec_open2(vstrm->codec, vcodec, nullptr);
if (ret < 0) {
std::cerr << "fail to avcodec_open2: ret=" << ret;
return 2;
}
const int dst_width = vstrm->codec->width;
const int dst_height = vstrm->codec->height;
const AVPixelFormat dst_pix_fmt = AV_PIX_FMT_BGR24;
SwsContext* swsctx = sws_getCachedContext(
nullptr, vstrm->codec->width, vstrm->codec->height, vstrm->codec->pix_fmt,
dst_width, dst_height, dst_pix_fmt, SWS_BICUBIC, nullptr, nullptr, nullptr);
if (!swsctx) {
std::cerr << "fail to sws_getCachedContext";
return 2;
}
AVFrame* frame = av_frame_alloc();
std::vector<uint8_t> framebuf(avpicture_get_size(dst_pix_fmt, dst_width, dst_height));
avpicture_fill(reinterpret_cast<AVPicture*>(frame), framebuf.data(), dst_pix_fmt, dst_width, dst_height);
AVFrame* decframe = av_frame_alloc();
bool end_of_stream = false;
int got_pic = 0;
AVPacket pkt;
auto rpm = std::chrono::high_resolution_clock::now();
uint16_t fps_counter = 0;
do {
if ((std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - rpm)).count() >= 1000000) {
std::cout << "FPS_COUNTER: " << fps_counter << std::endl;
rpm = std::chrono::high_resolution_clock::now();
fps_counter = 0;
}
auto fps_time_start = std::chrono::high_resolution_clock::now();
usleep(50000); //35000 for cam
//while(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - fps_time_start).count() <= 100000);
if (!end_of_stream) {
ret = av_read_frame(inctx, &pkt);
if (ret < 0 && ret != AVERROR_EOF) {
std::cerr << "fail to av_read_frame: ret=" << ret;
return 2;
}
if (ret == 0 && pkt.stream_index != vstrm_idx)
goto next_packet;
end_of_stream = (ret == AVERROR_EOF);
}
if (end_of_stream) {
// null packet for bumping process
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
}
// decode video frame
avcodec_decode_video2(vstrm->codec, decframe, &got_pic, &pkt);
if (!got_pic) {
goto next_packet;
}
// convert frame to OpenCV matrix
sws_scale(swsctx, decframe->data, decframe->linesize, 0, decframe->height, frame->data, frame->linesize);
{
cv::Mat image(dst_height, dst_width, CV_8UC3, framebuf.data(), frame->linesize[0]);
//cv::imwrite("frame_test.png", image);
//cv::resize(image, image, cv::Size(640, 640), cv::INTER_LINEAR);
//auto fps_duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - fps_time_start);
//
//std::cout << "fps_duration" << 1000000/fps_duration.count() << std::endl;
uint64_t frame_id = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
u_char b_frame_id[16];
int2array(b_frame_id, frame_id, 16);
auto pub_time_start = std::chrono::high_resolution_clock::now();
u_char main_array[16+image.total()*image.elemSize()];
combine_arrays(main_array, 16, image.total()*image.elemSize(), b_frame_id, image.data);
zmq::message_t msg(main_array, 16+image.total()*image.elemSize());
//zmq::message_t msg_frame_id(b_frame_id, 16);
//zmq::message_t msg_frame(image.data, image.total()*image.elemSize());
//publisher.send(msg_frame_id, zmq::send_flags::sndmore);
//publisher.send(msg_frame, zmq::send_flags::none);
publisher.send(msg, zmq::send_flags::none);
auto pub_duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - pub_time_start);
auto fps_duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - fps_time_start);
std::cout << "ZMQ publish took: " << pub_duration.count() << " microseconds " << 1000000/fps_duration.count() << " fps" << std::endl;
time_t now = time(0);
fps_counter++;
std::cout << "[INFO] Frame Published, frame_id: " << frame_id << ", datetime: " << std::ctime(&now);
}
next_packet:
av_free_packet(&pkt);
} while (!end_of_stream || got_pic);
av_frame_free(&decframe);
av_frame_free(&frame);
avcodec_close(vstrm->codec);
avformat_close_input(&inctx);
return 0;
}
void combine_arrays(u_char* main_array, int id_size, int data_size, u_char* array_1, u_char* array_2){
for(int i = 0; i < id_size; i++){
main_array[i] = array_1[i];
}
for(int i = 0; i < data_size; i++){
main_array[i+16] = array_2[i];
}
}
void int2array(u_char* output_array, uint64_t num, uint8_t digit){
for (int i = digit-1-3; i >= 0; i--)
{
output_array[i] = (num % 10);
num /= 10;
}
output_array[13] = '=';
output_array[14] = '=';
output_array[15] = '=';
}
Also I have found a solution but it’s CPU usage around between %20-30. I executing a shell command that reads frames with ffmpeg command. Not an effective solution.
My goal is reducing the CPU usage to between %5-10.
tchip_askquestions
out.zip (987 Bytes)