1 | initial version |
Not sure if this is possible using the OpenCV VideoCapture. I too needed to stream RTSP feeds, so I made use of libvlc for these. Here's some info:
http://study.marearts.com/2015/09/opencv-rtsp-connection-using-vlc-library.html
Good luck.
2 | No.2 Revision |
Not sure if this is possible using the OpenCV VideoCapture. I too needed to stream RTSP feeds, so I made use of libvlc for these. Here's some info:
http://study.marearts.com/2015/09/opencv-rtsp-connection-using-vlc-library.html
Good luck.Here is the class that I created to allow for a similar interface to what you get with VideoCapture:
Header:
#ifndef VLCCAP_H
#define VLCCAP_H
#include <opencv2/opencv.hpp>
#include <vlc/vlc.h>
#include <mutex>
#include <atomic>
using namespace std;
using namespace cv;
class VlcCap {
public:
VlcCap();
~VlcCap();
void open(const char* url);
void release();
bool isOpened();
bool read(Mat& outFrame);
private:
unsigned format(char* chroma, unsigned* width, unsigned* height, unsigned* pitches, unsigned* lines);
void* lock(void** p_pixels);
void unlock(void* id, void* const* p_pixels);
static unsigned format_helper(void** data, char* chroma, unsigned* width, unsigned* height, unsigned* pitches, unsigned* lines);
static void* lock_helper(void* data, void** p_pixels);
static void unlock_helper(void* data, void* id, void* const* p_pixels);
private:
mutex m_mutex;
string m_url;
Mat m_frame;
bool m_isOpen;
atomic<bool> m_hasFrame;
libvlc_instance_t* m_vlcInstance;
libvlc_media_player_t* m_mp;
};
#endif //VLCCAP_H
Implementation:
#include "VlcCap.h"
#include <thread>
#include <cstring>
VlcCap::VlcCap()
: m_isOpen(false)
, m_hasFrame(false)
, m_vlcInstance(NULL)
, m_mp(NULL)
{
}
VlcCap::~VlcCap() {
try {
release();
} catch(...) {
// TODO log
}
}
void VlcCap::open(const char* url) {
release();
m_url = url;
const char* args[] = {"-I", "dummy", "--ignore-config"};
m_vlcInstance = libvlc_new(3, args);
libvlc_media_t* media = libvlc_media_new_location(m_vlcInstance, m_url.c_str());
m_mp = libvlc_media_player_new_from_media(media);
libvlc_media_release(media);
libvlc_video_set_callbacks(m_mp, lock_helper, unlock_helper, NULL, this);
libvlc_video_set_format_callbacks(m_mp, format_helper, NULL);
int resp = libvlc_media_player_play(m_mp);
if(resp == 0) {
m_isOpen = true;
} else {
release();
}
}
void VlcCap::release() {
if(m_vlcInstance) {
libvlc_media_player_stop(m_mp);
libvlc_release(m_vlcInstance);
libvlc_media_player_release(m_mp);
m_vlcInstance = NULL;
m_mp = NULL;
}
m_hasFrame = false;
m_isOpen = false;
}
bool VlcCap::isOpened() {
if(!m_isOpen)
return false;
libvlc_state_t state = libvlc_media_player_get_state(m_mp);
return (state != libvlc_Paused && state != libvlc_Stopped && state != libvlc_Ended && state != libvlc_Error);
}
bool VlcCap::read(Mat& outFrame) {
while(!m_hasFrame) {
this_thread::sleep_for(chrono::milliseconds(100));
if(!isOpened())
return false; // connection closed
}
{
lock_guard<mutex> guard(m_mutex);
outFrame = m_frame.clone();
m_hasFrame = false;
}
return true;
}
unsigned VlcCap::format(char* chroma, unsigned* width, unsigned* height, unsigned* pitches, unsigned* lines) {
// TODO: Allow overriding of native size?
lock_guard<mutex> guard(m_mutex);
//cout << "VlcCap::format - " << chroma << " - " << *width<<"/"<<*height << endl;
memcpy(chroma, "RV24", 4);
pitches[0] = (*width) * 24/8;
lines[0] = *height;
m_frame.create(*height, *width, CV_8UC3);
return 1;
}
void* VlcCap::lock(void** p_pixels) {
//cout << "VlcCap::lock" << endl;
m_mutex.lock();
*p_pixels = (unsigned char*)m_frame.data;
return NULL;
}
void VlcCap::unlock(void* id, void* const* p_pixels) {
m_hasFrame = true;
m_mutex.unlock();
}
unsigned VlcCap::format_helper(void** data, char* chroma, unsigned* width, unsigned* height, unsigned* pitches, unsigned* lines) {
return ((VlcCap*)(*data))->format(chroma, width, height, pitches, lines);
}
void* VlcCap::lock_helper(void* data, void** p_pixels) {
return ((VlcCap*)data)->lock(p_pixels);
}
void VlcCap::unlock_helper(void* data, void* id, void* const* p_pixels) {
((VlcCap*)data)->unlock(id, p_pixels);
}