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** H264_V4l2DeviceSource.cpp
7**
8** H264 V4L2 Live555 source
9**
10** -------------------------------------------------------------------------*/
11
12#include <sstream>
13
14// live555
15#include <Base64.hh>
16
17// project
18#include "logger.h"
19#include "H264_V4l2DeviceSource.h"
20
21// ---------------------------------
22// H264 V4L2 FramedSource
23// ---------------------------------
24
25
26// split packet in frames
27std::list< std::pair<unsigned char*,size_t> > H264_V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize)
28{
29 std::list< std::pair<unsigned char*,size_t> > frameList;
30
31 size_t bufSize = frameSize;
32 size_t size = 0;
33 int frameType = 0;
34 unsigned char* buffer = this->extractFrame(frame, bufSize, size, frameType);
35 while (buffer != NULL)
36 {
37 switch (frameType&0x1F)
38 {
39 case 7: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
40 case 8: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
41 case 5: LOG(INFO) << "IDR size:" << size << " bufSize:" << bufSize;
42 if (m_repeatConfig && !m_sps.empty() && !m_pps.empty())
43 {
44 frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_sps.c_str(), m_sps.size()));
45 frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_pps.c_str(), m_pps.size()));
46 }
47 break;
48 default:
49 break;
50 }
51
52 if (!m_sps.empty() && !m_pps.empty())
53 {
54 u_int32_t profile_level_id = 0;
55 if (m_sps.size() >= 4) profile_level_id = (((unsigned char)m_sps[1])<<16)|(((unsigned char)m_sps[2])<<8)|((unsigned char)m_sps[3]);
56
57 char* sps_base64 = base64Encode(m_sps.c_str(), m_sps.size());
58 char* pps_base64 = base64Encode(m_pps.c_str(), m_pps.size());
59
60 std::ostringstream os;
61 os << "profile-level-id=" << std::hex << std::setw(6) << std::setfill('0') << profile_level_id;
62 os << ";sprop-parameter-sets=" << sps_base64 <<"," << pps_base64;
63 m_auxLine.assign(os.str());
64
65 delete [] sps_base64;
66 delete [] pps_base64;
67 }
68 frameList.push_back(std::pair<unsigned char*,size_t>(buffer, size));
69
70 buffer = this->extractFrame(&buffer[size], bufSize, size, frameType);
71 }
72 return frameList;
73}
74
75// split packet in frames
76std::list< std::pair<unsigned char*,size_t> > H265_V4L2DeviceSource::splitFrames(unsigned char* frame, unsigned frameSize)
77{
78 std::list< std::pair<unsigned char*,size_t> > frameList;
79
80 size_t bufSize = frameSize;
81 size_t size = 0;
82 int frameType = 0;
83 unsigned char* buffer = this->extractFrame(frame, bufSize, size, frameType);
84 while (buffer != NULL)
85 {
86 switch ((frameType&0x7E)>>1)
87 {
88 case 32: LOG(INFO) << "VPS size:" << size << " bufSize:" << bufSize; m_vps.assign((char*)buffer,size); break;
89 case 33: LOG(INFO) << "SPS size:" << size << " bufSize:" << bufSize; m_sps.assign((char*)buffer,size); break;
90 case 34: LOG(INFO) << "PPS size:" << size << " bufSize:" << bufSize; m_pps.assign((char*)buffer,size); break;
91 case 19:
92 case 20: LOG(INFO) << "IDR size:" << size << " bufSize:" << bufSize;
93 if (m_repeatConfig && !m_vps.empty() && !m_sps.empty() && !m_pps.empty())
94 {
95 frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_vps.c_str(), m_vps.size()));
96 frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_sps.c_str(), m_sps.size()));
97 frameList.push_back(std::pair<unsigned char*,size_t>((unsigned char*)m_pps.c_str(), m_pps.size()));
98 }
99 break;
100 default: break;
101 }
102
103 if (!m_vps.empty() && !m_sps.empty() && !m_pps.empty())
104 {
105 char* vps_base64 = base64Encode(m_vps.c_str(), m_vps.size());
106 char* sps_base64 = base64Encode(m_sps.c_str(), m_sps.size());
107 char* pps_base64 = base64Encode(m_pps.c_str(), m_pps.size());
108
109 std::ostringstream os;
110 os << "sprop-vps=" << vps_base64;
111 os << ";sprop-sps=" << sps_base64;
112 os << ";sprop-pps=" << pps_base64;
113 m_auxLine.assign(os.str());
114
115 delete [] vps_base64;
116 delete [] sps_base64;
117 delete [] pps_base64;
118 }
119 frameList.push_back(std::pair<unsigned char*,size_t>(buffer, size));
120
121 buffer = this->extractFrame(&buffer[size], bufSize, size, frameType);
122 }
123 return frameList;
124}
125
126// extract a frame
127unsigned char* H26X_V4L2DeviceSource::extractFrame(unsigned char* frame, size_t& size, size_t& outsize, int& frameType)
128{
129 unsigned char * outFrame = NULL;
130 outsize = 0;
131 unsigned int markerlength = 0;
132 frameType = 0;
133
134 unsigned char *startFrame = (unsigned char*)memmem(frame,size,H264marker,sizeof(H264marker));
135 if (startFrame != NULL) {
136 markerlength = sizeof(H264marker);
137 } else {
138 startFrame = (unsigned char*)memmem(frame,size,H264shortmarker,sizeof(H264shortmarker));
139 if (startFrame != NULL) {
140 markerlength = sizeof(H264shortmarker);
141 }
142 }
143 if (startFrame != NULL) {
144 frameType = startFrame[markerlength];
145
146 int remainingSize = size-(startFrame-frame+markerlength);
147 unsigned char *endFrame = (unsigned char*)memmem(&startFrame[markerlength], remainingSize, H264marker, sizeof(H264marker));
148 if (endFrame == NULL) {
149 endFrame = (unsigned char*)memmem(&startFrame[markerlength], remainingSize, H264shortmarker, sizeof(H264shortmarker));
150 }
151
152 if (m_keepMarker)
153 {
154 size -= startFrame-frame;
155 outFrame = startFrame;
156 }
157 else
158 {
159 size -= startFrame-frame+markerlength;
160 outFrame = &startFrame[markerlength];
161 }
162
163 if (endFrame != NULL)
164 {
165 outsize = endFrame - outFrame;
166 }
167 else
168 {
169 outsize = size;
170 }
171 size -= outsize;
172 } else if (size>= sizeof(H264shortmarker)) {
173 LOG(INFO) << "No marker found";
174 }
175
176 return outFrame;
177}
178
179