extract H264 stuff from V4L2 stuff

pull/33/head
Michel Promonet 10 years ago
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…
Cancel
Save