|
Posted at 3/24/2023 16:49:32
Problem description and steps to reproduce:
Last edited by emreharbutoglu In 3/24/2023 16:50 Editor
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] = '=';
- }
Copy the code
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.
|
|