2016-05-17 19:29:48 +00:00
|
|
|
/* ---------------------------------------------------------------------------
|
|
|
|
** 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.
|
|
|
|
**
|
|
|
|
** MJPEGVideoSource.h
|
|
|
|
**
|
|
|
|
** V4L2 RTSP streamer
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** -------------------------------------------------------------------------*/
|
|
|
|
|
2016-06-19 08:53:56 +00:00
|
|
|
#include "logger.h"
|
2016-05-17 19:29:48 +00:00
|
|
|
#include "JPEGVideoSource.hh"
|
|
|
|
|
|
|
|
class MJPEGVideoSource : public JPEGVideoSource
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static MJPEGVideoSource* createNew (UsageEnvironment& env, FramedSource* source)
|
|
|
|
{
|
|
|
|
return new MJPEGVideoSource(env,source);
|
|
|
|
}
|
|
|
|
virtual void doGetNextFrame()
|
|
|
|
{
|
|
|
|
if (m_inputSource)
|
|
|
|
m_inputSource->getNextFrame(fTo, fMaxSize, afterGettingFrameSub, this, FramedSource::handleClosure, this);
|
|
|
|
}
|
|
|
|
virtual void doStopGettingFrames()
|
|
|
|
{
|
|
|
|
FramedSource::doStopGettingFrames();
|
|
|
|
if (m_inputSource)
|
|
|
|
m_inputSource->stopGettingFrames();
|
|
|
|
}
|
|
|
|
static void afterGettingFrameSub(void* clientData, unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
|
|
|
|
{
|
|
|
|
MJPEGVideoSource* source = (MJPEGVideoSource*)clientData;
|
|
|
|
source->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime, durationInMicroseconds);
|
2017-06-03 14:19:55 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 19:29:48 +00:00
|
|
|
void afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
|
|
|
|
{
|
2017-06-03 14:19:55 +00:00
|
|
|
int headerSize = 0;
|
|
|
|
fFrameSize = 0;
|
2016-05-18 20:29:03 +00:00
|
|
|
|
2017-06-03 14:19:55 +00:00
|
|
|
unsigned int i = 0;
|
|
|
|
while ( (i<frameSize) && (headerSize==0) ) {
|
2016-05-17 19:29:48 +00:00
|
|
|
// SOF
|
2017-06-03 14:19:55 +00:00
|
|
|
if ( ((i+11) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xC0) ) {
|
|
|
|
int length = (fTo[i+2]<<8)|(fTo[i+3]);
|
|
|
|
LOG(DEBUG) << "SOF length:" << length;
|
2016-06-19 08:53:56 +00:00
|
|
|
|
2017-06-03 14:19:55 +00:00
|
|
|
m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
|
|
|
|
m_width = (fTo[i+7]<<5)|(fTo[i+8]>>3);
|
|
|
|
|
|
|
|
int hv_subsampling = fTo[i+11];
|
|
|
|
if (hv_subsampling == 0x21 ) {
|
|
|
|
m_type = 0; // JPEG 4:2:2
|
|
|
|
} else if (hv_subsampling == 0x22 ) {
|
|
|
|
m_type = 1; // JPEG 4:2:0
|
|
|
|
} else {
|
|
|
|
LOG(NOTICE) << "not managed sampling:0x" << std::hex << hv_subsampling;
|
|
|
|
m_type = 255;
|
|
|
|
}
|
|
|
|
LOG(INFO) << "width:" << (int)(m_width<<3) << " height:" << (int)(m_height<<3) << " type:"<< (int)m_type;
|
|
|
|
|
2017-06-11 13:47:15 +00:00
|
|
|
i+=length+2;
|
2016-05-17 19:29:48 +00:00
|
|
|
}
|
|
|
|
// DQT
|
2017-06-03 14:19:55 +00:00
|
|
|
else if ( ( (i+5+64) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDB)) {
|
|
|
|
int length = (fTo[i+2]<<8)|(fTo[i+3]);
|
|
|
|
LOG(DEBUG) << "DQT length:" << length;
|
|
|
|
|
2017-06-11 14:25:52 +00:00
|
|
|
unsigned int precision = fTo[i+4]<<4;
|
2017-06-11 13:47:15 +00:00
|
|
|
unsigned int quantIdx = fTo[i+4]&0x0f;
|
|
|
|
unsigned int quantSize = length-3;
|
2017-06-03 14:19:55 +00:00
|
|
|
if (quantSize*quantIdx+quantSize <= sizeof(m_qTable)) {
|
|
|
|
memcpy(m_qTable + quantSize*quantIdx, fTo + i + 5, quantSize);
|
|
|
|
if (quantSize*quantIdx+quantSize > m_qTableSize) {
|
|
|
|
m_qTableSize = quantSize*quantIdx+quantSize;
|
2017-06-11 14:25:52 +00:00
|
|
|
LOG(NOTICE) << "Quantization table idx:" << quantIdx << " precision:" << precision << " size:" << quantSize << " total size:" << m_qTableSize;
|
2017-06-03 14:19:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-11 13:47:15 +00:00
|
|
|
i+=length+2;
|
2016-05-17 19:29:48 +00:00
|
|
|
}
|
2017-06-03 14:19:55 +00:00
|
|
|
// SOS
|
|
|
|
else if ( ((i+1) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDA) ) {
|
|
|
|
int length = (fTo[i+2]<<8)|(fTo[i+3]);
|
|
|
|
LOG(DEBUG) << "SOS length:" << length;
|
|
|
|
|
|
|
|
headerSize = i+length+2;
|
|
|
|
} else {
|
|
|
|
i++;
|
2016-05-17 19:29:48 +00:00
|
|
|
}
|
2017-06-03 14:19:55 +00:00
|
|
|
}
|
2016-05-17 19:29:48 +00:00
|
|
|
|
2017-06-03 14:19:55 +00:00
|
|
|
if (headerSize != 0) {
|
|
|
|
LOG(DEBUG) << "headerSize:" << headerSize;
|
2016-05-17 19:29:48 +00:00
|
|
|
fFrameSize = frameSize - headerSize;
|
|
|
|
memmove( fTo, fTo + headerSize, fFrameSize );
|
2017-06-03 14:19:55 +00:00
|
|
|
} else {
|
2016-06-19 08:53:56 +00:00
|
|
|
LOG(NOTICE) << "Bad header => dropping frame";
|
2017-06-03 14:19:55 +00:00
|
|
|
}
|
2016-05-17 19:29:48 +00:00
|
|
|
|
2017-06-03 14:19:55 +00:00
|
|
|
fNumTruncatedBytes = numTruncatedBytes;
|
|
|
|
fPresentationTime = presentationTime;
|
|
|
|
fDurationInMicroseconds = durationInMicroseconds;
|
|
|
|
afterGetting(this);
|
2016-05-17 19:29:48 +00:00
|
|
|
}
|
|
|
|
virtual u_int8_t type() { return m_type; };
|
|
|
|
virtual u_int8_t qFactor() { return 128; };
|
|
|
|
virtual u_int8_t width() { return m_width; };
|
|
|
|
virtual u_int8_t height() { return m_height; };
|
|
|
|
u_int8_t const* quantizationTables( u_int8_t& precision, u_int16_t& length )
|
|
|
|
{
|
|
|
|
length = 0;
|
|
|
|
precision = 0;
|
2016-05-18 20:29:03 +00:00
|
|
|
if (m_qTableSize > 0)
|
2016-05-17 19:29:48 +00:00
|
|
|
{
|
2016-05-18 20:29:03 +00:00
|
|
|
length = m_qTableSize;
|
2017-06-11 13:47:15 +00:00
|
|
|
precision = m_precision;
|
2016-05-17 19:29:48 +00:00
|
|
|
}
|
|
|
|
return m_qTable;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
MJPEGVideoSource(UsageEnvironment& env, FramedSource* source) : JPEGVideoSource(env),
|
|
|
|
m_inputSource(source),
|
2017-06-11 13:47:15 +00:00
|
|
|
m_width(0), m_height(0), m_qTableSize(0), m_precision(0),
|
2016-05-17 19:29:48 +00:00
|
|
|
m_type(0)
|
|
|
|
{
|
|
|
|
memset(&m_qTable,0,sizeof(m_qTable));
|
|
|
|
}
|
|
|
|
virtual ~MJPEGVideoSource()
|
|
|
|
{
|
|
|
|
Medium::close(m_inputSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
FramedSource* m_inputSource;
|
|
|
|
u_int8_t m_width;
|
|
|
|
u_int8_t m_height;
|
2016-05-18 20:29:03 +00:00
|
|
|
u_int8_t m_qTable[128*2];
|
|
|
|
unsigned int m_qTableSize;
|
2017-06-11 13:47:15 +00:00
|
|
|
unsigned int m_precision;
|
2016-05-17 19:29:48 +00:00
|
|
|
u_int8_t m_type;
|
|
|
|
};
|