| 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 |
| 27 | std::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 |
| 76 | std::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 |
| 127 | unsigned char* H26X_V4L2DeviceSource::(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 | |