【问题标题】:use gstreamer pipeline to init opencv's videocapture, has memory leak when Repeatedly reset videocapture使用 gstreamer 管道初始化 opencv 的 videocapture,当反复重置 videocapture 时有内存泄漏
【发布时间】:2022-07-27 15:10:22
【问题描述】:

环境

  • Jetson Xavier NX
  • 喷气背包 4.6
  • NVIDIA® Jetson™ Linux 驱动程序包 (L4T) 32.6.1
  • gstreamer1.14.5
  • opencv4.1.1

代码

int CMyServer::open_camera() {
   string zstr = "rtspsrc location=rtsp://........ ! rtph264depay ! h264parse ! nvv4l2decoder ! nvvidconv ! video/x-raw, width=(int)1920, height=(int)1080, format=(string)BGRx ! videoconvert ! appsink";
   if (!video_cap_) {
       try {
//         video_cap_ = make_unique<VideoCapture>(zstr, cv::CAP_GSTREAMER);
           video_cap_.reset(new VideoCapture(zstr, cv::CAP_GSTREAMER));
           LOGF(INFO, "\n      reset video_cap_");
       } catch (...) {
           cerr << "error in opening camera\n" << flush;
           LOGF(WARNING, "\n      error in reseting video_cap_ first time");
       }
   }
   int wnum = 10;
   while (!video_cap_->isOpened() && wnum >= 0) {
       try {
           wnum--;
           video_cap_->open(zstr, cv::CAP_GSTREAMER);
       } catch (...) {
           cerr << "error in opening camera\n" << flush;
           LOGF(WARNING, "\n      error in reseting video_cap_ in while() and send camera err msg to client");
           break;
       }
       boost::this_thread::sleep(boost::posix_time::millisec(500));
   }
   if(!video_cap_->isOpened()||!video_cap_){
       return 1;
   }
   int w = static_cast<int>(video_cap_->get(CAP_PROP_FRAME_WIDTH));
   int h = static_cast<int>(video_cap_->get(CAP_PROP_FRAME_HEIGHT));
   Size videoSize(1920, 1080);
   if (!video_writer_) {
       video_writer_.reset(new VideoWriter("..//data//testgst-zhi-1920-30.avi",
                                                VideoWriter::fourcc('M', 'J', 'P', 'G'), 30,
                                               videoSize));
       LOGF(INFO, "\n      reset video_writer_");
   }
   if (!video_writer_->isOpened()) {
       video_writer_.reset(new VideoWriter("..//data//testgst-zhi-1920-30.avi",
                                           VideoWriter::fourcc('M', 'J', 'P', 'G'), 30,
                                          videoSize));
       LOGF(WARNING, "\n      error in reseting video_writer_ first time");
   }
   if (!video_writer_ && !video_writer_->isOpened()) {
       cerr << "!!!!!!error: cant open video writer\n" << flush;
       LOGF(WARNING, "\n!!!!!!error: cant open video writer");
       return 1;
   }
   if (video_cap_ && video_cap_->isOpened() && video_writer_ && video_writer_->isOpened()) {
       cout << "------camera is working\n" << flush;
       LOGF(INFO, "\n      both video_cap_ and video_writer_ are working");

       isCameraOpenedMutex_.lock();
       isCameraOpened_ = true;
       isCameraOpenedMutex_.unlock();

       isCameraStoppedMutex_.lock();
       isCameraStopped_ = false;
       isCameraStoppedMutex_.unlock();

       isCameraReadingStoppedMutex_.lock();
       isCameraReadingStopped_ = false;
       isCameraReadingStoppedMutex_.unlock();

       isCameraWritingStoppedMutex_.lock();
       isCameraWritingStopped_ = false;
       isCameraWritingStoppedMutex_.unlock();

       thread te(&CMyServer::camera_reading_and_enque, this);
       te.detach();
       LOGF(INFO, "\n      starts camera_reading_and_enque() thread");
       thread td(&CMyServer::camera_deque_and_writing, this);
       td.detach();
       LOGF(INFO, "\n      starts camera_deque_and_writing() thread");
   }

   return 0;
}

int CMyServer::close_camera() {
   if (video_cap_ && video_cap_->isOpened() && video_writer_ && video_writer_->isOpened()) {
       isCameraStoppedMutex_.lock();
       isCameraStopped_ = true;
       isCameraStoppedMutex_.unlock();
       LOGF(INFO, "\n      wants to close camera");

       bool read_stopped = false, write_stopped = false;
       while (1) {
           isCameraReadingStoppedMutex_.lock();
           if (isCameraReadingStopped_)
               read_stopped = true;
           isCameraReadingStoppedMutex_.unlock();

           isCameraWritingStoppedMutex_.lock();
           if (isCameraWritingStopped_)
               write_stopped = true;
           isCameraWritingStoppedMutex_.unlock();

           if (write_stopped && read_stopped) {
//            if (read_stopped) {
//                video_cap_->release();
//                video_writer_->release();
               isCameraOpenedMutex_.lock();
               isCameraOpened_ = false;
               isCameraOpenedMutex_.unlock();
               LOGF(INFO, "\n      both thread are closed, free video_cap_ and video_writer_ and queue");
               cout << "------camera is closed\n" << flush;
               break;
           }
       }
       std::queue<Mat>().swap(video_frame_queue_);
       video_cap_.reset();
       video_writer_.reset();
   }
   return 0;
}

void MyCamera::camera_reading_and_enque() {
   if (!(video_cap_ && video_cap_->isOpened() && video_writer_ && video_writer_->isOpened())) {
       LOGF(WARNING, "\n!!!!!! video_cap_ and video_writer_ are not all available in camera_reading_and_enque()");
       return;
   }
   bool isend = false;
   Mat frame;

   while (1) {
       video_cap_->read(frame);
       if (!frame.empty()) {

           VideoFrameQueueMutex_.lock();
           if (video_frame_queue_.size() < maxQueueSize_)
               video_frame_queue_.push(frame);
           else {
               video_frame_queue_.pop();
               video_frame_queue_.push(frame);
               LOGF(WARNING, "\n      video_frame_queue_.size() is > maxQueueSize_");
           }
           VideoFrameQueueMutex_.unlock();
       }

       isCameraStoppedMutex_.lock();
       if (isCameraStopped_)
           isend = true;
       isCameraStoppedMutex_.unlock();

       if (isend) {
           isCameraReadingStoppedMutex_.lock();
           isCameraReadingStopped_ = true;
           isCameraReadingStoppedMutex_.unlock();
           cout << "------end camera reading\n" << flush;
           LOGF(INFO, "\n      camera_reading_and_enque() thread is stopped");
           break;
       }
   }
}

void MyCamera::camera_deque_and_writing() {
   if (!(video_cap_ && video_cap_->isOpened() && video_writer_ && video_writer_->isOpened())) {
       LOGF(WARNING, "\n!!!!!! video_cap_ and video_writer_ are not all available in camera_deque_and_writing()");
       return;
   }
   bool isend = false;
   Mat frame;
   int fram_num = 0, pic_num = 0;

   while (1) {
       VideoFrameQueueMutex_.lock();
       if (video_frame_queue_.size() > 0) {
           frame = video_frame_queue_.front();
           video_frame_queue_.pop();
       } else {
           frame.resize(0);
           LOGF(WARNING, "\n      video_frame_queue_.size() is <= 0");
       }
       VideoFrameQueueMutex_.unlock();

       if (!frame.empty()) {
           video_writer_->write(frame);

           if (fram_num % 20 == 0) {
               stringstream str;
               str << "..//test_pic//camera//test//z" << pic_num << ".png";
//                str << "..//test_pic//camera//test//z" << pic_num << ".jpg";
               //str << "..//test_pic//camera//test//d" << pic_num << ".png";
//                str << "..//test_pic//camera//test//d" << pic_num << ".jpg";
               cout << str.str() << endl;
               pic_num++;
               imwrite(str.str(), frame);
               LOGF(INFO, "\n      write one frame to %s", str.str());
           }

           fram_num++;
       }

       isCameraStoppedMutex_.lock();
       if (isCameraStopped_)
           isend = true;
       isCameraStoppedMutex_.unlock();

       if (isend) {
           fram_num = 0;
           isCameraWritingStoppedMutex_.lock();
           isCameraWritingStopped_ = true;
           isCameraWritingStoppedMutex_.unlock();
           cout << "------end camera writing\n" << flush;
           LOGF(INFO, "\n------camera_deque_and_writing() thread is stopped");
           break;
       }
   }
}

问题描述

  • 使用 open_camera() 开始保存 rtsp steam 和 jpg 图片。
  • 使用 close_camera() 将其停止。
  • 使用两个线程读取帧,解码并保存为 jpg。
  • 使用此 gstreamer 管道,使用 NX 上的 NVDEC 芯片解码视频帧。
  • 重复此过程时: 调用 open_camera(),然后在 3 秒后调用 close_camera(),
  • 我的代码使用 top 显示它占用了越来越多的内存。
  • 使用 videocapture 的函数 release() 也会有内存泄漏。
  • 发现只有在使用gstreamer进行视频采集时才会有内存泄漏,并且只有在重复过程:“reset(pipeline),and then reset()”时才会有内存泄漏。
  • 没有 gstreamer 的视频捕获没有泄漏。
  • valgrind 显示所有内存泄漏都在 boost 或 gstreamer 中。

感谢您的帮助!!! 你的帮助真的很重要!!!

【问题讨论】:

    标签: memory-leaks gstreamer-1.0


    【解决方案1】:

    你解决了这个问题吗?我也遇到了同样的问题

    【讨论】:

      猜你喜欢
      • 2015-08-12
      • 2017-08-29
      • 2014-03-01
      • 2021-07-01
      • 2013-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多