diff --git a/inc/ServerMediaSubsession.h b/inc/ServerMediaSubsession.h index a1f80be..2cd3195 100644 --- a/inc/ServerMediaSubsession.h +++ b/inc/ServerMediaSubsession.h @@ -11,12 +11,12 @@ #define SERVER_MEDIA_SUBSESSION #include +#include // live555 #include -//forward declarations -class V4L2DeviceSource; +class H264Filter; // --------------------------------- // BaseServerMediaSubsession @@ -29,7 +29,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(V4L2DeviceSource* source,unsigned char rtpPayloadType); + char const* getAuxLine(H264Filter* source,unsigned char rtpPayloadType); protected: StreamReplicator* m_replicator; diff --git a/inc/V4l2DeviceSource.h b/inc/V4l2DeviceSource.h index 3e8707f..6295be3 100644 --- a/inc/V4l2DeviceSource.h +++ b/inc/V4l2DeviceSource.h @@ -16,6 +16,7 @@ #include #include #include +#include // live555 #include @@ -23,11 +24,90 @@ // 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 // --------------------------------- -const char marker[] = {0,0,0,1}; -class V4L2DeviceSource: public FramedSource +class V4L2DeviceSource: public FramedSource, public H264Filter { public: // --------------------------------- @@ -65,7 +145,6 @@ class V4L2DeviceSource: public FramedSource 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); @@ -78,8 +157,7 @@ class V4L2DeviceSource: public FramedSource void deliverFrame(); static void incomingPacketHandlerStub(void* clientData, int mask) { ((V4L2DeviceSource*) clientData)->getNextFrame(); }; int getNextFrame(); - 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); // overide FramedSource @@ -93,7 +171,6 @@ class V4L2DeviceSource: public FramedSource Stats m_out; EventTriggerId m_eventTriggerId; int m_outfd; - std::string m_auxLine; V4l2Capture * m_device; unsigned int m_queueSize; int m_verbose; diff --git a/src/ServerMediaSubsession.cpp b/src/ServerMediaSubsession.cpp index cdbd83a..474bcff 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(V4L2DeviceSource* source,unsigned char rtpPayloadType) +char const* BaseServerMediaSubsession::getAuxLine(H264Filter* 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 4f4653a..4c099ab 100644 --- a/src/V4l2DeviceSource.cpp +++ b/src/V4l2DeviceSource.cpp @@ -179,13 +179,7 @@ void V4L2DeviceSource::deliverFrame() printf ("deliverFrame\ttimestamp:%ld.%06ld\tsize:%d diff:%d ms queue:%d\n",fPresentationTime.tv_sec, fPresentationTime.tv_usec, fFrameSize, (int)(diff.tv_sec*1000+diff.tv_usec/1000), m_captureQueue.size()); } - int offset = 0; - if ( (fFrameSize>sizeof(marker)) && (memcmp(frame->m_buffer,marker,sizeof(marker)) == 0) ) - { - offset = sizeof(marker); - } - fFrameSize -= offset; - memcpy(fTo, frame->m_buffer+offset, fFrameSize); + memcpy(fTo, frame->m_buffer, fFrameSize); delete frame; } @@ -197,7 +191,7 @@ void V4L2DeviceSource::deliverFrame() // FrameSource callback on read event int V4L2DeviceSource::getNextFrame() { - char* buffer = new char[m_device->getBufferSize()]; + char buffer[m_device->getBufferSize()]; timeval ref; gettimeofday(&ref, NULL); int frameSize = m_device->read(buffer, m_device->getBufferSize()); @@ -205,13 +199,11 @@ int V4L2DeviceSource::getNextFrame() if (frameSize < 0) { envir() << "V4L2DeviceSource::getNextFrame errno:" << errno << " " << strerror(errno) << "\n"; - delete [] buffer; handleClosure(this); } else if (frameSize == 0) { envir() << "V4L2DeviceSource::getNextFrame no data errno:" << errno << " " << strerror(errno) << "\n"; - delete [] buffer; handleClosure(this); } else @@ -226,93 +218,12 @@ int V4L2DeviceSource::getNextFrame() printf ("getNextFrame\ttimestamp:%ld.%06ld\tsize:%d diff:%d ms queue:%d\n", ref.tv_sec, ref.tv_usec, frameSize, (int)(diff.tv_sec*1000+diff.tv_usec/1000), m_captureQueue.size()); } processFrame(buffer,frameSize,ref); - if (!processConfigrationFrame(buffer,frameSize)) - { - queueFrame(buffer,frameSize,ref); - } - else - { - delete [] buffer; - } } return frameSize; } -bool V4L2DeviceSource::processConfigrationFrame(char * frame, int frameSize) -{ - bool ret = false; - - if (memcmp(frame,marker,sizeof(marker)) == 0) - { - // save SPS and PPS - ssize_t spsSize = -1; - ssize_t ppsSize = -1; - u_int8_t nal_unit_type = frame[sizeof(marker)]&0x1F; - if (nal_unit_type == 7) - { - std::cout << "SPS\n"; - for (int i=sizeof(marker); i+sizeof(marker) < frameSize; ++i) - { - if (memcmp(&frame[i],marker,sizeof(marker)) == 0) - { - spsSize = i-sizeof(marker) ; - std::cout << "SPS size:" << spsSize << "\n"; - - nal_unit_type = frame[i+sizeof(marker)]&0x1F; - if (nal_unit_type == 8) - { - std::cout << "PPS\n"; - for (int j=i+sizeof(marker); j+sizeof(marker) < frameSize; ++j) - { - if (memcmp(&frame[j],marker,sizeof(marker)) == 0) - { - ppsSize = j-sizeof(marker); - std::cout << "PPS size:" << ppsSize << "\n"; - break; - } - } - if (ppsSize <0) - { - ppsSize = frameSize - spsSize - 2*sizeof(marker); - std::cout << "PPS size:" << ppsSize << "\n"; - } - } - } - } - if ( (spsSize > 0) && (ppsSize > 0) ) - { - char sps[spsSize]; - memcpy(&sps, frame+sizeof(marker), spsSize); - char pps[ppsSize]; - memcpy(&pps, &frame[spsSize+2*sizeof(marker)], ppsSize); - u_int32_t profile_level_id = 0; - if (spsSize >= 4) - { - profile_level_id = (sps[1]<<16)|(sps[2]<<8)|sps[3]; - } - - char* sps_base64 = base64Encode(sps, spsSize); - char* pps_base64 = base64Encode(pps, ppsSize); - - 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 << "AuxLine:" << m_auxLine << " \n"; - } - ret = true; - } - } - - return ret; -} - -void V4L2DeviceSource::processFrame(char * frame, int &frameSize, const timeval &ref) +void V4L2DeviceSource::processFrame(char * frame, int frameSize, const timeval &ref) { timeval tv; gettimeofday(&tv, NULL); @@ -324,6 +235,18 @@ void V4L2DeviceSource::processFrame(char * frame, int &frameSize, const timeval printf ("queueFrame\ttimestamp:%ld.%06ld\tsize:%d diff:%d ms queue:%d data:%02X%02X%02X%02X%02X...\n", ref.tv_sec, ref.tv_usec, frameSize, (int)(diff.tv_sec*1000+diff.tv_usec/1000), m_captureQueue.size(), frame[0], frame[1], frame[2], frame[3], frame[4]); } if (m_outfd != -1) write(m_outfd, frame, frameSize); + + std::list< std::pair > frameList = this->splitFrames((unsigned char*)frame, frameSize); + while (!frameList.empty()) + { + std::pair & frame = frameList.front(); + size_t size = frame.second; + char* buf = new char[size]; + memcpy(buf, frame.first, size); + queueFrame(buf,size,ref); + + frameList.pop_front(); + } } void V4L2DeviceSource::queueFrame(char * frame, int frameSize, const timeval &tv)