A bug in CV::VideoCapture::open()? - c++

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!

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.

OpenCV FFMPEG RTSP Camera Feed Errors

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.

Video Capture : Frame always empty - opencv

I am working with openCV Version 2.4.9, and on Mac OSX.
I have written this code for loading and displaying a video on my desktop. But it never seems to work. I always get the output as "frame empty". Thus it does not complain about reading the video using VideoCapture.It is NOT able to capture any frames, and thus 'frame' is always EMPTY. Any idea what the problem might be?
Note: I have tried both ways to capture a frame - commented as try 1 and try2.
int main(int argc, const char * argv[])
{
Mat frame;
VideoCapture capture_ir("/Users/shreyatandon/Desktop/resize_ir.avi");
if ( !capture_ir.isOpened() ) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
for (;;){
// capture_ir.read(frame); //try1
capture_ir>>frame; //try2
if(frame.empty()){
std::cerr<<"frame is empty"<<std::endl;
break;
}
imshow("", frame);
waitKey(10);
break;
}
return 0;
}
Just made it work.
Mat current_frame;
VideoCapture video("video.avi");
while(true)
{
video.read(current_frame);
imshow("Image",current_frame);
}
If you keep having problems using avi format have a look at your links to the ffmpeg libraries and it dependencies. I tried to install it from scratch using homebrew and it is working without problems. Cheers

Unable to read frames from VideoCapture from secondary webcam with OpenCV

Code:
Simple example that works perfectly with primary webcam (device 0):
VideoCapture cap(0);
if (!cap.isOpened()) {
std::cout << "Unable to read stream from specified device." << std::endl;
return;
}
while (true)
{
// retrieve the frame:
Mat frame;
if (!cap.read(frame)) {
std::cout << "Unable to retrieve frame from video stream." << std::endl;
break;
}
// display it:
imshow("MyVideo", frame);
// check if Esc has been pressed:
if (waitKey(1) == 27) {
break;
}
// else continue:
}
cap.release();
Problem:
I have a second webcam, which I'd like to use. However, when I replace VideoCapture cap(0); with VideoCapture cap(1);, the stream is being opened correctly (or at least cap.isOpened() returns true) but the cap.read(frame) call returns false and I'm unable to find out why.
What I've tried:
I've been trying to play with VideoCapture's settings a bit like calling:
cap.set(CV_CAP_PROP_FORMAT, CV_8UC3);
and random stuff like that, but nothing seems to help.
I've also found this: VideoCapture::read fails on uncompressed video (Bug #2281), which seems to be solved on version 2.4.7.. but I've just updated OpenCV to 2.4.8 and it still doesn't work...
I've tried to use the AMCap to capture the raw video from this camera, save it as aaa.avi file and constructed VideoCapture by calling:
VideoCapture cap("aaa.avi");
and it works (while being read from file)... what I need is real-time processing with live view though.
HW, OS, SW details:
My HW: HP ProBook 4510s with built-in webcam that always works perfectly
+ external webcam CANYON CNR-FWCII3, refered by OS as "USB Video Device" (the troublesome one)
OS, SW: Windows 8.1 Pro x86, Visual Studio 2012 Pro, OpenCV 2.4.8 ~ using vc11 build
Questions:
Am I missing something?
Is there anything else that I could do?
Is there at least any way how to retrieve some additional information about what the problem might actually be?
... OpenCV's API seems quite poor in this case and everywhere where people seemed to be facing the similar issue, there was someone claiming it to be "OS / HW depnendant" as an excuse.
Any help will be appreciated.
After some time I've found out that it is always only the first call of read that fails and skipping the first frame started to work fine although the true reason of this behavior remained unknown.
Later James Barnett (see comments above) has pointed out that the reason might be that it takes a while till the camera gets ready for capturing and my current solution looks the following way (C++11's sleep):
#include <chrono>
#include <thread>
...
VideoCapture cap(1);
// give camera some extra time to get ready:
std::this_thread::sleep_for(std::chrono::milliseconds(200));
if (!cap.isOpened()) {
std::cout << "Unable to read stream from specified device." << std::endl;
return;
}
while (true)
{
// retrieve the frame:
Mat frame;
if (!cap.read(frame)) {
std::cout << "Unable to retrieve frame from video stream." << std::endl;
continue;
}
// display it:
imshow("LiveStream", frame);
// stop if Esc has been pressed:
if (waitKey(1) == 27) {
break;
}
}
cap.release();
Hopefully some future visitors will find it helpful :)
easiest way to solve is to read once before checking for success. This code snippet works for me.
//
cap.read(frame);
if(!cap.read(frame)){
//
...
the fix in my case is disconect any camera conected to a sub hub! even if is only one! use your pc's usb port directly.

OpenCV VideoCapture returns an empty frame only in first call to glutDisplayFunc callback

I have been trying to work with OpenCV and freeglut.
The program involves capturing an image from a WebCam, processing the image with OpenCV, and drawing 3D objects with OpenGL according to the processed image.
It works perfectly fine when I only use OpenCV routines.
The problem arises when the main loop becomes controlled by GLUT. When I try to grab a frame from within a callback I registered with glutDisplayFunc() the image returned is empty.
Strangely, however, when I grab a frame from a callback I registered with glutIdleFunc() it successfully returns a frame.
And after doodling around I figured out that somehow a frame cannot be captured in the first call of display() and works after the second call.
Currently my code is querying a frame inside the idle() function.
Regarding such background I have several questions.
Why does this happen? Is it because the program stalls inside display() before VideoCapture gains full access to the webcam? Or is this purely a hardware problem?
Is this safe? I'm perfectly fine about grabbing a frame from within idle(), but is this method safe to use?
If not so, is there a workaround? If this approach is not safe may somebody please notify me with another way of dealing with this issue?
The program is built on OS X Version 10.9.1 and libraries being use are
OpenCV 2.4.7.0
freeglut 2.0.1
Here is the simplified version of my code:
#include <opencv2/opencv.hpp>
#include <GL/freeglut.h>
#include <iostream>
cv::VideoCapture capture;
cv::Mat render;
void display()
{
std::cerr << "Grabbing frame in display()" << std::endl;
capture >> render; // This does not work on first call
if(render.empty()) {
std::cerr << "Error: Grabbing empty frame in display()" << std::endl;
}
}
void idle()
{
std::cerr << "Grabbing frame in idle()" << std::endl;
capture >> render; // This always works
if(render.empty()) {
std::cerr << "Error: Grabbing empty frame in idle()" << std::endl;
}
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(640, 480);
int debug_window = glutCreateWindow("Debug");
glutDisplayFunc(display);
glutIdleFunc(idle);
capture.open(0);
if(!capture.isOpened()) {
std::cerr << "Error: Failed to open camera" << std::endl;
exit(1);
}
glutMainLoop();
return 0;
}
known problem.
some sloppy webcam drivers return an empty 1st frame, warmup or something.
just try to capture 1 frame, before you go into the idle loop