1/* ---------------------------------------------------------------------------
2** This software is in the public domain, furnished "as is", without technical
3** support, and with no warranty, express or implied, as to its usefulness for
4** any purpose.
5**
6** MJPEGVideoSource.cpp
7**
8** V4L2 RTSP streamer
9**
10** MJPEG Source for RTSP server
11**
12** -------------------------------------------------------------------------*/
13
14#include "MJPEGVideoSource.h"
15
16
17void MJPEGVideoSource::afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
18{
19 int headerSize = 0;
20 fFrameSize = 0;
21
22 unsigned int i = 0;
23 while ( (i<frameSize) && (headerSize==0) ) {
24 // SOF
25 if ( ((i+11) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xC0) ) {
26 int length = (fTo[i+2]<<8)|(fTo[i+3]);
27 LOG(DEBUG) << "SOF length:" << length;
28
29 m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
30 m_width = (fTo[i+7]<<5)|(fTo[i+8]>>3);
31
32 int hv_subsampling = fTo[i+11];
33 if (hv_subsampling == 0x21 ) {
34 m_type = 0; // JPEG 4:2:2
35 } else if (hv_subsampling == 0x22 ) {
36 m_type = 1; // JPEG 4:2:0
37 } else {
38 LOG(NOTICE) << "not managed sampling:0x" << std::hex << hv_subsampling;
39 m_type = 255;
40 }
41
42 int precision = fTo[i+4];
43 LOG(INFO) << "width:" << (int)(m_width<<3) << " height:" << (int)(m_height<<3) << " type:"<< (int)m_type << " precision:" << precision;
44
45 i+=length+2;
46 }
47 // DQT
48 else if (((i+5) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDB)) {
49 int length = (fTo[i+2]<<8)|(fTo[i+3]);
50 LOG(DEBUG) << "DQT length:" << length;
51
52 unsigned int precision = (fTo[i+4]&0xf0)<<4;
53 unsigned int quantIdx = fTo[i+4]&0x0f;
54 unsigned int quantSize = 64*(precision+1);
55 if (quantSize*quantIdx+quantSize <= sizeof(m_qTable)) {
56 if ( (i+2+length) < frameSize) {
57 memcpy(m_qTable + quantSize*quantIdx, fTo + i + 5, length-3);
58 LOG(DEBUG) << "Quantization table idx:" << quantIdx << " precision:" << precision << " size:" << quantSize << " total size:" << m_qTableSize;
59 if (quantSize*quantIdx+quantSize > m_qTableSize) {
60 m_qTableSize = quantSize*quantIdx+quantSize;
61 }
62 }
63 }
64
65 i+=length+2;
66 }
67 // SOS
68 else if ( ((i+3) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDA) ) {
69 int length = (fTo[i+2]<<8)|(fTo[i+3]);
70 LOG(DEBUG) << "SOS length:" << length;
71
72 headerSize = i+length+2;
73 // DRI
74 } else if ( ((i+5) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDD) ) {
75 m_type |= 0x40;
76 int length = (fTo[i+2]<<8)|(fTo[i+3]);
77 m_restartInterval = (fTo[i+4]<<8)|(fTo[i+5]);
78 LOG(DEBUG) << "DRI restartInterval:" << m_restartInterval;
79 i+=length+2;
80 } else {
81 i++;
82 }
83 }
84
85 if (headerSize != 0) {
86 LOG(DEBUG) << "headerSize:" << headerSize;
87 fFrameSize = frameSize - headerSize;
88 memmove( fTo, fTo + headerSize, fFrameSize );
89 } else {
90 LOG(NOTICE) << "Bad header => dropping frame";
91 }
92
93 fNumTruncatedBytes = numTruncatedBytes;
94 fPresentationTime = presentationTime;
95 fDurationInMicroseconds = durationInMicroseconds;
96 afterGetting(this);
97}
98
99u_int8_t const* MJPEGVideoSource::quantizationTables( u_int8_t& precision, u_int16_t& length )
100{
101 length = 0;
102 precision = 0;
103 if (m_qTableSize > 0)
104 {
105 length = m_qTableSize;
106 precision = m_precision;
107 }
108 return m_qTable;
109}
110