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.264 Video RTP Sources
19// Implementation
20
21#include "H264VideoRTPSource.hh"
22#include "Base64.hh"
23
24////////// H264BufferedPacket and H264BufferedPacketFactory //////////
25
26class H264BufferedPacket: public BufferedPacket {
27public:
28 H264BufferedPacket(H264VideoRTPSource& ourSource);
29 virtual ~H264BufferedPacket();
30
31private: // redefined virtual functions
32 virtual unsigned nextEnclosedFrameSize(unsigned char*& framePtr,
33 unsigned dataSize);
34private:
35 H264VideoRTPSource& fOurSource;
36};
37
38class H264BufferedPacketFactory: public BufferedPacketFactory {
39private: // redefined virtual functions
40 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
41};
42
43
44///////// H264VideoRTPSource implementation ////////
45
46H264VideoRTPSource*
47H264VideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
48 unsigned char rtpPayloadFormat,
49 unsigned rtpTimestampFrequency) {
50 return new H264VideoRTPSource(env, RTPgs, rtpPayloadFormat,
51 rtpTimestampFrequency);
52}
53
54H264VideoRTPSource
55::H264VideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs,
56 unsigned char rtpPayloadFormat,
57 unsigned rtpTimestampFrequency)
58 : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency,
59 new H264BufferedPacketFactory) {
60}
61
62H264VideoRTPSource::~H264VideoRTPSource() {
63}
64
65Boolean H264VideoRTPSource
66::processSpecialHeader(BufferedPacket* packet,
67 unsigned& resultSpecialHeaderSize) {
68 unsigned char* headerStart = packet->data();
69 unsigned packetSize = packet->dataSize();
70 unsigned numBytesToSkip;
71
72 // Check the 'nal_unit_type' for special 'aggregation' or 'fragmentation' packets:
73 if (packetSize < 1) return False;
74 fCurPacketNALUnitType = (headerStart[0]&0x1F);
75 switch (fCurPacketNALUnitType) {
76 case 24: { // STAP-A
77 numBytesToSkip = 1; // discard the type byte
78 break;
79 }
80 case 25: case 26: case 27: { // STAP-B, MTAP16, or MTAP24
81 numBytesToSkip = 3; // discard the type byte, and the initial DON
82 break;
83 }
84 case 28: case 29: { // // FU-A or FU-B
85 // For these NALUs, the first two bytes are the FU indicator and the FU header.
86 // If the start bit is set, we reconstruct the original NAL header into byte 1:
87 if (packetSize < 2) return False;
88 unsigned char startBit = headerStart[1]&0x80;
89 unsigned char endBit = headerStart[1]&0x40;
90 if (startBit) {
91 fCurrentPacketBeginsFrame = True;
92
93 headerStart[1] = (headerStart[0]&0xE0)|(headerStart[1]&0x1F);
94 numBytesToSkip = 1;
95 } else {
96 // The start bit is not set, so we skip both the FU indicator and header:
97 fCurrentPacketBeginsFrame = False;
98 numBytesToSkip = 2;
99 }
100 fCurrentPacketCompletesFrame = (endBit != 0);
101 break;
102 }
103 default: {
104 // This packet contains one complete NAL unit:
105 fCurrentPacketBeginsFrame = fCurrentPacketCompletesFrame = True;
106 numBytesToSkip = 0;
107 break;
108 }
109 }
110
111 resultSpecialHeaderSize = numBytesToSkip;
112 return True;
113}
114
115char const* H264VideoRTPSource::MIMEtype() const {
116 return "video/H264";
117}
118
119SPropRecord* parseSPropParameterSets(char const* sPropParameterSetsStr,
120 // result parameter:
121 unsigned& numSPropRecords) {
122 // Make a copy of the input string, so we can replace the commas with '\0's:
123 char* inStr = strDup(sPropParameterSetsStr);
124 if (inStr == NULL) {
125 numSPropRecords = 0;
126 return NULL;
127 }
128
129 // Count the number of commas (and thus the number of parameter sets):
130 numSPropRecords = 1;
131 char* s;
132 for (s = inStr; *s != '\0'; ++s) {
133 if (*s == ',') {
134 ++numSPropRecords;
135 *s = '\0';
136 }
137 }
138
139 // Allocate and fill in the result array:
140 SPropRecord* resultArray = new SPropRecord[numSPropRecords];
141 s = inStr;
142 for (unsigned i = 0; i < numSPropRecords; ++i) {
143 resultArray[i].sPropBytes = base64Decode(s, resultArray[i].sPropLength);
144 s += strlen(s) + 1;
145 }
146
147 delete[] inStr;
148 return resultArray;
149}
150
151
152////////// H264BufferedPacket and H264BufferedPacketFactory implementation //////////
153
154H264BufferedPacket::H264BufferedPacket(H264VideoRTPSource& ourSource)
155 : fOurSource(ourSource) {
156}
157
158H264BufferedPacket::~H264BufferedPacket() {
159}
160
161unsigned H264BufferedPacket
162::nextEnclosedFrameSize(unsigned char*& framePtr, unsigned dataSize) {
163 unsigned resultNALUSize = 0; // if an error occurs
164
165 switch (fOurSource.fCurPacketNALUnitType) {
166 case 24: case 25: { // STAP-A or STAP-B
167 // The first two bytes are NALU size:
168 if (dataSize < 2) break;
169 resultNALUSize = (framePtr[0]<<8)|framePtr[1];
170 framePtr += 2;
171 break;
172 }
173 case 26: { // MTAP16
174 // The first two bytes are NALU size. The next three are the DOND and TS offset:
175 if (dataSize < 5) break;
176 resultNALUSize = (framePtr[0]<<8)|framePtr[1];
177 framePtr += 5;
178 break;
179 }
180 case 27: { // MTAP24
181 // The first two bytes are NALU size. The next four are the DOND and TS offset:
182 if (dataSize < 6) break;
183 resultNALUSize = (framePtr[0]<<8)|framePtr[1];
184 framePtr += 6;
185 break;
186 }
187 default: {
188 // Common case: We use the entire packet data:
189 return dataSize;
190 }
191 }
192
193 return (resultNALUSize <= dataSize) ? resultNALUSize : dataSize;
194}
195
196BufferedPacket* H264BufferedPacketFactory
197::createNewPacket(MultiFramedRTPSource* ourSource) {
198 return new H264BufferedPacket((H264VideoRTPSource&)(*ourSource));
199}
200