Fixed DevStudio 2005 build.
[opal.git] / src / codec / rfc4175.cxx
blobd9f08365f9e4b1c9cadf90575e067b9030c5bd34
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.8 2007/09/09 23:44:15 rjongbloed
28 * Fixed payload type and encoding name
30 * Revision 1.7 2007/08/29 00:46:13 csoutheren
31 * Change base class for RFC4175 transcoder
33 * Revision 1.6 2007/08/03 07:21:02 csoutheren
34 * Remove warnings
36 * Revision 1.5 2007/07/05 06:36:22 rjongbloed
37 * Fixed MSVC compiler warning.
39 * Revision 1.4 2007/07/05 06:25:13 rjongbloed
40 * Fixed GNU compiler warnings.
42 * Revision 1.3 2007/06/30 14:00:05 dsandras
43 * Fixed previous commit so that things at least compile. Untested.
45 * Revision 1.2 2007/06/29 23:24:25 csoutheren
46 * More RFC4175 implementation
48 * Revision 1.1 2007/05/31 14:11:45 csoutheren
49 * Add initial support for RFC 4175 uncompressed video encoding
53 #include <ptlib.h>
55 #include <ptclib/random.h>
57 #include <opal/buildopts.h>
59 #if OPAL_RFC4175
61 #include <codec/rfc4175.h>
62 #include <codec/opalplugin.h>
64 namespace PWLibStupidLinkerHacks {
65 int rfc4175Loader;
68 OPAL_REGISTER_RFC4175_VIDEO(RGB24)
69 OPAL_REGISTER_RFC4175_VIDEO(YUV420P)
71 #define FRAME_WIDTH 1920
72 #define FRAME_HEIGHT 1080
73 #define FRAME_RATE 60
75 #define REASONABLE_UDP_PACKET_SIZE 1000
77 const OpalVideoFormat & GetOpalRFC4175_YUV420P()
79 static const OpalVideoFormat RFC4175YUV420P(
80 OPAL_RFC4175_YUV420P,
81 RTP_DataFrame::DynamicBase,
82 "raw",
83 FRAME_WIDTH, FRAME_HEIGHT,
84 FRAME_RATE,
85 0xffffffff //12*FRAME_WIDTH*FRAME_HEIGHT*FRAME_RATE // Bandwidth
87 return RFC4175YUV420P;
90 const OpalVideoFormat & GetOpalRFC4175_RGB24()
92 static const OpalVideoFormat RFC4175RGB24(
93 OPAL_RFC4175_RGB24,
94 RTP_DataFrame::DynamicBase,
95 "raw",
96 32767, 32767,
97 FRAME_RATE,
98 0xffffffff //24*FRAME_WIDTH*FRAME_HEIGHT*FRAME_RATE // Bandwidth
100 return RFC4175RGB24;
103 /////////////////////////////////////////////////////////////////////////////
105 OpalRFC4175Transcoder::OpalRFC4175Transcoder(
106 const OpalMediaFormat & inputMediaFormat, ///< Input media format
107 const OpalMediaFormat & outputMediaFormat ///< Output media format
109 : OpalUncompVideoTranscoder(inputMediaFormat, outputMediaFormat)
113 PINDEX OpalRFC4175Transcoder::RFC4175HeaderSize(PINDEX lines)
114 { return 2 + lines*6; }
116 /////////////////////////////////////////////////////////////////////////////
118 OpalRFC4175Encoder::OpalRFC4175Encoder(
119 const OpalMediaFormat & inputMediaFormat, ///< Input media format
120 const OpalMediaFormat & outputMediaFormat ///< Output media format
121 ) : OpalRFC4175Transcoder(inputMediaFormat, outputMediaFormat)
123 extendedSequenceNumber = PRandom::Number();
126 BOOL OpalRFC4175Encoder::ConvertFrames(const RTP_DataFrame & input, RTP_DataFrameList & output)
128 // make sure the incoming frame is big enough for a frame header
129 if (input.GetPayloadSize() < (int)(sizeof(PluginCodec_Video_FrameHeader))) {
130 PTRACE(1,"RFC4175\tPayload of grabbed frame too small for frame header");
131 return FALSE;
134 PluginCodec_Video_FrameHeader * header = (PluginCodec_Video_FrameHeader *)input.GetPayloadPtr();
135 if (header->x != 0 && header->y != 0) {
136 PTRACE(1,"RFC4175\tVideo grab of partial frame unsupported");
137 return FALSE;
140 // get information from frame header
141 PINDEX frameHeight = header->height;
142 PINDEX frameWidth = header->width;
143 PINDEX frameWidthInBytes = PixelsToBytes(frameWidth);
145 // make sure the incoming frame is big enough for the specified frame size
146 if (input.GetPayloadSize() < (int)(sizeof(PluginCodec_Video_FrameHeader) + frameHeight*frameWidthInBytes)) {
147 PTRACE(1,"RFC4175\tPayload of grabbed frame too small for full frame");
148 return FALSE;
151 // calculate how many scan lines will fit in a reasonable UDP packet
152 PINDEX linesPerPacket = REASONABLE_UDP_PACKET_SIZE / frameWidthInBytes;
154 // if a scan line is longer than a reasonable packet, then return error for now
155 if (linesPerPacket <= 0) {
156 PTRACE(1,"RFC4175\tframe width too large");
157 return FALSE;
160 // encode the scan lines
161 PINDEX y = 0;
162 while (y < frameHeight) {
164 // allocate a new output frame
165 RTP_DataFrame * frame = new RTP_DataFrame;
166 output.Append(frame);
168 // populate RTP fields
169 frame->SetTimestamp(input.GetTimestamp());
170 frame->SetSequenceNumber((WORD)(extendedSequenceNumber & 0xffff));
172 // calculate number of scanlines in this packet
173 PINDEX lineCount = PMIN(linesPerPacket, frameHeight-y);
175 // set size of the packet
176 frame->SetPayloadSize(RFC4175HeaderSize(lineCount) + lineCount*frameWidthInBytes);
178 // populate extended sequence number
179 *(PUInt16b *)frame->GetPayloadPtr() = (WORD)(extendedSequenceNumber >> 16);
181 // initialise scan table
182 BYTE * ptr = frame->GetPayloadPtr() + 2;
183 PINDEX j;
184 PINDEX offset = 0;
185 for (j = 0; j < lineCount; ++j) {
187 // scan line length
188 *(PUInt16b *)ptr = (WORD)(PixelsToBytes(frameWidth));
189 ptr += 2;
191 // line number + field flag
192 *(PUInt16b *)ptr = (WORD)((y+j) & 0x7fff);
193 ptr += 2;
195 // pixel offset of scanline start
196 *(PUInt16b *)ptr = (WORD)PixelsToBytes(offset) & ((j == (lineCount-1)) ? 0x8000 : 0x0000);
197 ptr += 2;
199 // move to next scan line
200 offset += frameWidth;
203 // copy scan line data
204 memcpy(ptr, OPAL_VIDEO_FRAME_DATA_PTR(header)+y*frameWidthInBytes, lineCount*frameWidthInBytes);
206 // move to next block of scan lines
207 y += lineCount;
209 // increment sequence number
210 ++extendedSequenceNumber;
213 // set marker bit in last packet, if any packets created
214 if (output.GetSize() > 0)
215 output[output.GetSize()-1].SetMarker(TRUE);
217 return FALSE;
220 /////////////////////////////////////////////////////////////////////////////
222 OpalRFC4175Decoder::OpalRFC4175Decoder(
223 const OpalMediaFormat & inputMediaFormat, ///< Input media format
224 const OpalMediaFormat & outputMediaFormat ///< Output media format
225 ) : OpalRFC4175Transcoder(inputMediaFormat, outputMediaFormat)
227 Initialise();
230 BOOL OpalRFC4175Decoder::ConvertFrames(const RTP_DataFrame & input, RTP_DataFrameList & /*output*/)
232 if (input.GetPayloadSize() < 8) {
233 PTRACE(1,"RFC4175\tinput frame too small for header");
234 return FALSE;
237 // get pointer to scanline table
238 BYTE * ptr = input.GetPayloadPtr() + 2;
240 BOOL lastLine = FALSE;
241 PINDEX firstLineLength = 0;
242 BOOL firstLine = TRUE;
243 PINDEX lineCount = 0;
244 PINDEX maxLineNumber = 0;
246 do {
248 // ensure there is enough payload for this header
249 if ((2 + ((lineCount+1)*6)) >= input.GetPayloadSize()) {
250 PTRACE(1,"RFC4175\tinput frame too small for scan line table");
251 return FALSE;
254 // scan line length
255 PINDEX lineLength = BytesToPixels(*(PUInt16b *)ptr);
256 ptr += 2;
258 // line number
259 WORD lineNumber = ((*(PUInt16b *)ptr) & 0x7fff);
260 ptr += 2;
262 // pixel offset of scanline start
263 WORD offset = *(PUInt16b *)ptr;
264 ptr += 2;
266 // detect if last scanline in table
267 if (offset & 0x8000) {
268 lastLine = TRUE;
269 offset &= 0x7fff;
272 // we don't handle partial lines or variable length lines
273 if (offset != 0) {
274 PTRACE(1,"RFC4175\tpartial lines not supported");
275 return FALSE;
276 } else if (firstLine) {
277 firstLineLength = lineLength;
278 firstLine = FALSE;
279 } else if (lineLength != firstLineLength) {
280 PTRACE(1,"RFC4175\tline length changed during frame");
281 return FALSE;
284 // keep track of max line number
285 if (lineNumber > maxLineNumber)
286 maxLineNumber = lineNumber;
288 // count lines
289 ++lineCount;
291 } while (!lastLine);
293 // if this is the first frame, allocate the destination frame
294 if (firstFrame) {
297 return FALSE;
300 BOOL OpalRFC4175Decoder::Initialise()
302 firstFrame = TRUE;
303 width = 0;
304 maxY = 0;
305 return TRUE;
308 #endif // OPAL_RFC4175