From 2c4c64c0bb75de7b2da69f1b45cd781abbe88314 Mon Sep 17 00:00:00 2001 From: Michel Promonet Date: Sat, 7 Mar 2015 20:25:52 +0100 Subject: [PATCH] extract H264 stuff from V4L2DeviceSource --- inc/H264_V4l2DeviceSource.h | 42 ++++++++++++++ inc/ServerMediaSubsession.h | 5 +- inc/V4l2DeviceSource.h | 87 ++-------------------------- src/H264_V4l2DeviceSource.cpp | 105 ++++++++++++++++++++++++++++++++++ src/ServerMediaSubsession.cpp | 6 +- src/V4l2DeviceSource.cpp | 20 +++++-- src/main.cpp | 7 ++- 7 files changed, 177 insertions(+), 95 deletions(-) create mode 100644 inc/H264_V4l2DeviceSource.h create mode 100644 src/H264_V4l2DeviceSource.cpp diff --git a/inc/H264_V4l2DeviceSource.h b/inc/H264_V4l2DeviceSource.h new file mode 100644 index 0000000..24c9228 --- /dev/null +++ b/inc/H264_V4l2DeviceSource.h @@ -0,0 +1,42 @@ +/* --------------------------------------------------------------------------- +** This software is in the public domain, furnished "as is", without technical +** support, and with no warranty, express or implied, as to its usefulness for +** any purpose. +** +** H264_V4l2DeviceSource.h +** +** H264 V4L2 live555 source +** +** -------------------------------------------------------------------------*/ + + +#ifndef H264_V4L2_DEVICE_SOURCE +#define H264_V4L2_DEVICE_SOURCE + +// project +#include "V4l2DeviceSource.h" + +// --------------------------------- +// H264 V4L2 FramedSource +// --------------------------------- +const char H264marker[] = {0,0,0,1}; +class H264_V4L2DeviceSource : public V4L2DeviceSource +{ + public: + static H264_V4L2DeviceSource* createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread) ; + + protected: + H264_V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread); + virtual ~H264_V4L2DeviceSource(); + + unsigned char* extractFrame(unsigned char* frame, size_t size, size_t& outsize); + + // overide V4L2DeviceSource + virtual std::list< std::pair > splitFrames(unsigned char* frame, unsigned frameSize); + + private: + std::string m_sps; + std::string m_pps; +}; + +#endif diff --git a/inc/ServerMediaSubsession.h b/inc/ServerMediaSubsession.h index 2cd3195..00a5e64 100644 --- a/inc/ServerMediaSubsession.h +++ b/inc/ServerMediaSubsession.h @@ -16,7 +16,8 @@ // live555 #include -class H264Filter; +// forward declaration +class V4L2DeviceSource; // --------------------------------- // BaseServerMediaSubsession @@ -29,7 +30,7 @@ class BaseServerMediaSubsession public: static FramedSource* createSource(UsageEnvironment& env, FramedSource * videoES, int format); static RTPSink* createSink(UsageEnvironment& env, Groupsock * rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, int format); - char const* getAuxLine(H264Filter* source,unsigned char rtpPayloadType); + char const* getAuxLine(V4L2DeviceSource* source,unsigned char rtpPayloadType); protected: StreamReplicator* m_replicator; diff --git a/inc/V4l2DeviceSource.h b/inc/V4l2DeviceSource.h index 6295be3..4fa3faf 100644 --- a/inc/V4l2DeviceSource.h +++ b/inc/V4l2DeviceSource.h @@ -24,90 +24,10 @@ // project #include "V4l2Capture.h" -// --------------------------------- -// H264 parsing -// --------------------------------- -const char H264marker[] = {0,0,0,1}; -class H264Filter -{ - public: - H264Filter() {}; - virtual ~H264Filter() {}; - - std::string getAuxLine() { return m_auxLine; }; - - std::list< std::pair > splitFrames(unsigned char* frame, unsigned frameSize) - { - std::list< std::pair > frameList; - - size_t size = 0; - unsigned char* buffer = this->extractFrame(frame, frameSize, size); - while (buffer != NULL) - { - frameList.push_back(std::make_pair(buffer, size)); - switch (buffer[0]&0x1F) - { - case 7: std::cout << "SPS\n"; m_sps.assign((char*)buffer,size); break; - case 8: std::cout << "PPS\n"; m_pps.assign((char*)buffer,size); break; - default: break; - } - - if (m_auxLine.empty() && !m_sps.empty() && !m_pps.empty()) - { - u_int32_t profile_level_id = 0; - if (m_sps.size() >= 4) profile_level_id = (m_sps[1]<<16)|(m_sps[2]<<8)|m_sps[3]; - - char* sps_base64 = base64Encode(m_sps.c_str(), m_sps.size()); - char* pps_base64 = base64Encode(m_pps.c_str(), m_pps.size()); - - std::ostringstream os; - os << "profile-level-id=" << std::hex << std::setw(6) << profile_level_id; - os << ";sprop-parameter-sets=" << sps_base64 <<"," << pps_base64; - m_auxLine.assign(os.str()); - - free(sps_base64); - free(pps_base64); - std::cout << m_auxLine.c_str() << "\n"; - } - - frameSize -= size; - buffer = this->extractFrame(&buffer[size], frameSize, size); - } - return frameList; - } - - private: - unsigned char* extractFrame(unsigned char* frame, size_t size, size_t& outsize) - { - unsigned char * outFrame = NULL; - outsize = 0; - if ( (size>= sizeof(H264marker)) && (memcmp(frame,H264marker,sizeof(H264marker)) == 0) ) - { - outFrame = &frame[sizeof(H264marker)]; - outsize = size - sizeof(H264marker); - for (int i=0; i+sizeof(H264marker) < size; ++i) - { - if (memcmp(&outFrame[i],H264marker,sizeof(H264marker)) == 0) - { - outsize = i; - break; - } - } - } - return outFrame; - } - - private: - std::string m_auxLine; - std::string m_sps; - std::string m_pps; -}; - - // --------------------------------- // V4L2 FramedSource // --------------------------------- -class V4L2DeviceSource: public FramedSource, public H264Filter +class V4L2DeviceSource: public FramedSource { public: // --------------------------------- @@ -145,6 +65,7 @@ class V4L2DeviceSource: public FramedSource, public H264Filter public: 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, bool useThread); @@ -160,6 +81,9 @@ class V4L2DeviceSource: public FramedSource, public H264Filter void processFrame(char * frame, int frameSize, const timeval &ref); void queueFrame(char * frame, int frameSize, const timeval &tv); + // split packet in frames + virtual std::list< std::pair > splitFrames(unsigned char* frame, unsigned frameSize); + // overide FramedSource virtual void doGetNextFrame(); virtual void doStopGettingFrames(); @@ -175,6 +99,7 @@ class V4L2DeviceSource: public FramedSource, public H264Filter unsigned int m_queueSize; int m_verbose; pthread_t m_thid; + std::string m_auxLine; }; #endif diff --git a/src/H264_V4l2DeviceSource.cpp b/src/H264_V4l2DeviceSource.cpp new file mode 100644 index 0000000..e707dc9 --- /dev/null +++ b/src/H264_V4l2DeviceSource.cpp @@ -0,0 +1,105 @@ +/* --------------------------------------------------------------------------- +** This software is in the public domain, furnished "as is", without technical +** support, and with no warranty, express or implied, as to its usefulness for +** any purpose. +** +** H264_V4l2DeviceSource.cpp +** +** H264 V4L2 Live555 source +** +** -------------------------------------------------------------------------*/ + +#include + +// live555 +#include + +// project +#include "H264_V4l2DeviceSource.h" + +// --------------------------------- +// H264 V4L2 FramedSource +// --------------------------------- +H264_V4L2DeviceSource* H264_V4L2DeviceSource::createNew(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread) +{ + H264_V4L2DeviceSource* source = NULL; + if (device) + { + source = new H264_V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose, useThread); + } + return source; +} + +// Constructor +H264_V4L2DeviceSource::H264_V4L2DeviceSource(UsageEnvironment& env, V4L2DeviceParameters params, V4l2Capture * device, int outputFd, unsigned int queueSize, int verbose, bool useThread) + : V4L2DeviceSource(env, params, device, outputFd, queueSize, verbose,useThread) +{ +} + +// Destructor +H264_V4L2DeviceSource::~H264_V4L2DeviceSource() +{ +} + +// split packet in frames +std::list< std::pair > H264_V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize) +{ + std::list< std::pair > frameList; + + size_t size = 0; + unsigned char* buffer = this->extractFrame(frame, frameSize, size); + while (buffer != NULL) + { + frameList.push_back(std::make_pair(buffer, size)); + switch (buffer[0]&0x1F) + { + case 7: std::cout << "SPS\n"; m_sps.assign((char*)buffer,size); break; + case 8: std::cout << "PPS\n"; m_pps.assign((char*)buffer,size); break; + default: break; + } + + if (m_auxLine.empty() && !m_sps.empty() && !m_pps.empty()) + { + u_int32_t profile_level_id = 0; + if (m_sps.size() >= 4) profile_level_id = (m_sps[1]<<16)|(m_sps[2]<<8)|m_sps[3]; + + char* sps_base64 = base64Encode(m_sps.c_str(), m_sps.size()); + char* pps_base64 = base64Encode(m_pps.c_str(), m_pps.size()); + + std::ostringstream os; + os << "profile-level-id=" << std::hex << std::setw(6) << profile_level_id; + os << ";sprop-parameter-sets=" << sps_base64 <<"," << pps_base64; + m_auxLine.assign(os.str()); + + free(sps_base64); + free(pps_base64); + std::cout << m_auxLine.c_str() << "\n"; + } + + frameSize -= size; + buffer = this->extractFrame(&buffer[size], frameSize, size); + } + return frameList; +} + +// extract a frame +unsigned char* H264_V4L2DeviceSource::extractFrame(unsigned char* frame, size_t size, size_t& outsize) +{ + unsigned char * outFrame = NULL; + outsize = 0; + if ( (size>= sizeof(H264marker)) && (memcmp(frame,H264marker,sizeof(H264marker)) == 0) ) + { + outFrame = &frame[sizeof(H264marker)]; + outsize = size - sizeof(H264marker); + for (int i=0; i+sizeof(H264marker) < size; ++i) + { + if (memcmp(&outFrame[i],H264marker,sizeof(H264marker)) == 0) + { + outsize = i; + break; + } + } + } + return outFrame; +} + diff --git a/src/ServerMediaSubsession.cpp b/src/ServerMediaSubsession.cpp index 474bcff..cdbd83a 100644 --- a/src/ServerMediaSubsession.cpp +++ b/src/ServerMediaSubsession.cpp @@ -44,7 +44,7 @@ RTPSink* BaseServerMediaSubsession::createSink(UsageEnvironment& env, Groupsock return videoSink; } -char const* BaseServerMediaSubsession::getAuxLine(H264Filter* source,unsigned char rtpPayloadType) +char const* BaseServerMediaSubsession::getAuxLine(V4L2DeviceSource* source,unsigned char rtpPayloadType) { const char* auxLine = NULL; if (source) @@ -105,7 +105,7 @@ char const* MulticastServerMediaSubsession::sdpLines() char const* MulticastServerMediaSubsession::getAuxSDPLine(RTPSink* rtpSink,FramedSource* inputSource) { - return this->getAuxLine(dynamic_cast(m_replicator->inputSource()), rtpSink->rtpPayloadType()); + return this->getAuxLine(dynamic_cast(m_replicator->inputSource()), rtpSink->rtpPayloadType()); } // ----------------------------------------- @@ -129,5 +129,5 @@ RTPSink* UnicastServerMediaSubsession::createNewRTPSink(Groupsock* rtpGroupsock, char const* UnicastServerMediaSubsession::getAuxSDPLine(RTPSink* rtpSink,FramedSource* inputSource) { - return this->getAuxLine(dynamic_cast(m_replicator->inputSource()), rtpSink->rtpPayloadType()); + return this->getAuxLine(dynamic_cast(m_replicator->inputSource()), rtpSink->rtpPayloadType()); } diff --git a/src/V4l2DeviceSource.cpp b/src/V4l2DeviceSource.cpp index 82e731f..ea0791c 100644 --- a/src/V4l2DeviceSource.cpp +++ b/src/V4l2DeviceSource.cpp @@ -17,11 +17,6 @@ #include #include -// live555 -#include -#include -#include - // project #include "V4l2DeviceSource.h" @@ -249,7 +244,8 @@ void V4L2DeviceSource::processFrame(char * frame, int frameSize, const timeval & frameList.pop_front(); } } - + +// post a frame to fifo void V4L2DeviceSource::queueFrame(char * frame, int frameSize, const timeval &tv) { while (m_captureQueue.size() >= m_queueSize) @@ -267,4 +263,16 @@ void V4L2DeviceSource::queueFrame(char * frame, int frameSize, const timeval &tv envir().taskScheduler().triggerEvent(m_eventTriggerId, this); } +// split packet in frames +std::list< std::pair > V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize) +{ + std::list< std::pair > frameList; + if (frame != NULL) + { + frameList.push_back(std::make_pair(frame, frameSize)); + } + return frameList; +} + + diff --git a/src/main.cpp b/src/main.cpp index 86c5509..5bbccf1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,7 +37,7 @@ #include "V4l2ReadCapture.h" #include "V4l2MmapCapture.h" -#include "V4l2DeviceSource.h" +#include "H264_V4l2DeviceSource.h" #include "ServerMediaSubsession.h" // ----------------------------------------- @@ -244,20 +244,21 @@ 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, useThread); + V4L2DeviceSource* videoES = H264_V4L2DeviceSource::createNew(*env, param, videoCapture, outputFd, queueSize, verbose, useThread); if (videoES == NULL) { LOG(FATAL) << "Unable to create source for device " << dev_name; } else { - destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env); OutPacketBuffer::maxSize = videoCapture->getBufferSize(); StreamReplicator* replicator = StreamReplicator::createNew(*env, videoES, false); // Create Server Multicast Session if (multicast) { + destinationAddress.s_addr = chooseRandomIPv4SSMAddress(*env); + LOG(NOTICE) << "Mutlicast address " << inet_ntoa(destinationAddress); addSession(rtspServer, murl.c_str(), MulticastServerMediaSubsession::createNew(*env,destinationAddress, Port(rtpPortNum), Port(rtcpPortNum), ttl, replicator,format)); }