mirror of
https://github.com/mpromonet/v4l2rtspserver
synced 2024-11-17 21:25:40 +00:00
extract H264 stuff from V4L2 stuff
This commit is contained in:
parent
380945d3b6
commit
45ab4f57e4
@ -11,12 +11,12 @@
|
||||
#define SERVER_MEDIA_SUBSESSION
|
||||
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
||||
// live555
|
||||
#include <liveMedia.hh>
|
||||
|
||||
//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;
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
// live555
|
||||
#include <liveMedia.hh>
|
||||
@ -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<unsigned char*,size_t> > splitFrames(unsigned char* frame, unsigned frameSize)
|
||||
{
|
||||
std::list< std::pair<unsigned char*,size_t> > frameList;
|
||||
|
||||
size_t size = 0;
|
||||
unsigned char* buffer = this->extractFrame(frame, frameSize, size);
|
||||
while (buffer != NULL)
|
||||
{
|
||||
frameList.push_back(std::make_pair<unsigned char*,size_t>(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;
|
||||
|
@ -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<V4L2DeviceSource*>(m_replicator->inputSource()), rtpSink->rtpPayloadType());
|
||||
return this->getAuxLine(dynamic_cast<H264Filter*>(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<V4L2DeviceSource*>(m_replicator->inputSource()), rtpSink->rtpPayloadType());
|
||||
return this->getAuxLine(dynamic_cast<H264Filter*>(m_replicator->inputSource()), rtpSink->rtpPayloadType());
|
||||
}
|
||||
|
@ -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<unsigned char*,size_t> > frameList = this->splitFrames((unsigned char*)frame, frameSize);
|
||||
while (!frameList.empty())
|
||||
{
|
||||
std::pair<unsigned char*,size_t> & 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)
|
||||
|
Loading…
Reference in New Issue
Block a user