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 | // Raw Video RTP Sources (RFC 4175) |
19 | // Implementation |
20 | |
21 | #include "RawVideoRTPSource.hh" |
22 | |
23 | ////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory ////////// |
24 | |
25 | class RawVideoBufferedPacket: public BufferedPacket { |
26 | public: |
27 | RawVideoBufferedPacket(RawVideoRTPSource* ourSource); |
28 | virtual ~RawVideoBufferedPacket(); |
29 | |
30 | private: // redefined virtual functions |
31 | virtual void getNextEnclosedFrameParameters(unsigned char*& framePtr, |
32 | unsigned dataSize, |
33 | unsigned& frameSize, |
34 | unsigned& frameDurationInMicroseconds); |
35 | private: |
36 | RawVideoRTPSource* fOurSource; |
37 | }; |
38 | |
39 | class RawVideoBufferedPacketFactory: public BufferedPacketFactory { |
40 | private: // redefined virtual functions |
41 | virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource); |
42 | }; |
43 | |
44 | |
45 | ////////// LineHeader ////////// |
46 | |
47 | struct { |
48 | u_int16_t ; |
49 | u_int16_t fieldIdAndLineNumber; |
50 | u_int16_t ; |
51 | }; |
52 | |
53 | |
54 | ///////// RawVideoRTPSource implementation (RFC 4175) //////// |
55 | |
56 | RawVideoRTPSource* |
57 | RawVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs, |
58 | unsigned char rtpPayloadFormat, |
59 | unsigned rtpTimestampFrequency) { |
60 | return new RawVideoRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency); |
61 | } |
62 | |
63 | RawVideoRTPSource |
64 | ::RawVideoRTPSource(UsageEnvironment& env, Groupsock* RTPgs, |
65 | unsigned char rtpPayloadFormat, |
66 | unsigned rtpTimestampFrequency) |
67 | : MultiFramedRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, |
68 | new RawVideoBufferedPacketFactory), |
69 | fNumLines(0), fNextLine(0), fLineHeaders(NULL) { |
70 | } |
71 | |
72 | RawVideoRTPSource::~RawVideoRTPSource() { |
73 | delete[] fLineHeaders; |
74 | } |
75 | |
76 | u_int16_t RawVideoRTPSource::currentLineNumber() const { |
77 | if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! |
78 | return fLineHeaders[fNextLine-1].fieldIdAndLineNumber&0x7FFF; |
79 | } |
80 | |
81 | u_int8_t RawVideoRTPSource::currentLineFieldId() const { |
82 | if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! |
83 | return (fLineHeaders[fNextLine-1].fieldIdAndLineNumber&0x8000)>>15; |
84 | } |
85 | |
86 | u_int16_t RawVideoRTPSource::currentOffsetWithinLine() const { |
87 | if (fNextLine == 0 || fLineHeaders == NULL) return 0; // we've called this function too soon! |
88 | return fLineHeaders[fNextLine-1].offsetWithinLine; |
89 | } |
90 | |
91 | Boolean RawVideoRTPSource |
92 | ::(BufferedPacket* packet, |
93 | unsigned& ) { |
94 | |
95 | unsigned char* = packet->data(); |
96 | unsigned packetSize = packet->dataSize(); |
97 | |
98 | // The first 2 bytes of the header are the "Extended Sequence Number". |
99 | // In the current implementation, we ignore this. |
100 | if (packetSize < 2) return False; |
101 | headerStart += 2; |
102 | unsigned char* = headerStart; |
103 | packetSize -= 2; |
104 | |
105 | // The rest of the header should consist of N*6 bytes (with N >= 1) for each line included. |
106 | // Count how many of these there are: |
107 | unsigned numLines = 0; |
108 | while (1) { |
109 | if (packetSize < 6) return False; // there's not enough room for another line header |
110 | ++numLines; |
111 | Boolean continuationBit = (headerStart[4]&0x80)>>7; |
112 | headerStart += 6; |
113 | packetSize -= 6; |
114 | |
115 | // Check the "C" (continuation) bit of this header to see whether any more line headers follow: |
116 | if (continuationBit == 0) break; // no more line headers follow |
117 | } |
118 | |
119 | // We now know how many lines are contained in this payload. Allocate and fill in "fLineHeaders": |
120 | fNumLines = numLines; // ASSERT: >= 1 |
121 | fNextLine = 0; |
122 | delete[] fLineHeaders; fLineHeaders = new LineHeader[fNumLines]; |
123 | unsigned totalLength = 0; |
124 | for (unsigned i = 0; i < fNumLines; ++i) { |
125 | fLineHeaders[i].length = (lineHeaderStart[0]<<8) + lineHeaderStart[1]; |
126 | totalLength += fLineHeaders[i].length; |
127 | fLineHeaders[i].fieldIdAndLineNumber = (lineHeaderStart[2]<<8) + lineHeaderStart[3]; |
128 | fLineHeaders[i].offsetWithinLine = ((lineHeaderStart[4]&0x7F)<<8) + lineHeaderStart[5]; |
129 | lineHeaderStart += 6; |
130 | } |
131 | |
132 | // Make sure that we have enough bytes for all of the line lengths promised: |
133 | if (totalLength > packetSize) { |
134 | fNumLines = 0; |
135 | delete[] fLineHeaders; fLineHeaders = NULL; |
136 | return False; |
137 | } |
138 | |
139 | // Everything looks good: |
140 | fCurrentPacketBeginsFrame |
141 | = (fLineHeaders[0].fieldIdAndLineNumber&0x7FFF) == 0 && fLineHeaders[0].offsetWithinLine == 0; |
142 | fCurrentPacketCompletesFrame = packet->rtpMarkerBit(); |
143 | resultSpecialHeaderSize = headerStart - packet->data(); |
144 | return True; |
145 | } |
146 | |
147 | char const* RawVideoRTPSource::MIMEtype() const { |
148 | return "video/RAW" ; |
149 | } |
150 | |
151 | |
152 | ////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory implementation ////////// |
153 | |
154 | RawVideoBufferedPacket |
155 | ::RawVideoBufferedPacket(RawVideoRTPSource* ourSource) |
156 | : fOurSource(ourSource) { |
157 | } |
158 | |
159 | RawVideoBufferedPacket::~RawVideoBufferedPacket() { |
160 | } |
161 | |
162 | void RawVideoBufferedPacket::getNextEnclosedFrameParameters(unsigned char*& /*framePtr*/, |
163 | unsigned dataSize, |
164 | unsigned& frameSize, |
165 | unsigned& frameDurationInMicroseconds) { |
166 | frameDurationInMicroseconds = 0; // because all lines within the same packet are from the same frame |
167 | |
168 | if (fOurSource->fNextLine >= fOurSource->fNumLines) { |
169 | fOurSource->envir() << "RawVideoBufferedPacket::nextEnclosedFrameParameters(" |
170 | << dataSize << "): data error (" |
171 | << fOurSource->fNextLine << " >= " << fOurSource->fNumLines << ")!\n" ; |
172 | frameSize = dataSize; |
173 | return; |
174 | } |
175 | |
176 | frameSize = fOurSource->fLineHeaders[fOurSource->fNextLine++].length; |
177 | } |
178 | |
179 | BufferedPacket* RawVideoBufferedPacketFactory |
180 | ::createNewPacket(MultiFramedRTPSource* ourSource) { |
181 | return new RawVideoBufferedPacket((RawVideoRTPSource*)ourSource); |
182 | } |
183 | |