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