| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // "liveMedia" |
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
| 18 | // H.265 Video RTP Sources |
| 19 | // Implementation |
| 20 | |
| 21 | #include "H265VideoRTPSource.hh" |
| 22 | |
| 23 | ////////// H265BufferedPacket and H265BufferedPacketFactory ////////// |
| 24 | |
| 25 | class H265BufferedPacket: public BufferedPacket { |
| 26 | public: |
| 27 | H265BufferedPacket(H265VideoRTPSource& ourSource); |
| 28 | virtual ~H265BufferedPacket(); |
| 29 | |
| 30 | private: // redefined virtual functions |
| 31 | virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr, |
| 32 | unsigned dataSize); |
| 33 | private: |
| 34 | H265VideoRTPSource& fOurSource; |
| 35 | }; |
| 36 | |
| 37 | class H265BufferedPacketFactory: public BufferedPacketFactory { |
| 38 | private: // redefined virtual functions |
| 39 | virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); |
| 40 | }; |
| 41 | |
| 42 | |
| 43 | ///////// H265VideoRTPSource implementation //////// |
| 44 | |
| 45 | H265VideoRTPSource* |
| 46 | H265VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, |
| 47 | unsigned char rtpPayloadFormat, |
| 48 | Boolean expectDONFields, |
| 49 | unsigned rtpTimestampFrequency) { |
| 50 | return new H265VideoRTPSource(env, RTPgs, rtpPayloadFormat, |
| 51 | expectDONFields, rtpTimestampFrequency); |
| 52 | } |
| 53 | |
| 54 | H265VideoRTPSource |
| 55 | ::H265VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, |
| 56 | unsigned char rtpPayloadFormat, |
| 57 | Boolean expectDONFields, |
| 58 | unsigned rtpTimestampFrequency) |
| 59 | : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, |
| 60 | new H265BufferedPacketFactory), |
| 61 | fExpectDONFields(expectDONFields), |
| 62 | fPreviousNALUnitDON(0), fCurrentNALUnitAbsDon((u_int64_t)(~0)) { |
| 63 | } |
| 64 | |
| 65 | H265VideoRTPSource::~H265VideoRTPSource() { |
| 66 | } |
| 67 | |
| 68 | Boolean H265VideoRTPSource |
| 69 | ::(BufferedPacket* packet, |
| 70 | unsigned& ) { |
| 71 | unsigned char* = packet->data(); |
| 72 | unsigned packetSize = packet->dataSize(); |
| 73 | u_int16_t DONL = 0; |
| 74 | unsigned numBytesToSkip; |
| 75 | |
| 76 | // Check the Payload Header's 'nal_unit_type' for special aggregation or fragmentation packets: |
| 77 | if (packetSize < 2) return False; |
| 78 | fCurPacketNALUnitType = (headerStart[0]&0x7E)>>1; |
| 79 | switch (fCurPacketNALUnitType) { |
| 80 | case 48: { // Aggregation Packet (AP) |
| 81 | // We skip over the 2-byte Payload Header, and the DONL header (if any). |
| 82 | if (fExpectDONFields) { |
| 83 | if (packetSize < 4) return False; |
| 84 | DONL = (headerStart[2]<<8)|headerStart[3]; |
| 85 | numBytesToSkip = 4; |
| 86 | } else { |
| 87 | numBytesToSkip = 2; |
| 88 | } |
| 89 | break; |
| 90 | } |
| 91 | case 49: { // Fragmentation Unit (FU) |
| 92 | // This NALU begins with the 2-byte Payload Header, the 1-byte FU header, and (optionally) |
| 93 | // the 2-byte DONL header. |
| 94 | // If the start bit is set, we reconstruct the original NAL header at the end of these |
| 95 | // 3 (or 5) bytes, and skip over the first 1 (or 3) bytes. |
| 96 | if (packetSize < 3) return False; |
| 97 | u_int8_t startBit = headerStart[2]&0x80; // from the FU header |
| 98 | u_int8_t endBit = headerStart[2]&0x40; // from the FU header |
| 99 | if (startBit) { |
| 100 | fCurrentPacketBeginsFrame = True; |
| 101 | |
| 102 | u_int8_t nal_unit_type = headerStart[2]&0x3F; // the last 6 bits of the FU header |
| 103 | u_int8_t [2]; |
| 104 | newNALHeader[0] = (headerStart[0]&0x81)|(nal_unit_type<<1); |
| 105 | newNALHeader[1] = headerStart[1]; |
| 106 | |
| 107 | if (fExpectDONFields) { |
| 108 | if (packetSize < 5) return False; |
| 109 | DONL = (headerStart[3]<<8)|headerStart[4]; |
| 110 | headerStart[3] = newNALHeader[0]; |
| 111 | headerStart[4] = newNALHeader[1]; |
| 112 | numBytesToSkip = 3; |
| 113 | } else { |
| 114 | headerStart[1] = newNALHeader[0]; |
| 115 | headerStart[2] = newNALHeader[1]; |
| 116 | numBytesToSkip = 1; |
| 117 | } |
| 118 | } else { |
| 119 | // The start bit is not set, so we skip over all headers: |
| 120 | fCurrentPacketBeginsFrame = False; |
| 121 | if (fExpectDONFields) { |
| 122 | if (packetSize < 5) return False; |
| 123 | DONL = (headerStart[3]<<8)|headerStart[4]; |
| 124 | numBytesToSkip = 5; |
| 125 | } else { |
| 126 | numBytesToSkip = 3; |
| 127 | } |
| 128 | } |
| 129 | fCurrentPacketCompletesFrame = (endBit != 0); |
| 130 | break; |
| 131 | } |
| 132 | default: { |
| 133 | // This packet contains one complete NAL unit: |
| 134 | fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame = True; |
| 135 | numBytesToSkip = 0; |
| 136 | break; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | computeAbsDonFromDON(DONL); |
| 141 | resultSpecialHeaderSize = numBytesToSkip; |
| 142 | return True; |
| 143 | } |
| 144 | |
| 145 | char const* H265VideoRTPSource::MIMEtype() const { |
| 146 | return "video/H265" ; |
| 147 | } |
| 148 | |
| 149 | void H265VideoRTPSource::computeAbsDonFromDON(u_int16_t DON) { |
| 150 | if (!fExpectDONFields) { |
| 151 | // Without DON fields in the input stream, we just increment our "AbsDon" count each time: |
| 152 | ++fCurrentNALUnitAbsDon; |
| 153 | } else { |
| 154 | if (fCurrentNALUnitAbsDon == (u_int64_t)(~0)) { |
| 155 | // This is the very first NAL unit, so "AbsDon" is just "DON": |
| 156 | fCurrentNALUnitAbsDon = (u_int64_t)DON; |
| 157 | } else { |
| 158 | // Use the previous NAL unit's DON and the current DON to compute "AbsDon": |
| 159 | // AbsDon[n] = AbsDon[n-1] + (DON[n] - DON[n-1]) mod 2^16 |
| 160 | short signedDiff16 = (short)(DON - fPreviousNALUnitDON); |
| 161 | int64_t signedDiff64 = (int64_t)signedDiff16; |
| 162 | fCurrentNALUnitAbsDon += signedDiff64; |
| 163 | } |
| 164 | |
| 165 | fPreviousNALUnitDON = DON; // for next time |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | |
| 170 | ////////// H265BufferedPacket and H265BufferedPacketFactory implementation ////////// |
| 171 | |
| 172 | H265BufferedPacket::H265BufferedPacket(H265VideoRTPSource& ourSource) |
| 173 | : fOurSource(ourSource) { |
| 174 | } |
| 175 | |
| 176 | H265BufferedPacket::~H265BufferedPacket() { |
| 177 | } |
| 178 | |
| 179 | unsigned H265BufferedPacket |
| 180 | ::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) { |
| 181 | unsigned resultNALUSize = 0; // if an error occurs |
| 182 | |
| 183 | switch (fOurSource.fCurPacketNALUnitType) { |
| 184 | case 48: { // Aggregation Packet (AP) |
| 185 | if (useCount() > 0) { |
| 186 | // We're other than the first NAL unit inside this Aggregation Packet. |
| 187 | // Update our 'decoding order number': |
| 188 | u_int16_t DONL = 0; |
| 189 | if (fOurSource.fExpectDONFields) { |
| 190 | // There's a 1-byte DOND field next: |
| 191 | if (dataSize < 1) break; |
| 192 | u_int8_t DOND = framePtr[0]; |
| 193 | DONL = fOurSource.fPreviousNALUnitDON + (u_int16_t)(DOND + 1); |
| 194 | ++framePtr; |
| 195 | --dataSize; |
| 196 | } |
| 197 | fOurSource.computeAbsDonFromDON(DONL); |
| 198 | } |
| 199 | |
| 200 | // The next 2 bytes are the NAL unit size: |
| 201 | if (dataSize < 2) break; |
| 202 | resultNALUSize = (framePtr[0]<<8)|framePtr[1]; |
| 203 | framePtr += 2; |
| 204 | break; |
| 205 | } |
| 206 | default: { |
| 207 | // Common case: We use the entire packet data: |
| 208 | return dataSize; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | return (resultNALUSize <= dataSize) ? resultNALUSize : dataSize; |
| 213 | } |
| 214 | |
| 215 | BufferedPacket* H265BufferedPacketFactory |
| 216 | ::createNewPacket(MultiFramedRTPSource* ourSource) { |
| 217 | return new H265BufferedPacket((H265VideoRTPSource&)(*ourSource)); |
| 218 | } |
| 219 | |