]> git.vomp.tv Git - vompclient.git/blob - surfacemvp.cc
Prebuffering
[vompclient.git] / surfacemvp.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3     Portions copyright 2004 Jon Gettler
4
5     This file is part of VOMP.
6
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.
11
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.
16
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 */
21
22 #include "surfacemvp.h"
23 #include "osd.h"
24
25 SurfaceMVP::SurfaceMVP(int id)
26 : Surface(id)
27 {
28   fdOsd = Osd::getInstance()->getFD();
29   memset(&surface, 0, sizeof(osd_surface_t));
30   memset(&surface.sfc, 0, sizeof(stbgfx_sfc_t));
31   memset(&surface.map, 0, sizeof(stbgfx_map_t));
32 }
33
34 SurfaceMVP::~SurfaceMVP()
35 {
36   for (int i = 0; i < 3; i++)
37   {
38     if (surface.base[i]) munmap(surface.base[i], surface.map.map[i].size);
39   }
40
41   int a;
42
43   a = ioctl(fdOsd, GFX_FB_SFC_UNMAP, surface.sfc.handle);
44   if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface unmap failed");
45
46   a = ioctl(fdOsd, GFX_FB_SFC_FREE, surface.sfc.handle);
47   if (a) Log::getInstance()->log("Surface", Log::ERR, "Surface destroy failed");
48
49 }
50
51 int SurfaceMVP::create(UINT width, UINT height)
52 {
53   int r = 0;
54   int displayNumber = 0; // mvpmc iterates 0->15 till it gets one that works?
55
56   surface.sfc.width = width;
57   surface.sfc.height = height;
58   surface.sfc.flags = 0x3f1533;
59
60   surface.sfc.unknown = -1;
61
62 //  r = ioctl(fdOsd, GFX_FB_SET_OSD, &displayNumber);
63 //  if (r) return 0;
64
65   r = ioctl(fdOsd, GFX_FB_OSD_SURFACE, &displayNumber);
66   if (r) return 0;
67
68   r = ioctl(fdOsd, GFX_FB_SFC_ALLOC, &surface.sfc);
69   if (r) return 0;
70
71   surface.map.map[0].unknown = surface.sfc.handle;
72   r = ioctl(fdOsd, GFX_FB_MAP, &surface.map);
73   if (r) return 0;
74
75   surface.base[0] = (unsigned char *)mmap(NULL, surface.map.map[0].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[0].addr);
76   if (surface.base[0] == MAP_FAILED) return 0;
77
78   surface.base[1] = (unsigned char *)mmap(NULL, surface.map.map[1].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[1].addr);
79   if (surface.base[1] == MAP_FAILED) return 0;
80
81   surface.base[2] = (unsigned char *)mmap(NULL, surface.map.map[2].size, PROT_READ|PROT_WRITE, MAP_SHARED, fdOsd, surface.map.map[2].addr);
82   if (surface.base[2] == MAP_FAILED) return 0;
83
84 //  surface.display.num = displayNumber;
85 //  r = ioctl(fdOsd, GFX_FB_MOVE_DISPLAY, &surface.display);
86 //  if (r) return 0;
87
88 //  r = ioctl(fdOsd, GFX_FB_SET_DISPLAY, &surface.display);
89 //  if (r) return 0;
90
91   return 1;
92 }
93
94 void SurfaceMVP::display()
95 {
96   unsigned long fb_descriptor[2];
97
98   fb_descriptor[0] = surface.sfc.handle;
99   fb_descriptor[1] = 1;
100
101   ioctl(fdOsd, GFX_FB_ATTACH, fb_descriptor);
102 }
103
104 unsigned long SurfaceMVP::getSurfaceHandle()
105 {
106   return surface.sfc.handle;
107 }
108
109 // ----------------------------------------------------------------------------
110
111 // Now for the drawing functions
112
113 /*
114  * RGB to YUV conversion tables
115  */
116 int SurfaceMVP::conv_YB[256];
117 int SurfaceMVP::conv_YG[256];
118 int SurfaceMVP::conv_YR[256];
119 int SurfaceMVP::conv_UB[256];
120 int SurfaceMVP::conv_UG[256];
121 int SurfaceMVP::conv_UR[256];
122 int SurfaceMVP::conv_VB[256];
123 int SurfaceMVP::conv_VG[256];
124 int SurfaceMVP::conv_VR[256];
125
126 int SurfaceMVP::conv_BY[256];
127 int SurfaceMVP::conv_GY[256];
128 int SurfaceMVP::conv_RY[256];
129 int SurfaceMVP::conv_BU[256];
130 int SurfaceMVP::conv_GU[256];
131 int SurfaceMVP::conv_RU[256];
132 int SurfaceMVP::conv_BV[256];
133 int SurfaceMVP::conv_GV[256];
134 int SurfaceMVP::conv_RV[256];
135
136 /*
137  * gfx_init() - initialize the RGB to YUV conversion tables
138  */
139 void SurfaceMVP::initConversionTables(void)
140 {
141   int i;
142
143   for (i=0; i<256; i++) {
144     conv_YB[i] = (int)(0.299 * (double)i);
145     conv_BY[i] = i;
146   }
147   for (i=0; i<256; i++) {
148     conv_YG[i] = (int)(0.587 * (double)i);
149     conv_GY[i] = i;
150   }
151   for (i=0; i<256; i++) {
152     conv_YR[i] = (int)(0.114 * (double)i);
153     conv_RY[i] = i;
154   }
155
156   for (i=0; i<256; i++) {
157     conv_UB[i] = (int)(0.5 * (double)i);
158     conv_BU[i] = (int)(1.732 * (i - 128));
159   }
160   for (i=0; i<256; i++) {
161     conv_UG[i] = (int)(-0.33126 * (double)i);
162     conv_GU[i] = (int)(-0.338 * (i - 128));
163   }
164   for (i=0; i<256; i++) {
165     conv_UR[i] = (int)(-0.16874 * (double)i);
166     conv_RU[i] = 0;
167   }
168
169   for (i=0; i<256; i++) {
170     conv_VB[i] = (int)(-0.08131 * (double)i);
171     conv_BV[i] = 0;
172   }
173   for (i=0; i<256; i++) {
174     conv_VG[i] = (int)(-0.41869 * (double)i);
175     conv_GV[i] = (int)(-0.698 * (i - 128));
176   }
177   for (i=0; i<256; i++) {
178     conv_VR[i] = (int)(0.5 * (double)i);
179     conv_RV[i] = (int)(1.370 * ((double)i - 128));
180   }
181 }
182
183 /*
184  * rgb2yuv() - convert an RGB pixel to YUV
185  */
186  //inline me?
187 void SurfaceMVP::rgb2yuv(unsigned char r, unsigned char g, unsigned char b, unsigned char *y, unsigned char *u, unsigned char *v)
188 {
189   int Y, U, V;
190
191   Y = conv_YB[b] + conv_YG[g] + conv_YR[r];
192   U = conv_UB[b] + conv_UG[g] + conv_UR[r] + 128;
193   V = conv_VB[b] + conv_VG[g] + conv_VR[r] + 128;
194
195   if (Y > 255)
196     Y = 255;
197   else if (Y < 0)
198     Y = 0;
199   if (U > 255)
200     U = 255;
201   else if (U < 0)
202     U = 0;
203   if (V > 255)
204     V = 255;
205   else if (V < 0)
206     V = 0;
207
208   *y = Y;
209   *u = U;
210   *v = V;
211 }
212
213 int SurfaceMVP::fillblt(int x, int y, int width, int height, unsigned int c)
214 {
215   osd_fillblt_t fblt;
216
217   fblt.handle = surface.sfc.handle;
218   fblt.x = x;
219   fblt.y = y;
220   fblt.width = width;
221   fblt.height = height;
222   fblt.colour = c;
223
224   return ioctl(fdOsd, GFX_FB_OSD_FILLBLT, &fblt);
225 }
226
227 void SurfaceMVP::drawPixel(int x, int y, unsigned int c)
228 {
229   int offset;
230   unsigned char r, g, b, a, Y, U, V;
231   unsigned int line, remainder;
232
233   if ((x >= (int)surface.sfc.width) || (y >= (int)surface.sfc.height))
234     return;
235
236   c2rgba(c, &r, &g, &b, &a);
237
238   rgb2yuv(r, g, b, &Y, &U, &V);
239
240   remainder = (surface.sfc.width % 4);
241   if (remainder == 0)
242     line = surface.sfc.width;
243   else
244     line = surface.sfc.width + (4 - remainder);
245
246   offset = (y * line) + x;
247
248   *(surface.base[0] + offset) = Y;
249   *(surface.base[1] + (offset & 0xfffffffe)) = U;
250   *(surface.base[1] + (offset & 0xfffffffe) + 1) = V;
251   *(surface.base[2] + offset) = a;
252
253 }
254
255 void SurfaceMVP::drawHorzLine(int x1, int x2, int y, unsigned int c)
256 {
257   fillblt(x1, y, x2-x1, 1, c);
258 }
259
260 void SurfaceMVP::drawVertLine(int x, int y1, int y2, unsigned int c)
261 {
262   fillblt(x, y1, 1, y2-y1, c);
263 }
264
265
266   /* surface update to screen needs:
267   source x distance into this surface
268   source y distance into this surface
269   width of update
270   height of update
271   destination x on screen
272   destination y on screen
273   */
274 int SurfaceMVP::updateToScreen(int sx, int sy, int w, int h, int dx, int dy) // FIXME new, replace others with this FIXME
275 {
276   return blt(fdOsd, surface.sfc.handle, sx, sy, w, h, ((SurfaceMVP*)screen)->getSurfaceHandle(), dx, dy);
277 }
278
279 int SurfaceMVP::blt(int fd, unsigned long shandle, int sx, int sy, int width, int height, unsigned long dhandle, int dx, int dy)
280 {
281   osd_bitblt_t fblt;
282   memset(&fblt, 0, sizeof(fblt));
283
284   fblt.dst_handle = dhandle;
285   fblt.dst_x = dx;
286   fblt.dst_y = dy;
287
288   fblt.src_handle = shandle;
289   fblt.src_x = sx;
290   fblt.src_y = sy;
291
292   fblt.width = width;
293   fblt.height = height;
294
295   fblt.u1 = 1;
296   fblt.u2 = 0;
297   fblt.u3 = 0x0f;
298
299   return ioctl(fd, GFX_FB_OSD_BITBLT, &fblt);
300 }
301
302 void SurfaceMVP::screenShot(char* fileName)
303 {
304   Log* logger = Log::getInstance();
305
306   FILE* outfile = fopen(fileName, "w");
307   if (outfile == NULL)
308   {
309     logger->log("Surface", Log::ERR, "Can't open JPEG");
310     return;
311   }
312   logger->log("Surface", Log::DEBUG, "File opened %u %u", surface.sfc.height, surface.sfc.width);
313
314   struct jpeg_compress_struct cinfo;
315   struct jpeg_error_mgr jerr;
316   cinfo.err = jpeg_std_error(&jerr);
317   jpeg_create_compress(&cinfo);
318   jpeg_stdio_dest(&cinfo, outfile);
319   cinfo.image_width = surface.sfc.width;
320   cinfo.image_height = surface.sfc.height;
321   cinfo.input_components = 3;
322   cinfo.in_color_space = JCS_RGB;
323   jpeg_set_defaults(&cinfo);
324   jpeg_start_compress(&cinfo, TRUE);
325
326
327   unsigned char row[surface.sfc.width * 3];
328   unsigned char* prow = (unsigned char*)&row;
329   unsigned char r, g, b;
330
331   while (cinfo.next_scanline < cinfo.image_height)
332   {
333     for(unsigned int i = 0; i < surface.sfc.width; i++)
334     {
335       readPixel(i, cinfo.next_scanline, &r, &g, &b);
336       row[i * 3] = r;
337       row[(i * 3) + 1] = g;
338       row[(i * 3) + 2] = b;
339     }
340     jpeg_write_scanlines(&cinfo, (JSAMPLE **)&prow, 1);
341   }
342
343   jpeg_finish_compress(&cinfo);
344   jpeg_destroy_compress(&cinfo);
345   fclose(outfile);
346   logger->log("Surface", Log::DEBUG, "Jpeg saved");
347 }
348
349 void SurfaceMVP::readPixel(int x, int y, unsigned char* r, unsigned char* g, unsigned char* b)
350 {
351   int offset;
352   unsigned char a, Y, U, V;
353   unsigned int line, remainder;
354
355   if (((unsigned int)x >= surface.sfc.width) || ((unsigned int)y >= surface.sfc.height)) return;
356
357   remainder = (surface.sfc.width % 4);
358   if (remainder == 0)
359     line = surface.sfc.width;
360   else
361     line = surface.sfc.width + (4 - remainder);
362
363   offset = (y * line) + x;
364
365   Y = *(surface.base[0] + offset);
366   U = *(surface.base[1] + (offset & 0xfffffffe));
367   V = *(surface.base[1] + (offset & 0xfffffffe) + 1);
368   a = *(surface.base[2] + offset);
369
370   yuv2rgb(Y, U, V, r, g, b);
371 }
372
373 void SurfaceMVP::yuv2rgb(int y, int u, int v, unsigned char* pr, unsigned char* pg, unsigned char* pb)
374 {
375    // from http://www.fourcc.org/index.php?http%3A//www.fourcc.org/fccyvrgb.php
376
377 //   unsigned int pixel32;
378 //   unsigned char *pixel = (unsigned char *)&pixel32;
379    int r, g, b;
380
381
382    /*
383      One formula I found:  (not the right one)
384
385      R = 1.164(Y - 16) + 1.596(Cr - 128)
386      G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128)
387      B = 1.164(Y - 16)                   + 2.018(Cb - 128)
388
389
390    r = (1.164 * (y - 16))
391       + (2.018 * (v - 128));
392    g = (1.164 * (y - 16))
393       - (0.813 * (u - 128))
394       - (0.391 * (v - 128));
395    b = (1.164 * (y - 16))
396       + (1.596 * (u - 128));
397
398
399      Another formula I found:  (seems to work)
400
401      R = Y + 1.370705 (V-128)
402      G = Y - 0.698001 (V-128) - 0.337633 (U-128)
403      B = Y + 1.732446 (U-128)
404    */
405
406    r = (int)( y + (1.370705 * (v-128)) );
407    g = (int)( y - (0.698001 * (v-128)) - (0.337633 * (u-128)) );
408    b = (int)( y + (1.732446 * (u-128)) );
409
410    // Even with proper conversion, some values still need clipping.
411    if (r > 255) r = 255;
412    if (g > 255) g = 255;
413    if (b > 255) b = 255;
414    if (r < 0) r = 0;
415    if (g < 0) g = 0;
416    if (b < 0) b = 0;
417
418    // Values only go from 0-220..  Why?
419 //   pixel[0] = r * 220 / 256;
420 //   pixel[1] = g * 220 / 256;
421 //   pixel[2] = b * 220 / 256;
422 //   pixel[3] = 0;
423
424    *pr = (unsigned char) (r * 220 / 256);
425    *pg = (unsigned char) (g * 220 / 256);
426    *pb = (unsigned char) (b * 220 / 256);
427
428    /* Debug
429    //printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i  (0x%x)\n",
430     y, u, v,
431     pixel[0], pixel[1], pixel[2],
432     pixel32);
433    */
434
435 //   return pixel32;
436 }