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// Raw Video RTP Sources (RFC 4175)
19// Implementation
20
21#include "RawVideoRTPSource.hh"
22
23////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory //////////
24
25class RawVideoBufferedPacket: public BufferedPacket {
26public:
27 RawVideoBufferedPacket(RawVideoRTPSource* ourSource);
28 virtual ~RawVideoBufferedPacket();
29
30private: // redefined virtual functions
31 virtual void getNextEnclosedFrameParameters(unsigned char*& framePtr,
32 unsigned dataSize,
33 unsigned& frameSize,
34 unsigned& frameDurationInMicroseconds);
35private:
36 RawVideoRTPSource* fOurSource;
37};
38
39class RawVideoBufferedPacketFactory: public BufferedPacketFactory {
40private: // redefined virtual functions
41 virtual BufferedPacket* createNewPacket(MultiFramedRTPSource* ourSource);
42};
43
44
45////////// LineHeader //////////
46
47struct LineHeader {
48 u_int16_t length;
49 u_int16_t fieldIdAndLineNumber;
50 u_int16_t offsetWithinLine;
51};
52
53
54///////// RawVideoRTPSource implementation (RFC 4175) ////////
55
56RawVideoRTPSource*
57RawVideoRTPSource::createNew(UsageEnvironment& env, Groupsock* RTPgs,
58 unsigned char rtpPayloadFormat,
59 unsigned rtpTimestampFrequency) {
60 return new RawVideoRTPSource(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency);
61}
62
63RawVideoRTPSource
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
72RawVideoRTPSource::~RawVideoRTPSource() {
73 delete[] fLineHeaders;
74}
75
76u_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
81u_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
86u_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
91Boolean RawVideoRTPSource
92::processSpecialHeader(BufferedPacket* packet,
93 unsigned& resultSpecialHeaderSize) {
94
95 unsigned char* headerStart = 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* lineHeaderStart = 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
147char const* RawVideoRTPSource::MIMEtype() const {
148 return "video/RAW";
149}
150
151
152////////// RawVideoBufferedPacket and RawVideoBufferedPacketFactory implementation //////////
153
154RawVideoBufferedPacket
155::RawVideoBufferedPacket(RawVideoRTPSource* ourSource)
156 : fOurSource(ourSource) {
157}
158
159RawVideoBufferedPacket::~RawVideoBufferedPacket() {
160}
161
162void 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
179BufferedPacket* RawVideoBufferedPacketFactory
180::createNewPacket(MultiFramedRTPSource* ourSource) {
181 return new RawVideoBufferedPacket((RawVideoRTPSource*)ourSource);
182}
183