1 // Copyright (C)2004 Landmark Graphics Corporation
2 // Copyright (C)2005-2007 Sun Microsystems, Inc.
3 // Copyright (C)2009-2012, 2014, 2017-2020 D. R. Commander
4 //
5 // This library is free software and may be redistributed and/or modified under
6 // the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 // any later version.  The full license is in the LICENSE.txt file included
8 // with this distribution.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // wxWindows Library License for more details.
14 
15 #include "Log.h"
16 #include "Error.h"
17 #include "vglutil.h"
18 #include <string.h>
19 #include "vgllogo.h"
20 #include "Frame.h"
21 
22 using namespace vglutil;
23 using namespace vglcommon;
24 
25 
26 #define TJSUBSAMP(s) \
27 	(s >= 4 ? TJ_420 : \
28 		(s == 2 ? TJ_422 : \
29 			(s == 1 ? TJ_444 : \
30 				(s == 0 ? TJ_GRAYSCALE : TJ_444))))
31 
32 static int tjpf[PIXELFORMATS] =
33 {
34 	TJPF_RGB, TJPF_RGBX, -1, TJPF_BGR, TJPF_BGRX, -1, TJPF_XBGR, -1, TJPF_XRGB,
35 	-1, TJPF_GRAY
36 };
37 
38 
39 // Uncompressed frame
40 
Frame(bool primary_)41 Frame::Frame(bool primary_) : bits(NULL), rbits(NULL), pitch(0), flags(0),
42 	pf(pf_get(-1)), isGL(false), isXV(false), stereo(false), primary(primary_)
43 {
44 	memset(&hdr, 0, sizeof(rrframeheader));
45 	ready.wait();
46 }
47 
48 
~Frame(void)49 Frame::~Frame(void)
50 {
51 	deInit();
52 }
53 
54 
deInit(void)55 void Frame::deInit(void)
56 {
57 	if(primary)
58 	{
59 		delete [] bits;  bits = NULL;
60 		delete [] rbits;  rbits = NULL;
61 	}
62 }
63 
64 
init(rrframeheader & h,int pixelFormat,int flags_,bool stereo_)65 void Frame::init(rrframeheader &h, int pixelFormat, int flags_, bool stereo_)
66 {
67 	if(pixelFormat < 0 || pixelFormat >= PIXELFORMATS)
68 		throw(Error("Frame::init", "Invalid argument"));
69 
70 	flags = flags_;
71 	PF *newpf = pf_get(pixelFormat);
72 	if(h.size == 0) h.size = h.framew * h.frameh * newpf->size;
73 	checkHeader(h);
74 	if(h.framew != hdr.framew || h.frameh != hdr.frameh
75 		|| newpf->size != pf->size || !bits)
76 	{
77 		delete [] bits;
78 		bits = new unsigned char[h.framew * h.frameh * newpf->size + 1];
79 	}
80 	if(stereo_)
81 	{
82 		if(h.framew != hdr.framew || h.frameh != hdr.frameh
83 			|| newpf->size != pf->size || !rbits)
84 		{
85 			delete [] rbits;
86 			rbits = new unsigned char[h.framew * h.frameh * newpf->size + 1];
87 		}
88 	}
89 	else
90 	{
91 		delete [] rbits;  rbits = NULL;
92 	}
93 	pf = newpf;  pitch = pf->size * h.framew;  stereo = stereo_;  hdr = h;
94 }
95 
96 
init(unsigned char * bits_,int width,int pitch_,int height,int pixelFormat,int flags_)97 void Frame::init(unsigned char *bits_, int width, int pitch_, int height,
98 	int pixelFormat, int flags_)
99 {
100 	if(!bits_ || width < 1 || pitch_ < 1 || height < 1 || pixelFormat < 0
101 		|| pixelFormat >= PIXELFORMATS)
102 		THROW("Invalid argument");
103 
104 	bits = bits_;
105 	hdr.x = hdr.y = 0;
106 	hdr.framew = hdr.width = width;
107 	hdr.frameh = hdr.height = height;
108 	pf = pf_get(pixelFormat);
109 	hdr.size = hdr.framew * hdr.frameh * pf->size;
110 	checkHeader(hdr);
111 	pitch = pitch_;
112 	flags = flags_;
113 	primary = false;
114 }
115 
116 
getTile(int x,int y,int width,int height)117 Frame *Frame::getTile(int x, int y, int width, int height)
118 {
119 	Frame *f;
120 
121 	if(!bits || !pitch || !pf->size) THROW("Frame not initialized");
122 	if(x < 0 || y < 0 || width < 1 || height < 1 || (x + width) > hdr.width
123 		|| (y + height) > hdr.height)
124 		throw Error("Frame::getTile", "Argument out of range");
125 
126 	f = new Frame(false);
127 	f->hdr = hdr;
128 	f->hdr.x = x;
129 	f->hdr.y = y;
130 	f->hdr.width = width;
131 	f->hdr.height = height;
132 	f->pf = pf;
133 	f->flags = flags;
134 	f->pitch = pitch;
135 	f->stereo = stereo;
136 	f->isGL = isGL;
137 	bool bu = (flags & FRAME_BOTTOMUP);
138 	f->bits = &bits[pitch * (bu ? hdr.height - y - height : y) + pf->size * x];
139 	if(stereo && rbits)
140 		f->rbits =
141 			&rbits[pitch * (bu ? hdr.height - y - height : y) + pf->size * x];
142 	return f;
143 }
144 
145 
tileEquals(Frame * last,int x,int y,int width,int height)146 bool Frame::tileEquals(Frame *last, int x, int y, int width, int height)
147 {
148 	bool bu = (flags & FRAME_BOTTOMUP);
149 
150 	if(x < 0 || y < 0 || width < 1 || height < 1 || (x + width) > hdr.width
151 		|| (y + height) > hdr.height)
152 		throw Error("Frame::tileEquals", "Argument out of range");
153 
154 	if(last && hdr.width == last->hdr.width && hdr.height == last->hdr.height
155 		&& hdr.framew == last->hdr.framew && hdr.frameh == last->hdr.frameh
156 		&& hdr.qual == last->hdr.qual && hdr.subsamp == last->hdr.subsamp
157 		&& pf->id == last->pf->id && pf->size == last->pf->size
158 		&& hdr.winid == last->hdr.winid && hdr.dpynum == last->hdr.dpynum)
159 	{
160 		if(bits && last->bits)
161 		{
162 			unsigned char *newBits =
163 				&bits[pitch * (bu ? hdr.height - y - height : y) + pf->size * x];
164 			unsigned char *oldBits =
165 				&last->bits[last->pitch * (bu ? hdr.height - y - height : y) +
166 					pf->size * x];
167 			for(int i = 0; i < height; i++)
168 			{
169 				if(memcmp(&newBits[pitch * i], &oldBits[last->pitch * i],
170 					pf->size * width))
171 					return false;
172 			}
173 		}
174 		if(stereo && rbits && last->rbits)
175 		{
176 			unsigned char *newBits =
177 				&rbits[pitch * (bu ? hdr.height - y - height : y) + pf->size * x];
178 			unsigned char *oldBits =
179 				&last->rbits[last->pitch * (bu ? hdr.height - y - height : y) +
180 					pf->size * x];
181 			for(int i = 0; i < height; i++)
182 			{
183 				if(memcmp(&newBits[pitch * i], &oldBits[last->pitch * i],
184 					pf->size * width))
185 					return false;
186 			}
187 		}
188 		return true;
189 	}
190 	return false;
191 }
192 
193 
makeAnaglyph(Frame & r,Frame & g,Frame & b)194 void Frame::makeAnaglyph(Frame &r, Frame &g, Frame &b)
195 {
196 	int i, j;
197 	unsigned char *srcrptr = r.bits, *srcgptr = g.bits, *srcbptr = b.bits,
198 		*dstptr = bits, *dstrptr, *dstgptr, *dstbptr;
199 
200 	if(pf->bpc != 8) THROW("Anaglyphic stereo requires 8 bits per component");
201 
202 	for(j = 0; j < hdr.frameh; j++, srcrptr += r.pitch, srcgptr += g.pitch,
203 		srcbptr += b.pitch, dstptr += pitch)
204 	{
205 		for(i = 0, dstrptr = &dstptr[pf->rindex], dstgptr = &dstptr[pf->gindex],
206 			dstbptr = &dstptr[pf->bindex];
207 			i < hdr.framew;
208 			i++, dstrptr += pf->size, dstgptr += pf->size, dstbptr += pf->size)
209 		{
210 			*dstrptr = srcrptr[i];  *dstgptr = srcgptr[i];  *dstbptr = srcbptr[i];
211 		}
212 	}
213 }
214 
215 
makePassive(Frame & stf,int mode)216 void Frame::makePassive(Frame &stf, int mode)
217 {
218 	unsigned char *srclptr = stf.bits, *srcrptr = stf.rbits;
219 	unsigned char *dstptr = bits;
220 
221 	if(hdr.framew != stf.hdr.framew || hdr.frameh != stf.hdr.frameh
222 		|| pitch != stf.pitch)
223 		THROW("Frames are not the same size");
224 
225 	if(mode == RRSTEREO_INTERLEAVED)
226 	{
227 		int rowSize = pf->size * hdr.framew;
228 		for(int j = 0; j < hdr.frameh; j++)
229 		{
230 			if(j % 2 == 0) memcpy(dstptr, srclptr, rowSize);
231 			else memcpy(dstptr, srcrptr, rowSize);
232 			srclptr += pitch;  srcrptr += pitch;  dstptr += pitch;
233 		}
234 	}
235 	else if(mode == RRSTEREO_TOPBOTTOM)
236 	{
237 		int rowSize = pf->size * hdr.framew;
238 		srcrptr += pitch;
239 		for(int j = 0; j < (hdr.frameh + 1) / 2; j++)
240 		{
241 			memcpy(dstptr, srclptr, rowSize);
242 			srclptr += pitch * 2;  dstptr += pitch;
243 		}
244 		for(int j = (hdr.frameh + 1) / 2; j < hdr.frameh; j++)
245 		{
246 			memcpy(dstptr, srcrptr, rowSize);
247 			srcrptr += pitch * 2;  dstptr += pitch;
248 		}
249 	}
250 	else if(mode == RRSTEREO_SIDEBYSIDE)
251 	{
252 		int pad = pitch - hdr.framew * pf->size, h = hdr.frameh;
253 		while(h > 0)
254 		{
255 			unsigned char *srclptr2 = srclptr;
256 			unsigned char *srcrptr2 = srcrptr + pf->size;
257 			for(int i = 0; i < (hdr.framew + 1) / 2; i++)
258 			{
259 				*(int *)dstptr = *(int *)srclptr2;
260 				srclptr2 += pf->size * 2;  dstptr += pf->size;
261 			}
262 			for(int i = (hdr.framew + 1) / 2; i < hdr.framew - 1; i++)
263 			{
264 				*(int *)dstptr = *(int *)srcrptr2;
265 				srcrptr2 += pf->size * 2;  dstptr += pf->size;
266 			}
267 			if(hdr.framew > 1)
268 			{
269 				memcpy(dstptr, srcrptr2, pf->size);
270 				dstptr += pf->size;
271 			}
272 			srclptr += pitch;  srcrptr += pitch;  dstptr += pad;
273 			h--;
274 		}
275 	}
276 }
277 
278 
decompressRGB(Frame & f,int width,int height,bool rightEye)279 void Frame::decompressRGB(Frame &f, int width, int height, bool rightEye)
280 {
281 	if(!f.bits || f.hdr.size < 1 || !bits || !hdr.size)
282 		THROW("Frame not initialized");
283 	if(pf->bpc < 8)
284 		throw(Error("RGB decompressor",
285 			"Destination frame has the wrong pixel format"));
286 
287 	bool dstbu = (flags & FRAME_BOTTOMUP);
288 	int srcStride = f.pitch, dstStride = pitch;
289 	int startLine = dstbu ? max(0, hdr.frameh - f.hdr.y - height) : f.hdr.y;
290 	unsigned char *srcptr = rightEye ? f.rbits : f.bits,
291 		*dstptr = rightEye ? &rbits[pitch * startLine + f.hdr.x * pf->size] :
292 			&bits[pitch * startLine + f.hdr.x * pf->size];
293 
294 	if(!dstbu)
295 	{
296 		srcptr = &srcptr[(height - 1) * f.pitch];  srcStride = -srcStride;
297 	}
298 	pf_get(PF_RGB)->convert(srcptr, width, srcStride, height, dstptr, dstStride,
299 		pf);
300 }
301 
302 
303 #define DRAWLOGO() \
304 	switch(pf->size) \
305 	{ \
306 		case 3: \
307 		{ \
308 			for(int j = 0; j < height; j++, rowptr += stride) \
309 			{ \
310 				unsigned char *pixel = rowptr; \
311 				logoptr2 = logoptr; \
312 				for(int i = 0; i < width; i++, pixel += pf->size) \
313 				{ \
314 					if(*(logoptr2++)) \
315 					{ \
316 						pixel[pf->rindex] ^= 113;  pixel[pf->gindex] ^= 162; \
317 						pixel[pf->bindex] ^= 117; \
318 					} \
319 				} \
320 				logoptr += VGLLOGO_WIDTH; \
321 			} \
322 			break; \
323 		} \
324 		case 4: \
325 		{ \
326 			unsigned int mask; \
327 			pf->setRGB((unsigned char *)&mask, 113, 162, 117); \
328 			for(int j = 0; j < height; j++, rowptr += stride) \
329 			{ \
330 				unsigned int *pixel = (unsigned int *)rowptr; \
331 				logoptr2 = logoptr; \
332 				for(int i = 0; i < width; i++, pixel++) \
333 				{ \
334 					if(*(logoptr2++)) *pixel ^= mask; \
335 				} \
336 				logoptr += VGLLOGO_WIDTH; \
337 			} \
338 			break; \
339 		} \
340 		default: \
341 			THROW("Invalid pixel format"); \
342 	}
343 
344 
addLogo(void)345 void Frame::addLogo(void)
346 {
347 	unsigned char *rowptr, *logoptr = vgllogo, *logoptr2;
348 
349 	if(!bits || hdr.width < 1 || hdr.height < 1) return;
350 
351 	int height = min(VGLLOGO_HEIGHT, hdr.height - 1);
352 	int width = min(VGLLOGO_WIDTH, hdr.width - 1);
353 	int stride = flags & FRAME_BOTTOMUP ? -pitch : pitch;
354 	if(height < 1 || width < 1) return;
355 	if(flags & FRAME_BOTTOMUP)
356 		rowptr = &bits[pitch * height + (hdr.width - width - 1) * pf->size];
357 	else
358 		rowptr = &bits[pitch * (hdr.height - height - 1) +
359 			(hdr.width - width - 1) * pf->size];
360 	DRAWLOGO()
361 
362 	if(!rbits) return;
363 	logoptr = vgllogo;
364 	if(flags & FRAME_BOTTOMUP)
365 		rowptr = &rbits[pitch * height + (hdr.width - width - 1) * pf->size];
366 	else
367 		rowptr = &rbits[pitch * (hdr.height - height - 1) +
368 			(hdr.width - width - 1) * pf->size];
369 	logoptr = vgllogo;
370 	DRAWLOGO()
371 }
372 
373 
dumpHeader(rrframeheader & h)374 void Frame::dumpHeader(rrframeheader &h)
375 {
376 	vglout.print("hdr.size    = %lu\n", h.size);
377 	vglout.print("hdr.winid   = 0x%.8x\n", h.winid);
378 	vglout.print("hdr.dpynum  = %d\n", h.dpynum);
379 	vglout.print("hdr.compress= %d\n", h.compress);
380 	vglout.print("hdr.framew  = %d\n", h.framew);
381 	vglout.print("hdr.frameh  = %d\n", h.frameh);
382 	vglout.print("hdr.width   = %d\n", h.width);
383 	vglout.print("hdr.height  = %d\n", h.height);
384 	vglout.print("hdr.x       = %d\n", h.x);
385 	vglout.print("hdr.y       = %d\n", h.y);
386 	vglout.print("hdr.qual    = %d\n", h.qual);
387 	vglout.print("hdr.subsamp = %d\n", h.subsamp);
388 	vglout.print("hdr.flags   = %d\n", h.flags);
389 }
390 
391 
checkHeader(rrframeheader & h)392 void Frame::checkHeader(rrframeheader &h)
393 {
394 	if(h.flags != RR_EOF && (h.framew < 1 || h.frameh < 1 || h.width < 1
395 		|| h.height < 1 || h.x + h.width > h.framew || h.y + h.height > h.frameh))
396 	{
397 		throw(Error("Frame::checkHeader", "Invalid header"));
398 	}
399 }
400 
401 
402 // Compressed frame
403 
CompressedFrame(void)404 CompressedFrame::CompressedFrame(void) : Frame(), tjhnd(NULL)
405 {
406 	if(!(tjhnd = tjInitCompress())) THROW(tjGetErrorStr());
407 	pf = pf_get(PF_RGB);
408 	memset(&rhdr, 0, sizeof(rrframeheader));
409 }
410 
411 
~CompressedFrame(void)412 CompressedFrame::~CompressedFrame(void)
413 {
414 	if(tjhnd) tjDestroy(tjhnd);
415 }
416 
operator =(Frame & f)417 CompressedFrame &CompressedFrame::operator= (Frame &f)
418 {
419 	if(!f.bits) THROW("Frame not initialized");
420 	if(f.pf->size < 3 || f.pf->size > 4)
421 		THROW("Only true color frames are supported");
422 
423 	switch(f.hdr.compress)
424 	{
425 		case RRCOMP_RGB:  compressRGB(f);  break;
426 		case RRCOMP_JPEG:  compressJPEG(f);  break;
427 		case RRCOMP_YUV:  compressYUV(f);  break;
428 		default:  THROW("Invalid compression type");
429 	}
430 	return *this;
431 }
432 
433 
compressYUV(Frame & f)434 void CompressedFrame::compressYUV(Frame &f)
435 {
436 	int tjflags = 0;
437 
438 	if(f.hdr.subsamp != 4) throw(Error("YUV encoder", "Invalid argument"));
439 	if(f.pf->bpc != 8)
440 		throw(Error("YUV encoder", "YUV encoding requires 8 bits per component"));
441 
442 	init(f.hdr, 0);
443 	if(f.flags & FRAME_BOTTOMUP) tjflags |= TJ_BOTTOMUP;
444 	TRY_TJ(tjEncodeYUV2(tjhnd, f.bits, f.hdr.width, f.pitch, f.hdr.height,
445 		tjpf[f.pf->id], bits, TJSUBSAMP(f.hdr.subsamp), tjflags));
446 	hdr.size = (unsigned int)tjBufSizeYUV(f.hdr.width, f.hdr.height,
447 		TJSUBSAMP(f.hdr.subsamp));
448 }
449 
450 
compressJPEG(Frame & f)451 void CompressedFrame::compressJPEG(Frame &f)
452 {
453 	int tjflags = 0;
454 
455 	if(f.hdr.qual > 100 || f.hdr.subsamp > 16 || !IS_POW2(f.hdr.subsamp))
456 		throw(Error("JPEG compressor", "Invalid argument"));
457 	if(f.pf->bpc != 8)
458 		throw(Error("JPEG compressor",
459 			"JPEG compression requires 8 bits per component"));
460 
461 	init(f.hdr, f.stereo ? RR_LEFT : 0);
462 	if(f.flags & FRAME_BOTTOMUP) tjflags |= TJ_BOTTOMUP;
463 	unsigned long size;
464 	TRY_TJ(tjCompress2(tjhnd, f.bits, f.hdr.width, f.pitch, f.hdr.height,
465 		tjpf[f.pf->id], &bits, &size, TJSUBSAMP(f.hdr.subsamp), f.hdr.qual,
466 		tjflags | TJFLAG_NOREALLOC));
467 	hdr.size = (unsigned int)size;
468 	if(f.stereo && f.rbits)
469 	{
470 		init(f.hdr, RR_RIGHT);
471 		if(rbits)
472 			TRY_TJ(tjCompress2(tjhnd, f.rbits, f.hdr.width, f.pitch, f.hdr.height,
473 				tjpf[f.pf->id], &rbits, &size, TJSUBSAMP(f.hdr.subsamp), f.hdr.qual,
474 				tjflags | TJFLAG_NOREALLOC));
475 		rhdr.size = (unsigned int)size;
476 	}
477 }
478 
479 
compressRGB(Frame & f)480 void CompressedFrame::compressRGB(Frame &f)
481 {
482 	unsigned char *srcptr;
483 	bool bu = (f.flags & FRAME_BOTTOMUP);
484 
485 	if(f.pf->bpc != 8)
486 		throw(Error("RGB compressor",
487 			"RGB encoding requires 8 bits per component"));
488 
489 	int dstPitch = f.hdr.width * 3;
490 	int srcStride = bu ? f.pitch : -f.pitch;
491 	init(f.hdr, f.stereo ? RR_LEFT : 0);
492 	srcptr = bu ? f.bits : &f.bits[f.pitch * (f.hdr.height - 1)];
493 	f.pf->convert(srcptr, f.hdr.width, srcStride, f.hdr.height, bits, dstPitch,
494 		pf_get(PF_RGB));
495 	hdr.size = dstPitch * f.hdr.height;
496 
497 	if(f.stereo && f.rbits)
498 	{
499 		init(f.hdr, RR_RIGHT);
500 		if(rbits)
501 		{
502 			srcptr = bu ? f.rbits : &f.rbits[f.pitch * (f.hdr.height - 1)];
503 			f.pf->convert(srcptr, f.hdr.width, srcStride, f.hdr.height, rbits,
504 				dstPitch, pf_get(PF_RGB));
505 			rhdr.size = dstPitch * f.hdr.height;
506 		}
507 	}
508 }
509 
510 
init(rrframeheader & h,int buffer)511 void CompressedFrame::init(rrframeheader &h, int buffer)
512 {
513 	checkHeader(h);
514 	if(h.flags == RR_EOF) { hdr = h;  return; }
515 	switch(buffer)
516 	{
517 		case RR_LEFT:
518 			if(h.width != hdr.width || h.height != hdr.height || !bits)
519 			{
520 				delete [] bits;
521 				bits = new unsigned char[tjBufSize(h.width, h.height, h.subsamp)];
522 			}
523 			hdr = h;  hdr.flags = RR_LEFT;  stereo = true;
524 			break;
525 		case RR_RIGHT:
526 			if(h.width != rhdr.width || h.height != rhdr.height || !rbits)
527 			{
528 				delete [] rbits;
529 				rbits = new unsigned char[tjBufSize(h.width, h.height, h.subsamp)];
530 			}
531 			rhdr = h;  rhdr.flags = RR_RIGHT;  stereo = true;
532 			break;
533 		default:
534 			if(h.width != hdr.width || h.height != hdr.height || !bits)
535 			{
536 				delete [] bits;
537 				bits = new unsigned char[tjBufSize(h.width, h.height, h.subsamp)];
538 			}
539 			hdr = h;  hdr.flags = 0;  stereo = false;
540 			break;
541 	}
542 	if(!stereo && rbits)
543 	{
544 		delete [] rbits;  rbits = NULL;
545 		memset(&rhdr, 0, sizeof(rrframeheader));
546 	}
547 	pitch = hdr.width * pf->size;
548 }
549 
550 
551 // Frame created from shared graphics memory
552 
553 CriticalSection FBXFrame::mutex;
554 
555 
FBXFrame(Display * dpy,Drawable draw,Visual * vis,bool reuseConn_)556 FBXFrame::FBXFrame(Display *dpy, Drawable draw, Visual *vis,
557 	bool reuseConn_) : Frame()
558 {
559 	if(!dpy || !draw) throw(Error("FBXFrame::FBXFrame", "Invalid argument"));
560 
561 	XFlush(dpy);
562 	if(reuseConn_) init(dpy, draw, vis);
563 	else init(DisplayString(dpy), draw, vis);
564 }
565 
566 
FBXFrame(char * dpystring,Window win)567 FBXFrame::FBXFrame(char *dpystring, Window win) : Frame()
568 {
569 	init(dpystring, win);
570 }
571 
572 
init(char * dpystring,Drawable draw,Visual * vis)573 void FBXFrame::init(char *dpystring, Drawable draw, Visual *vis)
574 {
575 	tjhnd = NULL;  reuseConn = false;
576 	memset(&fb, 0, sizeof(fbx_struct));
577 
578 	if(!dpystring || !draw) throw(Error("FBXFrame::init", "Invalid argument"));
579 	CriticalSection::SafeLock l(mutex);
580 	if(!(wh.dpy = XOpenDisplay(dpystring)))
581 		throw(Error("FBXFrame::init", "Could not open display"));
582 
583 	wh.d = draw;  wh.v = vis;
584 }
585 
586 
init(Display * dpy,Drawable draw,Visual * vis)587 void FBXFrame::init(Display *dpy, Drawable draw, Visual *vis)
588 {
589 	tjhnd = NULL;  reuseConn = true;
590 	memset(&fb, 0, sizeof(fbx_struct));
591 
592 	if(!dpy || !draw) throw(Error("FBXFrame::init", "Invalid argument"));
593 
594 	wh.dpy = dpy;
595 	wh.d = draw;  wh.v = vis;
596 }
597 
598 
~FBXFrame(void)599 FBXFrame::~FBXFrame(void)
600 {
601 	if(fb.bits) fbx_term(&fb);
602 	if(bits) bits = NULL;
603 	if(tjhnd) tjDestroy(tjhnd);
604 	if(wh.dpy && !reuseConn) XCloseDisplay(wh.dpy);
605 }
606 
607 
init(rrframeheader & h)608 void FBXFrame::init(rrframeheader &h)
609 {
610 	checkHeader(h);
611 	int usexshm = 1;  char *env = NULL;
612 	if((env = getenv("VGL_USEXSHM")) != NULL && strlen(env) > 0
613 		&& !strcmp(env, "0"))
614 		usexshm = 0;
615 	{
616 		CriticalSection::SafeLock l(mutex);
617 		TRY_FBX(fbx_init(&fb, wh, h.framew, h.frameh, usexshm));
618 	}
619 	if(h.framew > fb.width || h.frameh > fb.height)
620 	{
621 		XSync(wh.dpy, False);
622 		CriticalSection::SafeLock l(mutex);
623 		TRY_FBX(fbx_init(&fb, wh, h.framew, h.frameh, usexshm));
624 	}
625 	hdr = h;
626 	if(hdr.framew > fb.width) hdr.framew = fb.width;
627 	if(hdr.frameh > fb.height) hdr.frameh = fb.height;
628 	pf = fb.pf;  pitch = fb.pitch;
629 	bits = (unsigned char *)fb.bits;
630 	flags = 0;
631 }
632 
633 
operator =(CompressedFrame & cf)634 FBXFrame &FBXFrame::operator= (CompressedFrame &cf)
635 {
636 	int tjflags = 0;
637 
638 	if(!cf.bits || cf.hdr.size < 1)
639 		THROW("JPEG not initialized");
640 	init(cf.hdr);
641 	if(!fb.xi) THROW("Frame not initialized");
642 
643 	int width = min(cf.hdr.width, fb.width - cf.hdr.x);
644 	int height = min(cf.hdr.height, fb.height - cf.hdr.y);
645 	if(width > 0 && height > 0 && cf.hdr.width <= width
646 		&& cf.hdr.height <= height)
647 	{
648 		if(cf.hdr.compress == RRCOMP_RGB) decompressRGB(cf, width, height, false);
649 		else
650 		{
651 			if(pf->bpc != 8)
652 				throw(Error("JPEG decompressor",
653 					"JPEG decompression requires 8 bits per component"));
654 			if(!tjhnd)
655 			{
656 				if((tjhnd = tjInitDecompress()) == NULL)
657 					throw(Error("FBXFrame::decompressor", tjGetErrorStr()));
658 			}
659 			TRY_TJ(tjDecompress2(tjhnd, cf.bits, cf.hdr.size,
660 				(unsigned char *)&fb.bits[fb.pitch * cf.hdr.y + cf.hdr.x * pf->size],
661 				width, fb.pitch, height, tjpf[pf->id], tjflags));
662 		}
663 	}
664 	return *this;
665 }
666 
667 
redraw(void)668 void FBXFrame::redraw(void)
669 {
670 	if(flags & FRAME_BOTTOMUP) TRY_FBX(fbx_flip(&fb, 0, 0, 0, 0));
671 	TRY_FBX(fbx_write(&fb, 0, 0, 0, 0, fb.width, fb.height));
672 }
673 
674 
675 #ifdef USEXV
676 
677 // Frame created using X Video
678 
679 CriticalSection XVFrame::mutex;
680 
681 
XVFrame(Display * dpy_,Window win_)682 XVFrame::XVFrame(Display *dpy_, Window win_) : Frame()
683 {
684 	if(!dpy_ || !win_) throw(Error("XVFrame::XVFrame", "Invalid argument"));
685 
686 	XFlush(dpy_);
687 	init(DisplayString(dpy_), win_);
688 }
689 
690 
XVFrame(char * dpystring,Window win_)691 XVFrame::XVFrame(char *dpystring, Window win_) : Frame()
692 {
693 	init(dpystring, win_);
694 }
695 
696 
init(char * dpystring,Window win_)697 void XVFrame::init(char *dpystring, Window win_)
698 {
699 	tjhnd = NULL;  isXV = true;
700 	memset(&fb, 0, sizeof(fbxv_struct));
701 
702 	if(!dpystring || !win_) throw(Error("XVFrame::init", "Invalid argument"));
703 	CriticalSection::SafeLock l(mutex);
704 	if(!(dpy = XOpenDisplay(dpystring)))
705 		throw(Error("XVFrame::init", "Could not open display"));
706 
707 	win = win_;
708 }
709 
710 
~XVFrame(void)711 XVFrame::~XVFrame(void)
712 {
713 	fbxv_term(&fb);
714 	if(bits) bits = NULL;
715 	if(tjhnd) tjDestroy(tjhnd);
716 	if(dpy) XCloseDisplay(dpy);
717 }
718 
719 
operator =(Frame & f)720 XVFrame &XVFrame::operator= (Frame &f)
721 {
722 	if(!f.bits) THROW("Frame not initialized");
723 	if(f.pf->bpc != 8)
724 		throw(Error("YUV encoder", "YUV encoding requires 8 bits per component"));
725 
726 	int tjflags = 0;
727 	init(f.hdr);
728 	if(f.flags & FRAME_BOTTOMUP) tjflags |= TJ_BOTTOMUP;
729 	if(!tjhnd)
730 	{
731 		if((tjhnd = tjInitCompress()) == NULL)
732 			throw(Error("XVFrame::compressor", tjGetErrorStr()));
733 	}
734 	TRY_TJ(tjEncodeYUV2(tjhnd, f.bits, f.hdr.width, f.pitch, f.hdr.height,
735 		tjpf[f.pf->id], bits, TJ_420, tjflags));
736 	hdr.size = (unsigned int)tjBufSizeYUV(f.hdr.width, f.hdr.height, TJ_420);
737 	if(hdr.size != (unsigned long)fb.xvi->data_size)
738 		THROW("Image size mismatch in YUV encoder");
739 	return *this;
740 }
741 
742 
init(rrframeheader & h)743 void XVFrame::init(rrframeheader &h)
744 {
745 	checkHeader(h);
746 	{
747 		CriticalSection::SafeLock l(mutex);
748 		TRY_FBXV(fbxv_init(&fb, dpy, win, h.framew, h.frameh, I420_PLANAR, 0));
749 	}
750 	if(h.framew > fb.xvi->width || h.frameh > fb.xvi->height)
751 	{
752 		XSync(dpy, False);
753 		CriticalSection::SafeLock l(mutex);
754 		TRY_FBXV(fbxv_init(&fb, dpy, win, h.framew, h.frameh, I420_PLANAR, 0));
755 	}
756 	hdr = h;
757 	if(hdr.framew > fb.xvi->width) hdr.framew = fb.xvi->width;
758 	if(hdr.frameh > fb.xvi->height) hdr.frameh = fb.xvi->height;
759 	bits = (unsigned char *)fb.xvi->data;
760 	flags = pitch = 0;
761 	hdr.size = fb.xvi->data_size;
762 }
763 
764 
redraw(void)765 void XVFrame::redraw(void)
766 {
767 	TRY_FBXV(fbxv_write(&fb, 0, 0, 0, 0, 0, 0, hdr.framew, hdr.frameh));
768 }
769 
770 #endif
771