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