add a separate thread to read V4L2 device + change default behavior to mmap+thread

pull/33/head
Michel Promonet 9 years ago
parent afdebb1515
commit 616789a33c

@ -15,6 +15,10 @@ include_directories("${PROJECT_BINARY_DIR}/v4l2wrapper/inc")
aux_source_directory(v4l2wrapper/src SRC_FILES)
add_executable(${PROJECT_NAME} ${SRC_FILES})
#pthread
find_package (Threads)
target_link_libraries (${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# LOG4CPP
find_path(LOG4CPP_INCLUDE_DIR log4cpp/Category.hh)
if (NOT LOG4CPP_INCLUDE_DIR)

@ -52,7 +52,7 @@ This RTSP server works on Raspberry Pi using :
Usage
-----
./h264_v4l2_rtspserver [-v[v]][-m] [-P RTSP port][-P RTSP/HTTP port][-Q queueSize] [-M] [-W width] [-H height] [-F fps] [-O file] [device]
./h264_v4l2_rtspserver [-v[v]][-m] [-P RTSP port][-P RTSP/HTTP port][-Q queueSize] [-M] [-t] [-W width] [-H height] [-F fps] [-O file] [device]
-v : verbose
-vv : very verbose
-Q length: Number of frame queue (default 10)
@ -63,8 +63,10 @@ Usage
-P port : RTSP port (default 8554)
-H port : RTSP over HTTP port (default 0)
V4L2 options :
-M : V4L2 capture using memory mapped buffers (default use read interface)
-M 0/1 : V4L2 capture 0:read interface /1:memory mapped buffers (default is 1)
-t 0/1 : V4L2 capture 0:read in live555 mainloop /1:in a thread (default is 1)
-F fps : V4L2 capture framerate (default 25)
-W width : V4L2 capture width (default 640)
-H height: V4L2 capture height (default 480)
device : V4L2 capture device (default /dev/video0)

@ -64,18 +64,20 @@ class V4L2DeviceSource: public FramedSource
};
public:
static V4L2DeviceSource* createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose) ;
static V4L2DeviceSource* createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread) ;
std::string getAuxLine() { return m_auxLine; };
protected:
V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose);
V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread);
virtual ~V4L2DeviceSource();
protected:
static void* threadStub(void* clientData) { return ((V4L2DeviceSource*) clientData)->thread();};
void* thread();
static void deliverFrameStub(void* clientData) {((V4L2DeviceSource*) clientData)->deliverFrame();};
void deliverFrame();
static void incomingPacketHandlerStub(void* clientData, int mask) { ((V4L2DeviceSource*) clientData)->getNextFrame(); };
void getNextFrame();
int getNextFrame();
bool processConfigrationFrame(char * frame, int frameSize);
void processFrame(char * frame, int &frameSize, const timeval &ref);
void queueFrame(char * frame, int frameSize, const timeval &tv);
@ -95,6 +97,7 @@ class V4L2DeviceSource: public FramedSource
V4l2Capture * m_device;
unsigned int m_queueSize;
int m_verbose;
pthread_t m_thid;
};
#endif

@ -48,18 +48,18 @@ int V4L2DeviceSource::Stats::notify(int tv_sec, int framesize, int verbose)
// ---------------------------------
// V4L2 FramedSource
// ---------------------------------
V4L2DeviceSource* V4L2DeviceSource::createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose)
V4L2DeviceSource* V4L2DeviceSource::createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread)
{
V4L2DeviceSource* source = NULL;
if (device)
{
source = new V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose);
source = new V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose, useThread);
}
return source;
}
// Constructor
V4L2DeviceSource::V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose)
V4L2DeviceSource::V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread)
: FramedSource(env),
m_params(params),
m_in("in"),
@ -72,17 +72,61 @@ V4L2DeviceSource::V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters p
m_eventTriggerId = envir().taskScheduler().createEventTrigger(V4L2DeviceSource::deliverFrameStub);
if (m_device)
{
envir().taskScheduler().turnOnBackgroundReadHandling( m_device->getFd(), V4L2DeviceSource::incomingPacketHandlerStub, this);
if (useThread)
{
pthread_create(&m_thid, NULL, threadStub, this);
}
else
{
envir().taskScheduler().turnOnBackgroundReadHandling( m_device->getFd(), V4L2DeviceSource::incomingPacketHandlerStub, this);
}
}
}
// Destructor
V4L2DeviceSource::~V4L2DeviceSource()
{
{
envir().taskScheduler().deleteEventTrigger(m_eventTriggerId);
m_device->captureStop();
pthread_join(m_thid, NULL);
}
// thread mainloop
void* V4L2DeviceSource::thread()
{
int stop=0;
fd_set fdset;
FD_ZERO(&fdset);
timeval tv;
envir() << "begin thread\n";
while (!stop)
{
FD_SET(m_device->getFd(), &fdset);
tv.tv_sec=1;
tv.tv_usec=0;
int ret = select(m_device->getFd()+1, &fdset, NULL, NULL, &tv);
if (ret == 1)
{
if (FD_ISSET(m_device->getFd(), &fdset))
{
if (this->getNextFrame() <= 0)
{
envir() << "error:" << strerror(errno) << "\n";
stop=1;
}
}
}
else if (ret == -1)
{
envir() << "stop " << strerror(errno) << "\n";
stop=1;
}
}
envir() << "end thread\n";
return NULL;
}
// getting FrameSource callback
void V4L2DeviceSource::doGetNextFrame()
{
@ -149,9 +193,9 @@ void V4L2DeviceSource::deliverFrame()
FramedSource::afterGetting(this);
}
}
// FrameSource callback on read event
void V4L2DeviceSource::getNextFrame()
int V4L2DeviceSource::getNextFrame()
{
char* buffer = new char[m_device->getBufferSize()];
timeval ref;
@ -168,6 +212,7 @@ void V4L2DeviceSource::getNextFrame()
{
envir() << "V4L2DeviceSource::getNextFrame no data errno:" << errno << " " << strerror(errno) << "\n";
delete [] buffer;
handleClosure(this);
}
else
{
@ -190,6 +235,7 @@ void V4L2DeviceSource::getNextFrame()
delete [] buffer;
}
}
return frameSize;
}
bool V4L2DeviceSource::processConfigrationFrame(char * frame, int frameSize)

@ -140,7 +140,7 @@ int createOutput(const std::string & outputFile, int inputFd)
}
return outputFd;
}
// -----------------------------------------
// entry point
// -----------------------------------------
@ -162,13 +162,14 @@ int main(int argc, char** argv)
bool multicast = false;
int verbose = 0;
std::string outputFile;
bool useMmap = false;
bool useMmap = true;
std::string url = "unicast";
std::string murl = "multicast";
bool useThread = true;
// decode parameters
int c = 0;
while ((c = getopt (argc, argv, "hW:H:Q:P:F:v::O:T:m:u:M")) != -1)
while ((c = getopt (argc, argv, "hW:H:Q:P:F:v::O:T:m:u:M:t:")) != -1)
{
switch (c)
{
@ -181,13 +182,14 @@ int main(int argc, char** argv)
case 'P': rtspPort = atoi(optarg); break;
case 'T': rtspOverHTTPPort = atoi(optarg); break;
case 'F': fps = atoi(optarg); break;
case 'M': useMmap = true; break;
case 'M': useMmap = atoi(optarg); break;
case 't': useThread = atoi(optarg); break;
case 'u': url = optarg; break;
case 'h':
default:
{
std::cout << argv[0] << " [-v[v]][-m] [-P RTSP port][-P RTSP/HTTP port][-Q queueSize] [-M] [-W width] [-H height] [-F fps] [-O file] [device]" << std::endl;
std::cout << argv[0] << " [-v[v]][-m] [-P RTSP port][-P RTSP/HTTP port][-Q queueSize] [-M] [-t] [-W width] [-H height] [-F fps] [-O file] [device]" << std::endl;
std::cout << "\t -v : verbose" << std::endl;
std::cout << "\t -vv : very verbose" << std::endl;
std::cout << "\t -Q length: Number of frame queue (default "<< queueSize << ")" << std::endl;
@ -198,7 +200,8 @@ int main(int argc, char** argv)
std::cout << "\t -P port : RTSP port (default "<< rtspPort << ")" << std::endl;
std::cout << "\t -H port : RTSP over HTTP port (default "<< rtspOverHTTPPort << ")" << std::endl;
std::cout << "\t V4L2 options :" << std::endl;
std::cout << "\t -M : V4L2 capture using memory mapped buffers (default use read interface)" << std::endl;
std::cout << "\t -M 0/1 : V4L2 capture 0:read interface /1:memory mapped buffers (default is 1)" << std::endl;
std::cout << "\t -t 0/1 : V4L2 capture 0:read in live555 mainloop /1:in a thread (default is 1)" << std::endl;
std::cout << "\t -F fps : V4L2 capture framerate (default "<< fps << ")" << std::endl;
std::cout << "\t -W width : V4L2 capture width (default "<< width << ")" << std::endl;
std::cout << "\t -H height: V4L2 capture height (default "<< height << ")" << std::endl;
@ -241,7 +244,7 @@ int main(int argc, char** argv)
int outputFd = createOutput(outputFile, videoCapture->getFd());
LOG(NOTICE) << "Start V4L2 Capture..." << dev_name;
videoCapture->captureStart();
V4L2DeviceSource* videoES = V4L2DeviceSource::createNew(*env, param, videoCapture, outputFd, queueSize, verbose);
V4L2DeviceSource* videoES = V4L2DeviceSource::createNew(*env, param, videoCapture, outputFd, queueSize, verbose, useThread);
if (videoES == NULL)
{
LOG(FATAL) << "Unable to create source for device " << dev_name;

Loading…
Cancel
Save