RV1126 frame reading CPU usage

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)

BTW FPS is 15

Um hocheffektive ICF ICF-ACC Zertifizierungsprüfung vorzubereiten, wissen Sie, Welches Gerät verwendbar ist? ICF ICF-ACC Dumps von Pass4Test sind die zuverlässigen Unterlagen. Die Unterlagen sind von IT-Eliten geschaffen. Die sind auch sehr seltene Unterlagen. Die Hitz-Rate der ICF ICF-ACC Dumps ist sehr hoch und die Durchlaufrate erreicht 100%, weil die IT-Eliten die Punkte der Prüfungsfragen sehr gut und alle möglichen Fragen in zukünftigen aktuellen Prüfungen sammeln. Glauben Sie nicht? Aber es ist wirklich. Sie können wissen nach der Nutzung.

The content is just that good—instant like from me. With the PSE-Cortex-Pro-24 reliable study questions book, I advanced in my career and earned a salary increase. Now, it’s free for everyone. Wishing you quick promotions!