1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 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
25class H265BufferedPacket: public BufferedPacket {
26public:
27 H265BufferedPacket(H265VideoRTPSource& ourSource);
28 virtual ~H265BufferedPacket();
29
30private: // redefined virtual functions
31 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
32 unsigned dataSize);
33private:
34 H265VideoRTPSource& fOurSource;
35};
36
37class H265BufferedPacketFactory: public BufferedPacketFactory {
38private: // redefined virtual functions
39 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
40};
41
42
43///////// H265VideoRTPSource implementation ////////
44
45H265VideoRTPSource*
46H265VideoRTPSource::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
54H265VideoRTPSource
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
65H265VideoRTPSource::~H265VideoRTPSource() {
66}
67
68Boolean H265VideoRTPSource
69::processSpecialHeader(BufferedPacket* packet,
70 unsigned& resultSpecialHeaderSize) {
71 unsigned char* headerStart = 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 newNALHeader[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
145char const* H265VideoRTPSource::MIMEtype() const {
146 return "video/H265";
147}
148
149void 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
172H265BufferedPacket::H265BufferedPacket(H265VideoRTPSource& ourSource)
173 : fOurSource(ourSource) {
174}
175
176H265BufferedPacket::~H265BufferedPacket() {
177}
178
179unsigned 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
215BufferedPacket* H265BufferedPacketFactory
216::createNewPacket(MultiFramedRTPSource* ourSource) {
217 return new H265BufferedPacket((H265VideoRTPSource&)(*ourSource));
218}
219