C++ suddenly blocks on reading a frame from IP camera using VideoCapture - c++

I'm using OpenCV 3. Grabbing a frame using VideoCapture with an IP Camera is blocking if the camera goes disconnected from the network or there is an issue with a frame.
I first check if videoCapture.isOpened(). If it is, I tried these methods but nothing seems to work:
1) grabber >> frame
if(grabber.isOpened()) {
grabber >> frame;
// DO SOMETHING WITH FRAME
}
2) read
if(grabber.isOpened()) {
if(!grabber.grab()){
cout << "failed to grab from camera" << endl;
} else {
if (grabber.retrieve(frame,0) ){
// DO SOMETHING WITH FRAME
} else {
// SHOW ERROR
}
}
}
3) grab/retrieve
if(grabber.isOpened()) {
if ( !grabber.read(frame) ) {
cout << "Unable to retrieve frame from video stream." << endl;
}
else {
// DO SOMETHING WITH FRAME
}
}
The video stream gets stuck at some point grabbing a frame with all of the previous options, each one blocks but doesn't exit or returns any error.
Do you know if there is a way to handle or solve this? Maybe some validations, try/catch or timer?

this issue is solved by this merge but unfortunetely opencv_ffmpeg.dll is not released yet.
you can find here updated opencv_ffmpeg.dll and test.

Related

Opencv writing and reading from a buffer

I have two tasks (Threads) each task runs on a different processor(core), the first capture an image repeatedly using OpenCV videocapture().
I only used these two lines for the capture :
cv::Mat frame;
capture.read(frame);
Now I want to display the captured image using the second task. After executing the imshow function within the second task's code :
cv::imshow("Display window", frame);
I got the following output error :
OpenCV Error: Assertion failed (size.width>0 && size.height>0) in imshow, file /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/highgui/src/window.cpp, line 304
terminate called after throwing an instance of 'cv::Exception'
what(): /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/highgui/src/window.cpp:304: error: (-215) size.width>0 && size.height>0 in function imshow
So, how can I avoid this error?
The complete code is hosted at Github
cv::VideoCapture::read() returns bool indicating if the read was successful or not.
You are passing an empty frame to cv::imshow(). Try checking if the read was successful before trying to show it.
cv::Mat frame;
if(capture.read(frame))
{
cv::imshow(frame);
}
EDIT
OP posted a link to the code. In his program frame is declared as a global variable. In line 120 capture.read(frame) writing into the frame and in line 140 imshow(frame) reads from the frame without using a mutex - that's a data race. Correct code should be along the lines of:
#include <mutex>
#include <opencv2/opencv.hpp>
std::mutex mutex;
cv::Mat frame;
{
mutex.lock();
capture.read(frame);
mutex.unlock();
}
{
mutex.lock();
cv::imshow(frame);
mutex.unlock();
}
The problem with your code is that there is a data race.. Imagine the display thread goes first lock the frame & try to display it before it is read so as you can see the problem
If you want a synchronized solution you can use the pthread condition & wait till an image is read to signal your display function otherwise you are gonna have an active wait!!
// in the declaration part
// Declaration of thread condition variable
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
//in the display function
ptask DisplyingImageTask()
{
int task_job = 0;
while (1)
{
std::cout << "The job " << task_job << " of Task T" << ptask_get_index()
<< " is running on core " << sched_getcpu() << " at time : "
<< ptask_gettime(MILLI) << std::endl;
cv::namedWindow("Display window", cv::WINDOW_AUTOSIZE);
pthread_mutex_lock(&frame_rw);
//wait for the read function to send a signal
pthread_cond_wait(&cond1, &frame_rw);
cv::imshow("Display window", frame);
cv::waitKey(1);
pthread_mutex_unlock(&frame_rw);
ptask_wait_for_period();
task_job++;
}
}
// in the Read function
ptask CapturingImageTask()
{
int task_job = 0;
while (1)
{
std::cout << "The job " << task_job << " of Task T" << ptask_get_index()
<< " is running on core " << sched_getcpu() << " at time : "
<< ptask_gettime(MILLI) << std::endl;
pthread_mutex_lock(&frame_rw);
capture.read(frame);
//after capturing the frame signal the display function & everything should be synchronize as you want
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&frame_rw);
ptask_wait_for_period();
task_job++;
}
}
int main()
{
VideoCapture cap;
while(1){
Mat frame;
cap >> frame;
imshow("frame",frame);
waitKey();}
}
You can try this. İf you write waitKey(); Code want to press any key for get frame and show frame.
As others have mentioned try using a mutex.
You can also have a condition on the cv::Mat before trying to display it:
if (frame.data())
imshow("window", frame);
This will check that the frame to be displayed has data and thus avoiding the error.
Again this condition is only to avoid the imshow error and not to solve the original problem which, as mentioned in other answers, is a data race between the 2 threads.

SDL_Mixer when play again, starts from random place for a while then from the beginning

Hi I'm trying to trigger multiple music playing here, here are some code.
Mix_Music *mix_list[MUSIC_COUNT] ;
//init music with SDL
int result = 0;
int flags = MIX_INIT_MP3;
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
printf("Failed to init SDL\n");
exit(1);
}
if (flags != (result = Mix_Init(flags))) {
printf("Could not initialize mixer (result: %d).\n", result);
printf("Mix_Init: %s\n", Mix_GetError());
exit(1);
}
//load music
Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 640);
for (int i = 0 ; i < musiclist.size() ; ++i){
mix_list[i] = Mix_LoadMUS(musiclist[i].c_str());
}
Then in a loop,
for (; ;){
//trigger from here, some code detect if there's a new music need to be played
//play sound here
if (!Mix_PlayingMusic()){
//if not playing just start fresh play
std::cout << "Start Play " << musiclist[markerIds[0]] << std::endl ;
Mix_FadeInMusic(mix_list[markerIds[0]],1,1000) ;
}
else{
//only if change to next music
if (lastDetected != markerIds[0]){
std::cout << "Fading out current" << std::endl ;
//first need to fade out current
while(!Mix_FadeOutMusic(2000) && Mix_PlayingMusic()) {
// wait for any fades to complete
SDL_Delay(100);
}
Mix_HaltMusic() ;
//then start the one
//problem happens here
//there will always be several seconds it plays from the middle somewhere, then plays from the beginning.
Mix_FadeInMusic(mix_list[markerIds[0]],1,4000) ;
}
}
}
My problem is listed in the code, the issue is when play the music that was played before, no matter Mix_FadeInMusic () or the Mix_PlayMusic() always plays the music from random place first for several seconds, then from the beginning. But all I need, is just smooth play through.
OS: Ubuntu 16.04
SDL:2.0.4
Mixer:2.0.1
I figured this myself, it is actually the mp3 issue. The SDL library bundled with Ubuntu 16.04 has little issue on playing some mp3 files. So after I convert file to OGG and use int flags = MIX_INIT_OGG; the problem just gone.

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