OpenCV FFMPEG RTSP Camera Feed Errors - c++

I'm getting these errors at random times when saving frames from an rtsp camera feed. The errors happen at different times, usually after 100-200 images have been saved, and the errors themselves are not always exactly the same. They cause the images that are saved at the time of the error to be distorted either to the point of being completely grey or contain distorted pixels.
#Frame_142 - [hevc # 0c3bf800] The cu_qp_delta 29 is outside the valid range [-26, 25].
#Frame_406 - [hevc # 0b6bdb80] Could not find ref with POC 41
I've tried implementing the code in both python and c++ with the same result. Also tried saving as .png instead of .jpg. The rtsp feed works fine when using imshow to display the camera, the problem only appears to happen when trying to save the frames. From what I can gather the errors have to do with ffmpeg but google isn't much help for these types of errors.
#include <iostream>
#include <opencv2\opencv.hpp>
#include <chrono>
#include <thread>
using namespace std;
using namespace cv;
int main() {
VideoCapture cap("rtsp://admin:admin#192.168.88.97/media/video1");
if (!cap.isOpened())
return -1;
for (int i = 0; i < 500; i++)
{
Mat frame;
cap >> frame;
imwrite("C:\\Users\\Documents\\Dev\\c++\\OpenCVExample\\frames\\frame" + std::to_string(i) + ".png", frame);
cout << i << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return 0;
}

OpenCV and RTSP streams are a little tricky. This usually happens when the frames of the stream cannot be read fast enough. In that case (somewhere) a buffer receiving RTSP frames will be filled faster than is can be emptied; when the buffer is full it will be flushed and will restart filling from the most recent frame. This will corrupt the stream decoding until the next keyframe.
My suggestion is to remove the sleep even if 10ms is pretty small. Since this won't be enough (:P), the only solution is to implement a thread constantly reading frames from the cv::VideoCapture and discarding the ones grabbed while the main thread is busy saving the previous frame.
A simple implementation could be:
#include <opencv2/opencv.hpp>
#include <thread>
class VideoSourceHandler
{
public:
// Video file or IP camera
VideoSourceHandler( const std::string & source ) :
mCapture( source ),
mRun( false )
{
}
// USB camera
VideoSourceHandler( int webcamID ) :
mCapture( webcamID ),
mRun( false )
{
}
// start and stopCapture can be squashed into C'tor and D'tor if you want RTTI
void startCapture()
{
mRun = true;
mLoopThread = std::thread( &VideoSourceHandler::threadLoop, this );
}
void stopCapture()
{
mRun = false;
mLoopThread.join();
}
cv::Mat getFrame()
{
std::this_thread::yield(); // Be nice
const std::lock_guard<std::mutex> lock( mMutex );
return mCurrentFrame;
}
private:
void threadLoop()
{
while( mRun )
{
// Sleep if you want to "control" FPS
{
const std::lock_guard<std::mutex> lock( mMutex );
mCapture >> mCurrentFrame;
}
std::this_thread::yield(); // Be nice
}
}
cv::VideoCapture mCapture;
std::thread mLoopThread;
std::mutex mMutex;
bool mRun;
cv::Mat mCurrentFrame;
};
int main()
{
VideoSourceHandler vsh( 0 );
vsh.startCapture();
while( true )
{
cv::Mat frame = vsh.getFrame();
if( frame.empty() )
continue;
cv::imshow( "Test", frame );
char key = cv::waitKey( 1 );
if( key == 'q' || key == 27 )
break;
}
vsh.stopCapture();
return 0;
}

Changing the video compression to H.264 resolved the issue for me.

Related

OpenCV C++ RTSP Stream VideoCapture Error - "Operation now in progress"

I am attempting to write a short C++ script that can show me an RTSP stream from a camera on my local network. Currently my script is the following:
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
std::string window_name = "RGB Camera";
setenv("OPENCV_FFMPEG_CAPTURE_OPTIONS", "rtsp_transport;udp", 1);
const std::string rtsp_url = "rtsp://192.168.2.100:5010/video.sdp";
cv::VideoCapture cap; // Declare capture stream
cap.open(rtsp_url, cv::CAP_FFMPEG);
if (!cap.isOpened()) // Prompt an error message if no video stream is found
{
perror("Video Stream Error");
exit(EXIT_FAILURE);
}
cv::namedWindow(window_name, cv::WindowFlags::WINDOW_KEEPRATIO); // Declaring the video to show the video
cv::Mat frame; // Declaring a matrix to load the frames
while (1)
{
const bool read_success = cap.read(frame);
if (!read_success)
{
printf("End of stream\n.");
break;
}
cv::imshow(window_name, frame);
char c = (char)cv::waitKey(25); // 25 milliseconds per frame
if (c == 27) // If 'Esc' key is pressed, break the loop
{
printf("Esc key pressed, terminating loop...\n");
break;
}
}
cap.release(); // Release memory buffer
cv::destroyAllWindows(); // Close all windows
return 0;
}
However when running I am getting the following error message:
Video Stream Error: Operation now in progress
I am aware that my script is failing in the if (!cap.isOpened()) check, however I am able to open this stream in VLC and with ffplay with the rtsp url. I'm not sure why OpenCV is not working.
Also, when I remove cv::CAP_FFMPEG in the cap.open() function I get the error:
Video Stream Error: No such file or directory
Any suggestions would be greatly appreciated.

AVerMedia Capture Card C985 didn't work with C++ and openCV

I bought 'AVerMedia Capture Card (C985 LITE)' last week, and I connected video camera to this capture card's HDMI input.
When I tested with AVerMedia's RECentral software, Amcap, ffmpeg, it worked.
But, when I tested with AVerMedia's AVerCapSDKDemo, VLC, Windows Movie maker, Windows directshow, it didn't work.
Then, I try to get camera frame(in real time) by internet sample code and my c++ code (with and without using openCV). All of the code work with general USB Webcam, but didn't work with this capture card.
The result showed that every c++ code can see this capture card, but can't see the camera that connected to the card.
The conditions, that I tested and it didn't work, are below:
1st PC Spec: Intel core i5, Ram 16 GB, HDD 1 TB, DirectX 11 with windows10 64 bit
2nd PC Spec: Intel core i7, Ram 8 GB, HDD 1 TB, DirectX 11 with windows7 64 bit
IDE: visual studio 2015
Camera: GoPro and SONY Handycam, both full HD with HDMI output
About my project, I want to tracking the car on the road in real time,
therefore I decided to use C985 Capture Card that support full HD.
Does anyone have any advice?
Thank you very much.
Best regards,
--
Edit: Add Example Code
1.My code with openCV: For this code, it always show "error: frame not read from webcam\n".
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include<conio.h>
int main() {
cv::VideoCapture capWebcam(0); // declare a VideoCapture object and associate to webcam, 0 => use 1st webcam
if (capWebcam.isOpened() == false) { // check if VideoCapture object was associated to webcam successfully
std::cout << "error: capWebcam not accessed successfully\n\n"; // if not, print error message to std out
_getch(); // may have to modify this line if not using Windows
return(0); // and exit program
}
char charCheckForEscKey = 0;
while (charCheckForEscKey != 27 && capWebcam.isOpened()) { // until the Esc key is pressed or webcam connection is lost
bool blnFrameReadSuccessfully = capWebcam.read(imgOriginal); // get next frame
if (!blnFrameReadSuccessfully || imgOriginal.empty()) { // if frame not read successfully
std::cout << "error: frame not read from webcam\n"; // print error message to std out
continue; // and jump out of while loop
}
cv::namedWindow("imgOriginal", CV_WINDOW_NORMAL); // note: you can use CV_WINDOW_NORMAL which allows resizing the window
cv::imshow("imgOriginal", imgOriginal); // show windows
charCheckForEscKey = cv::waitKey(1); // delay (in ms) and get key press, if any
} // end while
return(0);
}
2.My code without openCV. (Using AForge): For this code, the image show nothing.
private void Form1_Load(object sender, EventArgs e)
{
FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
for (int i = 0; i< videoDevices.Count; i++)
{
comboBox1.Items.Add(videoDevices[i].MonikerString);
}
// create video source
}
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
Bitmap img = (Bitmap)eventArgs.Frame.Clone();
pictureBox1.Image = img;
}
private void button1_Click(object sender, EventArgs e)
{
VideoCaptureDeviceForm xx = new VideoCaptureDeviceForm();
xx.ShowDialog();
VideoCaptureDevice videoSource = new VideoCaptureDevice(xx.VideoDeviceMoniker);
//videoSource.Source = "AVerMedia HD Capture C985 Bus 2";
VideoInput input = videoSource.CrossbarVideoInput;
MessageBox.Show("" + videoSource.CheckIfCrossbarAvailable());
MessageBox.Show(" " + input.Index + " " + input.Type);
// set NewFrame event handler
videoSource.NewFrame += video_NewFrame;
foreach(var x in videoSource.AvailableCrossbarVideoInputs)
{
MessageBox.Show("AvailableCrossbarVideoInputs > " + x.Index);
}
videoSource.VideoSourceError += VideoSource_VideoSourceError;
// start the video source
videoSource.Start();
// signal to stop when you no longer need capturing
videoSource.SignalToStop();
videoSource.Start();
MessageBox.Show("AvailableCrossbarVideoInputs length :" + videoSource.AvailableCrossbarVideoInputs.Length);
input = videoSource.CrossbarVideoInput;
MessageBox.Show(" " + input.Index + " " + input.Type);
videoSource.SignalToStop();
videoSource.Start();
}
3.Code from Internet: I use the code from code project(Capture Live Video from various Video Devices) in link below. It showed "can't detect Webcam".
https://www.codeproject.com/articles/7123/capture-live-video-from-various-video-devices
Hope my code can help: (I use AVerMedia SDK + OpenCV3, use directshow api to open device then get video to mat format)
#include "stdafx.h"
#include "atlstr.h"
#include <iostream>
#include "AVerCapAPI_Pro.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <windows.h>
using namespace std;
using namespace cv;
void ErrorMsg(DWORD ErrorCode)
{
printf("ErrorCode = %d\n", ErrorCode);
if (ErrorCode == CAP_EC_SUCCESS)
{
printf("CAP_EC_SUCCESS\n");
}
if (ErrorCode == CAP_EC_INIT_DEVICE_FAILED)
{
printf("CAP_EC_INIT_DEVICE_FAILED\n");
}
if (ErrorCode == CAP_EC_DEVICE_IN_USE)
{
printf("CAP_EC_DEVICE_IN_USE\n");
}
if (ErrorCode == CAP_EC_NOT_SUPPORTED)
{
printf("CAP_EC_NOT_SUPPORTED\n");
}
if (ErrorCode == CAP_EC_INVALID_PARAM)
{
printf("CAP_EC_INVALID_PARAM\n");
}
if (ErrorCode == CAP_EC_TIMEOUT)
{
printf("CAP_EC_TIMEOUT\n");
}
if (ErrorCode == CAP_EC_NOT_ENOUGH_MEMORY)
{
printf("CAP_EC_NOT_ENOUGH_MEMORY\n");
}
if (ErrorCode == CAP_EC_UNKNOWN_ERROR)
{
printf("CAP_EC_UNKNOWN_ERROR\n");
}
if (ErrorCode == CAP_EC_ERROR_STATE)
{
printf("CAP_EC_ERROR_STATE\n");
}
if (ErrorCode == CAP_EC_HDCP_PROTECTED_CONTENT)
{
printf("CAP_EC_HDCP_PROTECTED_CONTENT\n");
}
}
BOOL WINAPI CaptureVideo(VIDEO_SAMPLE_INFO VideoInfo, BYTE *pbData, LONG lLength, __int64 tRefTime, LONG lUserData);
BOOL bGetData = FALSE;
Mat ans2;
int main(int argc, char** argv)
{
LONG lRetVal;
DWORD dwDeviceNum;
DWORD dwDeviceIndex = 0;
HANDLE hAverCapturedevice[10];
//Device Control
//1. Get Device Number
lRetVal = AVerGetDeviceNum(&dwDeviceNum);
if (lRetVal != CAP_EC_SUCCESS) {
printf("\nAVerGetDeviceNum Fail");
ErrorMsg(lRetVal);
system("pause");
}
if (dwDeviceNum == 0) {
printf("NO device found\n");
system("pause");
}
else {
printf("Device Number = %d\n", dwDeviceNum);
}
//2. Create device representative object handle
for (DWORD dwDeviceIndex = 0; dwDeviceIndex < dwDeviceNum; dwDeviceIndex++) {
lRetVal = AVerCreateCaptureObjectEx(dwDeviceIndex, DEVICETYPE_ALL, NULL, &hAverCapturedevice[dwDeviceIndex]);
if (lRetVal != CAP_EC_SUCCESS) {
printf("\nAVerCreateCaptureObjectEx Fail\n");
ErrorMsg(lRetVal);
system("pause");
}
else
printf("\nAVerCreateCaptureObjectEx Success\n");
}
//3. Start Streaming//
//3.1 set video source
//lRetVal = AVerSetVideoSource(hAverCapturedevice[0], 3);
lRetVal = AVerSetVideoSource(hAverCapturedevice[0], 3);
//3.2 set Video Resolution & FrameRate
VIDEO_RESOLUTION VideoResolution = { 0 };
INPUT_VIDEO_INFO InputVideoInfo;
ZeroMemory(&InputVideoInfo, sizeof(InputVideoInfo));
InputVideoInfo.dwVersion = 2;
Sleep(500);
lRetVal = AVerGetVideoInfo(hAverCapturedevice[0], &InputVideoInfo);
VideoResolution.dwVersion = 1;
VideoResolution.dwVideoResolution = VIDEORESOLUTION_1280X720;
lRetVal = AVerSetVideoResolutionEx(hAverCapturedevice[0], &VideoResolution);
lRetVal = AVerSetVideoInputFrameRate(hAverCapturedevice[0], 6000);
//3.3 Start Streaming
lRetVal = AVerStartStreaming(hAverCapturedevice[0]);
if (lRetVal != CAP_EC_SUCCESS) {
printf("\AVerStartStreaming Fail\n");
ErrorMsg(lRetVal);
//system("pause");
}
else
{
printf("\AVerStartStreaming Success\n");
//system("pause");
}
//4. Capture Single Image
#if 0
CAPTURE_IMAGE_INFO m_CaptureImageInfo = { 0 };
char text[] = "E:\Lena.bmp";
wchar_t wtext[20];
#define _CRT_SECURE_NO_WARNINGS
#pragma warning( disable : 4996 )
mbstowcs(wtext, text, strlen(text) + 1);//Plus null
LPWSTR m_strSavePath = wtext;
CAPTURE_SINGLE_IMAGE_INFO pCaptureSingleImageInfo = { 0 };
pCaptureSingleImageInfo.dwVersion = 1;
pCaptureSingleImageInfo.dwImageType = 2;
pCaptureSingleImageInfo.bOverlayMix = FALSE;
pCaptureSingleImageInfo.lpFileName = m_strSavePath;
//pCaptureSingleImageInfo.rcCapRect = 0;
lRetVal = AVerCaptureSingleImage(hAverCapturedevice[0], &pCaptureSingleImageInfo);
printf("\AVerCaptureSingleImage\n");
ErrorMsg(lRetVal);
#endif
#if 1
//video capture
VIDEO_CAPTURE_INFO VideoCaptureInfo;
ZeroMemory(&VideoCaptureInfo, sizeof(VIDEO_CAPTURE_INFO));
VideoCaptureInfo.bOverlayMix = FALSE;
VideoCaptureInfo.dwCaptureType = CT_SEQUENCE_FRAME;
VideoCaptureInfo.dwSaveType = ST_CALLBACK_RGB24;
VideoCaptureInfo.lpCallback = CaptureVideo;
VideoCaptureInfo.lCallbackUserData = NULL;
lRetVal = AVerCaptureVideoSequenceStart(hAverCapturedevice[0], VideoCaptureInfo);
if (FAILED(lRetVal))
{
return lRetVal;
}
//system("pause");// hange up
#endif
int i;
scanf_s("%d", &i, 4); //must input any number in console !!
//5. Stop Streaming
lRetVal = AVerCaptureVideoSequenceStop(hAverCapturedevice[0]);
lRetVal = AVerStopStreaming(hAverCapturedevice[0]);
//printf("\AVerStopStreaming Success\n");
ErrorMsg(lRetVal);
return 0;
}
BOOL WINAPI CaptureVideo(VIDEO_SAMPLE_INFO VideoInfo, BYTE *pbData, LONG lLength, __int64 tRefTime, LONG lUserData)
{
if (!bGetData)
{
ans2 = Mat(VideoInfo.dwHeight, VideoInfo.dwWidth, CV_8UC3, (uchar*)pbData).clone();//single capture image
//ans2 = Mat(VideoInfo.dwHeight, VideoInfo.dwWidth, CV_8UC3, (uchar*)pbData); //sequence capture image
bGetData = TRUE;
}
imshow("ans2", ans2);
waitKey(1);
return TRUE;
}
Now, it's solved by formatted computer and installed Windows 10 without updates.
And I wrote program to call GraphEdit that set up the following filters.
GraphEdit's filter
Everything seemed to work fine until I updated windows by mistake.

A bug in CV::VideoCapture::open()?

I am using CV::VideoCapture to capture frames from an IP camera. It works most of time, however, sometimes it reports the error:
[mjpeg # 0x233aea0] overread 8
And when this error occurred, my program just stuck there. This might explain why. But how can I solve it in C++ code? Can OpenCV handle this error without terminate the program?
p.s. I found that if I didn't call CV::VideoCapture::read() immediately, but wait for a while, like 60 seconds, after CV::VideoCapture::open(), this error occurred everytime! Is it a bug of OpenCV?
#include <unistd.h>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
int main(int argc, char* argv[]) {
// argv[1] is a valid url, like "http://xxxx/mjpg/video.mjpg"
cv::VideoCapture cap(argv[1]);
if (!cap.isOpened()) {
std::cout << "Cannot Open Camera!" << std::endl;
return -1;
}
// The error occures if I pause for a while.
// But it is okay when I capture frames from video files intead of IP camera.
sleep(60);
while (static_cast<char>(cv::waitKey(1)) != 'q') {
cv::Mat frame;
cap >> frame;
if (frame.empty()) break;
cv::imshow("frame", frame);
}
}
I can't explain why but using the address http://xxxx/axis-cgi/mjpg/video.cgi instead of http://xxxx/mjpg/video.mjpg solved it! Can anyone provide some nice explanation here, or some links? Thanks!

updating cv::capturevideo frame in a boost::thread safely

I want to render via openGL 2camera in the same time. I want to refresh each frame as soon as possible. To update those frame I am using a thread in an infinite loop.
My actual problem is that my program crash if I put the resolution of those camera to high.
With 160:120 there's no problem. But if i put the max resolution (1920:1080) there's just 5 or 6 update of the image before crashing.
note: the number of update is not always the same before crashing
I suppose that If the resolution is low enough, frame_L and frame_R are changed quick enough that there's no colision beetween the main loop and the thread.
So I suppose that my mutex isnt doing what it should. How should I do?
(I'm not an expert in thread and variable safety)
My code:
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <opencv2/opencv.hpp>
boost::mutex m; //for an other thread
boost::mutex n;
cv::VideoCapture capture_L(0);
cv::VideoCapture capture_R(1);
cv::Mat frame_L;
cv::Mat frame_R;
void MyThreadFunction()
{
while (1)
{
{
boost::mutex::scoped_lock lk(n);
if (capture_L.grab()){
capture_L.retrieve(frame_L);
cv::transpose(frame_L, frame_L);
}
if (capture_R.grab()){
capture_R.retrieve(frame_R);
cv::transpose(frame_R, frame_R);
}
}
}
}
int main()
{
capture_L.set(CV_CAP_PROP_FRAME_WIDTH, 160);
capture_L.set(CV_CAP_PROP_FRAME_HEIGHT, 120);
capture_R.set(CV_CAP_PROP_FRAME_WIDTH, 160);
capture_R.set(CV_CAP_PROP_FRAME_HEIGHT, 120);
boost::thread thrd(&MyThreadFunction);
while(1)
{
[ use frame_L and frame_R ]
}
}
This is the code that I use for my threaded camera grab. Its part of a camera Object (eg; Each camera has it's own object and own thread for the capturing.
void Camera::setCapture(cv::VideoCapture cap)
{
pthread_mutex_lock(&latestFrameMutex);
videoCapture = cap;
videoCapture.read(latestFrame);
pthread_mutex_unlock(&latestFrameMutex);
int iret = pthread_create(&cameraGrabThread,NULL,&Camera::exec,this);
}
void *Camera::exec(void* thr)
{
reinterpret_cast<Camera *> (thr)->grabFrame();
}
This ensures that a new thread is started when a capture is set for that camera. The following code is run by the exec part of the thread to actually grab the frame.
void *Camera::grabFrame()
{
while(videoCapture.isOpened())
{
pthread_mutex_lock(&latestFrameMutex);
if(!videoCapture.read(latestFrame))
std::cout << "Unable to read frame" << std::endl;
pthread_mutex_unlock(&latestFrameMutex);
usleep(8000); // Sleep 8ms
}
}
And finally, the camera needs to be able to return the latest frame;
cv::Mat Camera::getLatestFrame()
{
while (getMilisecSinceLastCapture() < 35) //Enforce min time of 35 ms between frame requests.
{
usleep(5000);
}
pthread_mutex_lock(&latestFrameMutex);
cv::Mat result = latestFrame.clone();
pthread_mutex_unlock(&latestFrameMutex);
return result.clone();
}
Changing the size can be done by using
void Camera::setImageSize(const cv::Size& size)
{
pthread_mutex_lock(&latestFrameMutex);
videoCapture.set(CV_CAP_PROP_FRAME_HEIGHT, size.height);
videoCapture.set(CV_CAP_PROP_FRAME_WIDTH, size.width);
pthread_mutex_unlock(&latestFrameMutex);
}

How to make linux-system waiting on an OpenCV program?

I have a very simple program on OpenCV:
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace std;
void showVideo(CvCapture *video)
{
int width = (int) cvGetCaptureProperty(video, CV_CAP_PROP_FRAME_WIDTH);
int height = (int) cvGetCaptureProperty(video, CV_CAP_PROP_FRAME_HEIGHT);
//int fps = (int) cvGetCaptureProperty(video, CV_CAP_PROP_FPS);
IplImage* frame = cvCreateImage(cvSize(width, height), 8, 1);
cvNamedWindow("Showing Video:", 0);
while (true)
{
frame = cvQueryFrame(video);
cvShowImage("Showing Video:", frame);
cvWaitKey(10);
}
//cvDestroyWindow("Showing Video:");
//cvReleaseImage(&frame);
}
int main()
{
CvCapture *video = cvCaptureFromCAM(CV_CAP_ANY);
showVideo(video);
return 0;
}
I want to have a char ch; and something like this while(ch != 'q') then it still plays the video. There is some ways such as kbhit() or getch() but they are not standard and I want something that whenever the 'q' key is pressed, then the showing the video will finish, otherwise video showing will be still running.
How can I do this job?
cvWaitKey() returns 0 if no key was pressed in the allotted time or the key code if a key is pressed. Change your call to cvWaitKey() to test the return value like this:
chr = cvWaitKey(10);
if (chr == 'q')
break;
Create an additional thread, where the new one waits for stdin data. If it receives the proper content, then set a flag which the other thread checks. The most obvious means to check it is to replace
while (true)
with
while (!done)
where done is initialized to false, and set to true by the keyboard thread.