Fixed MSVC compiler warning.
[opal.git] / src / codec / rfc4175.cxx
blobceb6725ead295f1d6ff9bab493cb514558f0e1a6
1 /*
2 * rfc4175.cxx
4 * RFC4175 transport for uncompressed video
6 * Open Phone Abstraction Library
8 * Copyright (C) 2007 Post Increment
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open Phone Abstraction Library.
22 * The Initial Developer of the Original Code is Post Increment
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.5 2007/07/05 06:36:22 rjongbloed
28 * Fixed MSVC compiler warning.
30 * Revision 1.4 2007/07/05 06:25:13 rjongbloed
31 * Fixed GNU compiler warnings.
33 * Revision 1.3 2007/06/30 14:00:05 dsandras
34 * Fixed previous commit so that things at least compile. Untested.
36 * Revision 1.2 2007/06/29 23:24:25 csoutheren
37 * More RFC4175 implementation
39 * Revision 1.1 2007/05/31 14:11:45 csoutheren
40 * Add initial support for RFC 4175 uncompressed video encoding
44 #include <ptlib.h>
46 #include <ptclib/random.h>
48 #include <opal/buildopts.h>
50 #if OPAL_RFC4175
52 #include <codec/rfc4175.h>
53 #include <codec/opalplugin.h>
55 namespace PWLibStupidLinkerHacks {
56 int rfc4175Loader;
59 OPAL_REGISTER_RFC4175_VIDEO(RGB24)
60 OPAL_REGISTER_RFC4175_VIDEO(YUV420P)
62 #define FRAME_WIDTH 1920
63 #define FRAME_HEIGHT 1080
64 #define FRAME_RATE 60
66 #define REASONABLE_UDP_PACKET_SIZE 1000
68 const OpalVideoFormat & GetOpalRFC4175_YUV420P()
70 static const OpalVideoFormat RFC4175YUV420P(
71 OPAL_RFC4175_YUV420P,
72 RTP_DataFrame::MaxPayloadType,
73 OPAL_RFC4175_YUV420P,
74 FRAME_WIDTH, FRAME_HEIGHT,
75 FRAME_RATE,
76 0xffffffff //12*FRAME_WIDTH*FRAME_HEIGHT*FRAME_RATE // Bandwidth
78 return RFC4175YUV420P;
81 const OpalVideoFormat & GetOpalRFC4175_RGB24()
83 static const OpalVideoFormat RFC4175RGB24(
84 OPAL_RFC4175_RGB24,
85 RTP_DataFrame::MaxPayloadType,
86 OPAL_RFC4175_RGB24,
87 32767, 32767,
88 FRAME_RATE,
89 0xffffffff //24*FRAME_WIDTH*FRAME_HEIGHT*FRAME_RATE // Bandwidth
91 return RFC4175RGB24;
94 /////////////////////////////////////////////////////////////////////////////
96 OpalRFC4175Transcoder::OpalRFC4175Transcoder(
97 const OpalMediaFormat & inputMediaFormat, ///< Input media format
98 const OpalMediaFormat & outputMediaFormat ///< Output media format
100 : OpalVideoTranscoder(inputMediaFormat, outputMediaFormat)
104 PINDEX OpalRFC4175Transcoder::RFC4175HeaderSize(PINDEX lines)
105 { return 2 + lines*6; }
107 PINDEX OpalRFC4175Transcoder::GetOptimalDataFrameSize(BOOL /*input*/) const
109 return 0;
112 /////////////////////////////////////////////////////////////////////////////
114 OpalRFC4175Encoder::OpalRFC4175Encoder(
115 const OpalMediaFormat & inputMediaFormat, ///< Input media format
116 const OpalMediaFormat & outputMediaFormat ///< Output media format
117 ) : OpalRFC4175Transcoder(inputMediaFormat, outputMediaFormat)
119 extendedSequenceNumber = PRandom::Number();
122 BOOL OpalRFC4175Encoder::ConvertFrames(const RTP_DataFrame & input, RTP_DataFrameList & output)
124 // make sure the incoming frame is big enough for a frame header
125 if (input.GetPayloadSize() < (int)(sizeof(PluginCodec_Video_FrameHeader))) {
126 PTRACE(1,"RFC4175\tPayload of grabbed frame too small for frame header");
127 return FALSE;
130 PluginCodec_Video_FrameHeader * header = (PluginCodec_Video_FrameHeader *)input.GetPayloadPtr();
131 if (header->x != 0 && header->y != 0) {
132 PTRACE(1,"RFC4175\tVideo grab of partial frame unsupported");
133 return FALSE;
136 // get information from frame header
137 PINDEX frameHeight = header->height;
138 PINDEX frameWidth = header->width;
139 PINDEX frameWidthInBytes = PixelsToBytes(frameWidth);
141 // make sure the incoming frame is big enough for the specified frame size
142 if (input.GetPayloadSize() < (int)(sizeof(PluginCodec_Video_FrameHeader) + frameHeight*frameWidthInBytes)) {
143 PTRACE(1,"RFC4175\tPayload of grabbed frame too small for full frame");
144 return FALSE;
147 // calculate how many scan lines will fit in a reasonable UDP packet
148 PINDEX linesPerPacket = REASONABLE_UDP_PACKET_SIZE / frameWidthInBytes;
150 // if a scan line is longer than a reasonable packet, then return error for now
151 if (linesPerPacket <= 0) {
152 PTRACE(1,"RFC4175\tframe width too large");
153 return FALSE;
156 // encode the scan lines
157 PINDEX y = 0;
158 while (y < frameHeight) {
160 // allocate a new output frame
161 RTP_DataFrame * frame = new RTP_DataFrame;
162 output.Append(frame);
164 // populate RTP fields
165 frame->SetTimestamp(input.GetTimestamp());
166 frame->SetSequenceNumber((WORD)(extendedSequenceNumber & 0xffff));
168 // calculate number of scanlines in this packet
169 PINDEX lineCount = PMIN(linesPerPacket, frameHeight-y);
171 // set size of the packet
172 frame->SetPayloadSize(RFC4175HeaderSize(lineCount) + lineCount*frameWidthInBytes);
174 // populate extended sequence number
175 *(PUInt16b *)frame->GetPayloadPtr() = (WORD)(extendedSequenceNumber >> 16);
177 // initialise scan table
178 BYTE * ptr = frame->GetPayloadPtr() + 2;
179 PINDEX j;
180 PINDEX offset = 0;
181 for (j = 0; j < lineCount; ++j) {
183 // scan line length
184 *(PUInt16b *)ptr = (WORD)(PixelsToBytes(frameWidth));
185 ptr += 2;
187 // line number + field flag
188 *(PUInt16b *)ptr = (WORD)((y+j) & 0x7fff);
189 ptr += 2;
191 // pixel offset of scanline start
192 *(PUInt16b *)ptr = (WORD)PixelsToBytes(offset) & ((j == (lineCount-1)) ? 0x8000 : 0x0000);
193 ptr += 2;
195 // move to next scan line
196 offset += frameWidth;
199 // copy scan line data
200 memcpy(ptr, OPAL_VIDEO_FRAME_DATA_PTR(header)+y*frameWidthInBytes, lineCount*frameWidthInBytes);
202 // move to next block of scan lines
203 y += lineCount;
205 // increment sequence number
206 ++extendedSequenceNumber;
209 // set marker bit in last packet, if any packets created
210 if (output.GetSize() > 0)
211 output[output.GetSize()-1].SetMarker(TRUE);
213 return FALSE;
216 /////////////////////////////////////////////////////////////////////////////
218 OpalRFC4175Decoder::OpalRFC4175Decoder(
219 const OpalMediaFormat & inputMediaFormat, ///< Input media format
220 const OpalMediaFormat & outputMediaFormat ///< Output media format
221 ) : OpalRFC4175Transcoder(inputMediaFormat, outputMediaFormat)
223 Initialise();
226 BOOL OpalRFC4175Decoder::ConvertFrames(const RTP_DataFrame & input, RTP_DataFrameList & output)
228 if (input.GetPayloadSize() < 8) {
229 PTRACE(1,"RFC4175\tinput frame too small for header");
230 return FALSE;
233 // get pointer to scanline table
234 BYTE * ptr = input.GetPayloadPtr() + 2;
236 BOOL lastLine = FALSE;
237 PINDEX firstLineLength = 0;
238 BOOL firstLine = TRUE;
239 PINDEX lineCount = 0;
240 PINDEX maxLineNumber = 0;
242 do {
244 // ensure there is enough payload for this header
245 if ((2 + ((lineCount+1)*6)) >= input.GetPayloadSize()) {
246 PTRACE(1,"RFC4175\tinput frame too small for scan line table");
247 return FALSE;
250 // scan line length
251 PINDEX lineLength = BytesToPixels(*(PUInt16b *)ptr);
252 ptr += 2;
254 // line number
255 WORD lineNumber = ((*(PUInt16b *)ptr) & 0x7fff);
256 ptr += 2;
258 // pixel offset of scanline start
259 WORD offset = *(PUInt16b *)ptr;
260 ptr += 2;
262 // detect if last scanline in table
263 if (offset & 0x8000) {
264 lastLine = TRUE;
265 offset &= 0x7fff;
268 // we don't handle partial lines or variable length lines
269 if (offset != 0) {
270 PTRACE(1,"RFC4175\tpartial lines not supported");
271 return FALSE;
272 } else if (firstLine) {
273 firstLineLength = lineLength;
274 firstLine = FALSE;
275 } else if (lineLength != firstLineLength) {
276 PTRACE(1,"RFC4175\tline length changed during frame");
277 return FALSE;
280 // keep track of max line number
281 if (lineNumber > maxLineNumber)
282 maxLineNumber = lineNumber;
284 // count lines
285 ++lineCount;
287 } while (!lastLine);
289 // if this is the first frame, allocate the destination frame
290 if (firstFrame) {
294 return FALSE;
297 BOOL OpalRFC4175Decoder::Initialise()
299 firstFrame = TRUE;
300 width = 0;
301 maxY = 0;
302 return TRUE;
305 #endif // OPAL_RFC4175