2 Copyright 2004-2005 Chris Tallon
3 Portions copyright 2004 Jon Gettler
5 This file is part of VOMP.
7 VOMP is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 VOMP is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with VOMP; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "surfacemvp.h"
28 SurfaceMVP::SurfaceMVP(int id)
31 fdOsd = Osd::getInstance()->getFD();
32 memset(&surface, 0, sizeof(osd_surface_t));
33 memset(&surface.sfc, 0, sizeof(stbgfx_sfc_t));
34 memset(&surface.map, 0, sizeof(stbgfx_map_t));
37 SurfaceMVP::~SurfaceMVP()
39 for (int i = 0; i < 3; i++)
41 if (surface.base[i]) munmap(surface.base[i], surface.map.map[i].size);
46 a = ioctl(fdOsd, GFX_FB_SFC_UNMAP, surface.sfc.handle);
47 if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface unmap failed");
49 a = ioctl(fdOsd, GFX_FB_SFC_FREE, surface.sfc.handle);
50 if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface destroy failed");
54 int SurfaceMVP::create(UINT width, UINT height)
57 int displayNumber = 0; // mvpmc iterates 0->15 till it gets one that works?
59 surface.sfc.width = width;
60 surface.sfc.height = height;
61 surface.sfc.flags = 0x3f1533;
63 surface.sfc.unknown = -1;
65 // r = ioctl(fdOsd, GFX_FB_SET_OSD, &displayNumber);
68 r = ioctl(fdOsd, GFX_FB_OSD_SURFACE, &displayNumber);
71 r = ioctl(fdOsd, GFX_FB_SFC_ALLOC, &surface.sfc);
74 surface.map.map[0].unknown = surface.sfc.handle;
75 r = ioctl(fdOsd, GFX_FB_MAP, &surface.map);
78 surface.base[0] = (unsigned char *)mmap(NULL, surface.map.map[0].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[0].addr);
79 if (surface.base[0] == MAP_FAILED) return 0;
81 surface.base[1] = (unsigned char *)mmap(NULL, surface.map.map[1].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[1].addr);
82 if (surface.base[1] == MAP_FAILED) return 0;
84 surface.base[2] = (unsigned char *)mmap(NULL, surface.map.map[2].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[2].addr);
85 if (surface.base[2] == MAP_FAILED) return 0;
87 // surface.display.num = displayNumber;
88 // r = ioctl(fdOsd, GFX_FB_MOVE_DISPLAY, &surface.display);
91 // r = ioctl(fdOsd, GFX_FB_SET_DISPLAY, &surface.display);
97 void SurfaceMVP::display()
99 unsigned long fb_descriptor[2];
101 fb_descriptor[0] = surface.sfc.handle;
102 fb_descriptor[1] = 1;
104 ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
107 unsigned long SurfaceMVP::getSurfaceHandle()
109 return surface.sfc.handle;
112 // ----------------------------------------------------------------------------
114 // Now for the drawing functions
117 * RGB to YUV conversion tables
119 int SurfaceMVP::conv_YB[256];
120 int SurfaceMVP::conv_YG[256];
121 int SurfaceMVP::conv_YR[256];
122 int SurfaceMVP::conv_UB[256];
123 int SurfaceMVP::conv_UG[256];
124 int SurfaceMVP::conv_UR[256];
125 int SurfaceMVP::conv_VB[256];
126 int SurfaceMVP::conv_VG[256];
127 int SurfaceMVP::conv_VR[256];
129 int SurfaceMVP::conv_BY[256];
130 int SurfaceMVP::conv_GY[256];
131 int SurfaceMVP::conv_RY[256];
132 int SurfaceMVP::conv_BU[256];
133 int SurfaceMVP::conv_GU[256];
134 int SurfaceMVP::conv_RU[256];
135 int SurfaceMVP::conv_BV[256];
136 int SurfaceMVP::conv_GV[256];
137 int SurfaceMVP::conv_RV[256];
140 * gfx_init() - initialize the RGB to YUV conversion tables
142 void SurfaceMVP::initConversionTables(int rfactor, int gfactor, int bfactor)
145 double drfactor=(double)rfactor/(double)100;
146 double dgfactor=(double)gfactor/(double)100;
147 double dbfactor=(double)bfactor/(double)100;
149 for (i=0; i<256; i++) {
150 conv_YB[i] = (int)(0.299 * (double)i *dbfactor);
153 for (i=0; i<256; i++) {
154 conv_YG[i] = (int)(0.587 * (double)i * dgfactor);
157 for (i=0; i<256; i++) {
158 conv_YR[i] = (int)(0.114 * (double)i *drfactor);
162 for (i=0; i<256; i++) {
163 conv_UB[i] = (int)(0.5 * (double)i *dbfactor);
164 conv_BU[i] = (int)(1.732 * (i - 128));
166 for (i=0; i<256; i++) {
167 conv_UG[i] = (int)(-0.33126 * (double)i*dgfactor);
168 conv_GU[i] = (int)(-0.338 * (i - 128));
170 for (i=0; i<256; i++) {
171 conv_UR[i] = (int)(-0.16874 * (double)i *drfactor);
175 for (i=0; i<256; i++) {
176 conv_VB[i] = (int)(-0.08131 * (double)i *dbfactor);
179 for (i=0; i<256; i++) {
180 conv_VG[i] = (int)(-0.41869 * (double)i * dgfactor);
181 conv_GV[i] = (int)(-0.698 * (i - 128));
183 for (i=0; i<256; i++) {
184 conv_VR[i] = (int)(0.5 * (double)i * drfactor);
185 conv_RV[i] = (int)(1.370 * ((double)i - 128));
189 int SurfaceMVP::fillblt(int x, int y, int width, int height, unsigned int c)
193 fblt.handle = surface.sfc.handle;
197 fblt.height = height;
200 return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt);
203 void SurfaceMVP::drawPixel(int x, int y, unsigned int c, bool fastdraw)
206 unsigned char r, g, b, a, Y, U, V;
207 unsigned int line, remainder;
209 if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height))
212 c2rgba(c, &r, &g, &b, &a);
214 rgb2yuv(r, g, b, &Y, &U, &V);
216 remainder = (surface.sfc.width % 4);
218 line = surface.sfc.width;
220 line = surface.sfc.width + (4 - remainder);
222 offset = (y * line) + x;
224 *(surface.base[0] + offset) = Y;
225 *(surface.base[1] + (offset & 0xfffffffe)) = U;
226 *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
227 *(surface.base[2] + offset) = a;
230 void SurfaceMVP::drawPixel(int x, int y, Colour& c, bool fastdraw)
233 unsigned char Y, U, V;
234 unsigned int line, remainder;
236 if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height))
240 rgb2yuv(c.red, c.green, c.blue, &Y, &U, &V);
242 remainder = (surface.sfc.width % 4);
244 line = surface.sfc.width;
246 line = surface.sfc.width + (4 - remainder);
248 offset = (y * line) + x;
250 *(surface.base[0] + offset) = Y;
251 *(surface.base[1] + (offset & 0xfffffffe)) = U;
252 *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
253 *(surface.base[2] + offset) = 0xff;
256 void SurfaceMVP::drawHorzLine(int x1, int x2, int y, unsigned int c)
258 fillblt(x1, y, x2-x1, 1, c);
261 void SurfaceMVP::drawVertLine(int x, int y1, int y2, unsigned int c)
263 fillblt(x, y1, 1, y2-y1, c);
266 void SurfaceMVP::drawBitmap(int x, int y, const Bitmap& bm)
268 UINT bmw = bm.getWidth(); UINT bmh = bm.getHeight();
269 if (bmw == 0 || bmh == 0) return;
270 if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height)) return;
271 int remainder = (surface.sfc.width % 4);
274 line = surface.sfc.width;
276 line = surface.sfc.width + (4 - remainder);
277 const std::vector<UCHAR>& bmdata = bm.rawData();
278 const std::vector<UCHAR>& Y = bm.palette.getYVector();
279 const std::vector<UCHAR>& Cr = bm.palette.getCrVector();
280 const std::vector<UCHAR>& Cb = bm.palette.getCbVector();
281 const std::vector<UCHAR>& A = bm.palette.getAVector();
283 UINT s_offset = x + y*line;
284 UINT plotWidth = bmw;
285 UINT plotHeight = bmh;
286 if (x + plotWidth - 1 > surface.sfc.width)
287 plotWidth = surface.sfc.width - x + 1;
288 if (y + plotHeight - 1 > surface.sfc.height)
289 plotHeight = surface.sfc.height - y + 1;
290 for (UINT j = 0; j < plotHeight; ++j)
293 if (x & 1) // odd x - need to plot first column separately
295 UCHAR index = bmdata[b_offset];
296 *(surface.base[0] + s_offset) = Y[index];
297 *(surface.base[1] + s_offset - 1) = Cb[index];
298 *(surface.base[1] + s_offset) = Cr[index];
299 *(surface.base[2] + s_offset) = A[index];
302 // Now, plot pairs of pixels with averaged chroma values
303 while (i < plotWidth - 1)
305 UCHAR index1 = bmdata[b_offset + i];
306 UCHAR index2 = bmdata[b_offset + i + 1];
307 *(surface.base[0] + s_offset + i) = Y[index1];
308 *(surface.base[0] + s_offset + i + 1) = Y[index2];
309 *(surface.base[1] + s_offset + i) = (Cb[index1] + Cb[index2]) / 2;
310 *(surface.base[1] + s_offset + i + 1) = (Cr[index1] + Cr[index2]) / 2;
311 *(surface.base[2] + s_offset + i) = A[index1];
312 *(surface.base[2] + s_offset + i + 1) = A[index2];
315 if (i == plotWidth - 1) // One column left to do
317 UCHAR index = bmdata[b_offset + i];
318 *(surface.base[0] + s_offset + i) = Y[index];
319 *(surface.base[1] + s_offset + i) = Cb[index];
320 *(surface.base[1] + s_offset + i + 1) = Cr[index];
321 *(surface.base[2] + s_offset + i) = A[index];
328 /* surface update to screen needs:
329 source x distance into this surface
330 source y distance into this surface
333 destination x on screen
334 destination y on screen
336 int SurfaceMVP::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
338 return blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceMVP*)screen)->getSurfaceHandle(), dx, dy);
341 int SurfaceMVP::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
344 memset(&fblt, 0, sizeof(fblt));
346 fblt.dst_handle = dhandle;
350 fblt.src_handle = shandle;
355 fblt.height = height;
361 return ioctl(fd, GFX_FB_OSD_BITBLT, &fblt);
364 void SurfaceMVP::screenShot(char* fileName)
366 Log* logger = Log::getInstance();
368 FILE* outfile = fopen(fileName, "w");
371 logger->log("Surface", Log::ERR, "Can't open JPEG");
374 logger->log("Surface", Log::DEBUG, "File opened %u %u", surface.sfc.height, surface.sfc.width);
376 struct jpeg_compress_struct cinfo;
377 struct jpeg_error_mgr jerr;
378 cinfo.err = jpeg_std_error(&jerr);
379 jpeg_create_compress(&cinfo);
380 jpeg_stdio_dest(&cinfo, outfile);
381 cinfo.image_width = surface.sfc.width;
382 cinfo.image_height = surface.sfc.height;
383 cinfo.input_components = 3;
384 cinfo.in_color_space = JCS_RGB;
385 jpeg_set_defaults(&cinfo);
386 jpeg_start_compress(&cinfo, TRUE);
389 unsigned char row[surface.sfc.width * 3];
390 unsigned char* prow = (unsigned char*)&row;
391 unsigned char r, g, b;
393 while (cinfo.next_scanline < cinfo.image_height)
395 for(unsigned int i = 0; i < surface.sfc.width; i++)
397 readPixel(i, cinfo.next_scanline, &r, &g, &b);
399 row[(i * 3) + 1] = g;
400 row[(i * 3) + 2] = b;
402 jpeg_write_scanlines(&cinfo, (JSAMPLE **)&prow, 1);
405 jpeg_finish_compress(&cinfo);
406 jpeg_destroy_compress(&cinfo);
408 logger->log("Surface", Log::DEBUG, "Jpeg saved");
411 void SurfaceMVP::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
414 unsigned char a, Y, U, V;
415 unsigned int line, remainder;
417 if (((unsigned int)x >= surface.sfc.width) || ((unsigned int)y >= surface.sfc.height)) return;
419 remainder = (surface.sfc.width % 4);
421 line = surface.sfc.width;
423 line = surface.sfc.width + (4 - remainder);
425 offset = (y * line) + x;
427 Y = *(surface.base[0] + offset);
428 U = *(surface.base[1] + (offset & 0xfffffffe));
429 V = *(surface.base[1] + (offset & 0xfffffffe) + 1);
430 a = *(surface.base[2] + offset);
432 yuv2rgb(Y, U, V, r, g, b);
435 void SurfaceMVP::yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb)
437 // from http://www.fourcc.org/index.php?http%3A//www.fourcc.org/fccyvrgb.php
439 // unsigned int pixel32;
440 // unsigned char *pixel = (unsigned char *)&pixel32;
445 One formula I found: (not the right one)
447 R = 1.164(Y - 16) + 1.596(Cr - 128)
448 G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128)
449 B = 1.164(Y - 16) + 2.018(Cb - 128)
452 r = (1.164 * (y - 16))
453 + (2.018 * (v - 128));
454 g = (1.164 * (y - 16))
455 - (0.813 * (u - 128))
456 - (0.391 * (v - 128));
457 b = (1.164 * (y - 16))
458 + (1.596 * (u - 128));
461 Another formula I found: (seems to work)
463 R = Y + 1.370705 (V-128)
464 G = Y - 0.698001 (V-128) - 0.337633 (U-128)
465 B = Y + 1.732446 (U-128)
468 r = (int)( y + (1.370705 * (v-128)) );
469 g = (int)( y - (0.698001 * (v-128)) - (0.337633 * (u-128)) );
470 b = (int)( y + (1.732446 * (u-128)) );
472 // Even with proper conversion, some values still need clipping.
473 if (r > 255) r = 255;
474 if (g > 255) g = 255;
475 if (b > 255) b = 255;
480 // Values only go from 0-220.. Why?
481 // pixel[0] = r * 220 / 256;
482 // pixel[1] = g * 220 / 256;
483 // pixel[2] = b * 220 / 256;
486 *pr = (unsigned char) (r * 220 / 256);
487 *pg = (unsigned char) (g * 220 / 256);
488 *pb = (unsigned char) (b * 220 / 256);
491 //printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i (0x%x)\n",
493 pixel[0], pixel[1], pixel[2],