start with HEVC

This commit is contained in:
Michel Promonet 2017-08-15 17:49:30 +02:00
parent 17adacfe8b
commit b0e3d7bdc7
4 changed files with 152 additions and 58 deletions

View File

@ -21,21 +21,18 @@
// ---------------------------------
const char H264marker[] = {0,0,0,1};
const char H264shortmarker[] = {0,0,1};
class H264_V4L2DeviceSource : public V4L2DeviceSource
class H26X_V4L2DeviceSource : public V4L2DeviceSource
{
public:
static H264_V4L2DeviceSource* createNew(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker) ;
protected:
H264_V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker);
virtual ~H264_V4L2DeviceSource();
H26X_V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker)
: V4L2DeviceSource(env, device, outputFd, queueSize, useThread), m_repeatConfig(repeatConfig), m_keepMarker(keepMarker), m_frameType(0) {}
virtual ~H26X_V4L2DeviceSource() {}
unsigned char* extractFrame(unsigned char* frame, size_t& size, size_t& outsize);
// overide V4L2DeviceSource
virtual std::list< std::pair<unsigned char*,size_t> > splitFrames(unsigned char* frame, unsigned frameSize);
private:
virtual unsigned char* extractFrame(unsigned char* frame, size_t& size, size_t& outsize);
protected:
std::string m_sps;
std::string m_pps;
bool m_repeatConfig;
@ -43,4 +40,37 @@ class H264_V4L2DeviceSource : public V4L2DeviceSource
int m_frameType;
};
class H264_V4L2DeviceSource : public H26X_V4L2DeviceSource
{
public:
static H264_V4L2DeviceSource* createNew(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker) {
return new H264_V4L2DeviceSource(env, device, outputFd, queueSize, useThread, repeatConfig, keepMarker);
}
protected:
H264_V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker)
: H26X_V4L2DeviceSource(env, device, outputFd, queueSize, useThread, repeatConfig, keepMarker) {}
// overide V4L2DeviceSource
virtual std::list< std::pair<unsigned char*,size_t> > splitFrames(unsigned char* frame, unsigned frameSize);
};
class H265_V4L2DeviceSource : public H26X_V4L2DeviceSource
{
public:
static H265_V4L2DeviceSource* createNew(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker) {
return new H265_V4L2DeviceSource(env, device, outputFd, queueSize, useThread, repeatConfig, keepMarker);
}
protected:
H265_V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker)
: H26X_V4L2DeviceSource(env, device, outputFd, queueSize, useThread, repeatConfig, keepMarker) {}
// overide V4L2DeviceSource
virtual std::list< std::pair<unsigned char*,size_t> > splitFrames(unsigned char* frame, unsigned frameSize);
protected:
std::string m_vps;
};
#endif

View File

@ -21,26 +21,7 @@
// ---------------------------------
// H264 V4L2 FramedSource
// ---------------------------------
H264_V4L2DeviceSource* H264_V4L2DeviceSource::createNew(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker)
{
H264_V4L2DeviceSource* source = NULL;
if (device)
{
source = new H264_V4L2DeviceSource(env, device, outputFd, queueSize, useThread, repeatConfig, keepMarker);
}
return source;
}
// Constructor
H264_V4L2DeviceSource::H264_V4L2DeviceSource(UsageEnvironment& env, DeviceInterface * device, int outputFd, unsigned int queueSize, bool useThread, bool repeatConfig, bool keepMarker)
: V4L2DeviceSource(env, device, outputFd, queueSize, useThread), m_repeatConfig(repeatConfig), m_keepMarker(keepMarker), m_frameType(0)
{
}
// Destructor
H264_V4L2DeviceSource::~H264_V4L2DeviceSource()
{
}
// split packet in frames
std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize)
@ -51,8 +32,8 @@ std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames
size_t size = 0;
unsigned char* buffer = this->extractFrame(frame, bufSize, size);
while (buffer != NULL)
{
switch (m_frameType)
{
switch (m_frameType&0x1F)
{
case 7: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
case 8: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
@ -63,7 +44,8 @@ std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_pps.c_str(), m_pps.size()));
}
break;
default: break;
default:
break;
}
if (m_auxLine.empty() && !m_sps.empty() && !m_pps.empty())
@ -90,49 +72,113 @@ std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames
return frameList;
}
// split packet in frames
std::list< std::pair<unsigned char*,size_t> > H265_V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize)
{
std::list< std::pair<unsigned char*,size_t> > frameList;
size_t bufSize = frameSize;
size_t size = 0;
unsigned char* buffer = this->extractFrame(frame, bufSize, size);
while (buffer != NULL)
{
switch ((m_frameType&0x7E)>>1)
{
case 32: LOG(INFO) << "VPS size:" << size << " bufSize:" << bufSize; m_vps.assign((char*)buffer,size); break;
case 33: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
case 34: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
case 19:
case 20: LOG(INFO) << "IDR size:" << size << " bufSize:" << bufSize;
if (m_repeatConfig && !m_vps.empty() && !m_sps.empty() && !m_pps.empty())
{
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_vps.c_str(), m_vps.size()));
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_sps.c_str(), m_sps.size()));
frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_pps.c_str(), m_pps.size()));
}
break;
default: break;
}
if (m_auxLine.empty() && !m_vps.empty() && !m_sps.empty() && !m_pps.empty())
{
char* vps_base64 = base64Encode(m_vps.c_str(), m_vps.size());
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 << "sprop-vps=" << vps_base64;
os << ";sprop-sps=" << sps_base64;
os << ";sprop-pps=" << pps_base64;
m_auxLine.assign(os.str());
LOG(NOTICE) << m_auxLine;
delete [] vps_base64;
delete [] sps_base64;
delete [] pps_base64;
}
frameList.push_back(std::pair<unsigned char*,size_t>(buffer, size));
buffer = this->extractFrame(&buffer[size], bufSize, size);
}
return frameList;
}
// extract a frame
unsigned char* H264_V4L2DeviceSource::extractFrame(unsigned char* frame, size_t& size, size_t& outsize)
{
unsigned char* H26X_V4L2DeviceSource::extractFrame(unsigned char* frame, size_t& size, size_t& outsize)
{
unsigned char * outFrame = NULL;
outsize = 0;
unsigned int markerlength = 0;
m_frameType = 0;
if ( (size>= sizeof(H264marker)) && (memcmp(frame,H264marker,sizeof(H264marker)) == 0) )
{
markerlength = sizeof(H264marker);
}
else if ( (size>= sizeof(H264shortmarker)) && (memcmp(frame,H264shortmarker,sizeof(H264shortmarker)) == 0) )
{
markerlength = sizeof(H264shortmarker);
}
m_frameType = 0;
if (markerlength != 0)
{
m_frameType = (frame[markerlength]&0x1F);
unsigned char * ptr = (unsigned char*)memmem(&frame[markerlength], size-markerlength, H264marker, sizeof(H264marker));
if (ptr == NULL)
{
ptr = (unsigned char*)memmem(&frame[markerlength], size-markerlength, H264shortmarker, sizeof(H264shortmarker));
unsigned char *startFrame = (unsigned char*)memmem(frame,size,H264marker,sizeof(H264marker));
if (startFrame != NULL) {
markerlength = sizeof(H264marker);
} else {
startFrame = (unsigned char*)memmem(frame,size,H264shortmarker,sizeof(H264shortmarker));
if (startFrame != NULL) {
markerlength = sizeof(H264shortmarker);
}
}
if (startFrame != NULL) {
std::ostringstream os;
for (int j=0; j<16 && j<size ; j++) {
os << std::hex << int(frame[j]) << " ";
}
std::cout << os.str() << std::endl;
m_frameType = startFrame[markerlength];
int remainingSize = size-(startFrame-frame+markerlength);
unsigned char *endFrame = (unsigned char*)memmem(&startFrame[markerlength], remainingSize, H264marker, sizeof(H264marker));
if (endFrame == NULL) {
endFrame = (unsigned char*)memmem(&startFrame[markerlength], remainingSize, H264shortmarker, sizeof(H264shortmarker));
}
if (m_keepMarker)
{
outFrame = &frame[0];
size -= startFrame-frame;
outFrame = startFrame;
}
else
{
size -= markerlength;
outFrame = &frame[markerlength];
size -= startFrame-frame+markerlength;
outFrame = &startFrame[markerlength];
}
if (ptr != NULL)
if (endFrame != NULL)
{
outsize = ptr - outFrame;
outsize = endFrame - outFrame;
}
else
{
outsize = size;
}
size -= outsize;
size -= outsize;
} else if (size>= sizeof(H264shortmarker)) {
LOG(INFO) << "No marker found";
}
return outFrame;
}

View File

@ -33,6 +33,10 @@ FramedSource* BaseServerMediaSubsession::createSource(UsageEnvironment& env, Fra
{
source = H264VideoStreamDiscreteFramer::createNew(env, videoES);
}
else if (format == "video/H265")
{
source = H265VideoStreamDiscreteFramer::createNew(env, videoES);
}
else if (format == "video/JPEG")
{
source = MJPEGVideoSource::createNew(env, videoES);
@ -55,6 +59,10 @@ RTPSink* BaseServerMediaSubsession::createSink(UsageEnvironment& env, Groupsock
{
videoSink = H264VideoRTPSink::createNew(env, rtpGroupsock,rtpPayloadTypeIfDynamic);
}
else if (format == "video/H265")
{
videoSink = H265VideoRTPSink::createNew(env, rtpGroupsock,rtpPayloadTypeIfDynamic);
}
else if (format == "video/VP8")
{
videoSink = VP8VideoRTPSink::createNew (env, rtpGroupsock,rtpPayloadTypeIfDynamic);

View File

@ -114,6 +114,16 @@ FramedSource* createFramedSource(UsageEnvironment* env, int format, DeviceInterf
source = muxer;
}
}
else if (format == V4L2_PIX_FMT_HEVC)
{
source = H265_V4L2DeviceSource::createNew(*env, videoCapture, outfd, queueSize, useThread, repeatConfig, muxTS);
if (muxTS)
{
MPEG2TransportStreamFromESSource* muxer = MPEG2TransportStreamFromESSource::createNew(*env);
muxer->addNewVideoSource(source, 6);
source = muxer;
}
}
else
{
source = V4L2DeviceSource::createNew(*env, videoCapture, outfd, queueSize, useThread);