Michel Promonet 10 years ago
commit 4a767df872

@ -8,12 +8,36 @@ set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_C_FLAGS "-Wall") set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "-Wall") set(CMAKE_CXX_FLAGS "-Wall")
add_custom_target(git_update
COMMAND git submodule init
COMMAND git submodule update
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)
# define executable to build # define executable to build
include_directories("${PROJECT_BINARY_DIR}/inc") include_directories("${PROJECT_BINARY_DIR}/inc")
aux_source_directory(src SRC_FILES) aux_source_directory(src SRC_FILES)
include_directories("${PROJECT_BINARY_DIR}/v4l2wrapper/inc")
aux_source_directory(v4l2wrapper/src SRC_FILES)
add_executable(${PROJECT_NAME} ${SRC_FILES}) add_executable(${PROJECT_NAME} ${SRC_FILES})
add_dependencies(${PROJECT_NAME} git_update)
# v4l2wrapper
include_directories("${PROJECT_BINARY_DIR}/v4l2wrapper/inc")
set_source_files_properties(${PROJECT_BINARY_DIR}/v4l2wrapper/src/V4l2Capture.cpp PROPERTIES GENERATED 1)
set_source_files_properties(${PROJECT_BINARY_DIR}/v4l2wrapper/src/V4l2MmapCapture.cpp PROPERTIES GENERATED 1)
set_source_files_properties(${PROJECT_BINARY_DIR}/v4l2wrapper/src/V4l2ReadCapture.cpp PROPERTIES GENERATED 1)
add_library(v4l2wrapper
STATIC
v4l2wrapper/src/V4l2Capture.cpp
v4l2wrapper/src/V4l2MmapCapture.cpp
v4l2wrapper/src/V4l2ReadCapture.cpp
)
target_link_libraries(${PROJECT_NAME} v4l2wrapper)
add_dependencies(v4l2wrapper git_update)
#pthread
find_package (Threads)
target_link_libraries (${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# LOG4CPP # LOG4CPP
find_path(LOG4CPP_INCLUDE_DIR log4cpp/Category.hh) find_path(LOG4CPP_INCLUDE_DIR log4cpp/Category.hh)

@ -27,8 +27,6 @@ Dependencies
Build Build
------- -------
git submodule init
git submodule update
cmake . cmake .
make make
@ -52,7 +50,7 @@ This RTSP server works on Raspberry Pi using :
Usage 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 -v : verbose
-vv : very verbose -vv : very verbose
-Q length: Number of frame queue (default 10) -Q length: Number of frame queue (default 10)
@ -63,8 +61,10 @@ Usage
-P port : RTSP port (default 8554) -P port : RTSP port (default 8554)
-H port : RTSP over HTTP port (default 0) -H port : RTSP over HTTP port (default 0)
V4L2 options : 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) -F fps : V4L2 capture framerate (default 25)
-W width : V4L2 capture width (default 640) -W width : V4L2 capture width (default 640)
-H height: V4L2 capture height (default 480) -H height: V4L2 capture height (default 480)
device : V4L2 capture device (default /dev/video0) device : V4L2 capture device (default /dev/video0)

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

@ -48,18 +48,18 @@ int V4L2DeviceSource::Stats::notify(int tv_sec, int framesize, int verbose)
// --------------------------------- // ---------------------------------
// V4L2 FramedSource // 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; V4L2DeviceSource* source = NULL;
if (device) if (device)
{ {
source = new V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose); source = new V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose, useThread);
} }
return source; return source;
} }
// Constructor // 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), : FramedSource(env),
m_params(params), m_params(params),
m_in("in"), m_in("in"),
@ -72,17 +72,61 @@ V4L2DeviceSource::V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters p
m_eventTriggerId = envir().taskScheduler().createEventTrigger(V4L2DeviceSource::deliverFrameStub); m_eventTriggerId = envir().taskScheduler().createEventTrigger(V4L2DeviceSource::deliverFrameStub);
if (m_device) 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 // Destructor
V4L2DeviceSource::~V4L2DeviceSource() V4L2DeviceSource::~V4L2DeviceSource()
{ {
envir().taskScheduler().deleteEventTrigger(m_eventTriggerId); envir().taskScheduler().deleteEventTrigger(m_eventTriggerId);
m_device->captureStop(); 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 // getting FrameSource callback
void V4L2DeviceSource::doGetNextFrame() void V4L2DeviceSource::doGetNextFrame()
{ {
@ -149,9 +193,9 @@ void V4L2DeviceSource::deliverFrame()
FramedSource::afterGetting(this); FramedSource::afterGetting(this);
} }
} }
// FrameSource callback on read event // FrameSource callback on read event
void V4L2DeviceSource::getNextFrame() int V4L2DeviceSource::getNextFrame()
{ {
char* buffer = new char[m_device->getBufferSize()]; char* buffer = new char[m_device->getBufferSize()];
timeval ref; timeval ref;
@ -168,6 +212,7 @@ void V4L2DeviceSource::getNextFrame()
{ {
envir() << "V4L2DeviceSource::getNextFrame no data errno:" << errno << " " << strerror(errno) << "\n"; envir() << "V4L2DeviceSource::getNextFrame no data errno:" << errno << " " << strerror(errno) << "\n";
delete [] buffer; delete [] buffer;
handleClosure(this);
} }
else else
{ {
@ -190,6 +235,7 @@ void V4L2DeviceSource::getNextFrame()
delete [] buffer; delete [] buffer;
} }
} }
return frameSize;
} }
bool V4L2DeviceSource::processConfigrationFrame(char * frame, int frameSize) bool V4L2DeviceSource::processConfigrationFrame(char * frame, int frameSize)

@ -140,7 +140,7 @@ int createOutput(const std::string & outputFile, int inputFd)
} }
return outputFd; return outputFd;
} }
// ----------------------------------------- // -----------------------------------------
// entry point // entry point
// ----------------------------------------- // -----------------------------------------
@ -162,13 +162,14 @@ int main(int argc, char** argv)
bool multicast = false; bool multicast = false;
int verbose = 0; int verbose = 0;
std::string outputFile; std::string outputFile;
bool useMmap = false; bool useMmap = true;
std::string url = "unicast"; std::string url = "unicast";
std::string murl = "multicast"; std::string murl = "multicast";
bool useThread = true;
// decode parameters // decode parameters
int c = 0; 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) switch (c)
{ {
@ -181,13 +182,14 @@ int main(int argc, char** argv)
case 'P': rtspPort = atoi(optarg); break; case 'P': rtspPort = atoi(optarg); break;
case 'T': rtspOverHTTPPort = atoi(optarg); break; case 'T': rtspOverHTTPPort = atoi(optarg); break;
case 'F': fps = 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 'u': url = optarg; break;
case 'h': case 'h':
default: 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 -v : verbose" << std::endl;
std::cout << "\t -vv : very verbose" << std::endl; std::cout << "\t -vv : very verbose" << std::endl;
std::cout << "\t -Q length: Number of frame queue (default "<< queueSize << ")" << 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 -P port : RTSP port (default "<< rtspPort << ")" << std::endl;
std::cout << "\t -H port : RTSP over HTTP port (default "<< rtspOverHTTPPort << ")" << 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 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 -F fps : V4L2 capture framerate (default "<< fps << ")" << std::endl;
std::cout << "\t -W width : V4L2 capture width (default "<< width << ")" << 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; 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()); int outputFd = createOutput(outputFile, videoCapture->getFd());
LOG(NOTICE) << "Start V4L2 Capture..." << dev_name; LOG(NOTICE) << "Start V4L2 Capture..." << dev_name;
videoCapture->captureStart(); 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) if (videoES == NULL)
{ {
LOG(FATAL) << "Unable to create source for device " << dev_name; LOG(FATAL) << "Unable to create source for device " << dev_name;

Loading…
Cancel
Save