add dm920 support
[aio-grab.git] / main.c
1 /*
2 AiO Dreambox Screengrabber v0.83a
3
4 written 2006 - 2009 by Seddi
5 Contact: seddi@ihad.tv / http://www.ihad.tv
6
7 This standalone binary will grab the video-picture convert it from
8 yuv to rgb and resize it, if neccesary, to the same size as the framebuffer or 
9 vice versa. For the DM7025 (Xilleon) and DM800/DM8000/DM500HD (Broadcom) the video will be
10 grabbed directly from the decoder memory.
11 It also grabs the framebuffer picture in 32Bit, 16Bit or in 8Bit mode with the 
12 correct colortable in 8Bit mode from the main graphics memory, because the 
13 FBIOGETCMAP is buggy on Vulcan/Pallas boxes and didnt give you the correct color 
14 map.
15 Finally it will combine the pixmaps to one final picture by using the framebuffer
16 alphamap and save it as bmp, jpeg or png file. So you will get the same picture 
17 as you can see on your TV Screen.
18
19 There are a few command line switches, use "grab -h" to get them listed.
20
21 A special Thanx to tmbinc and ghost for the needed decoder memory information and 
22 the great support.
23
24 Feel free to use the code for your own projects. See LICENSE file for details.
25 */
26
27 #include "grab_config.h"
28
29 #include <assert.h>
30 #include <fcntl.h>
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/ioctl.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41
42 #include <linux/fb.h>
43
44 #include <png.h>
45 #include <jpeglib.h>
46
47 #define CLAMP(x)    ((x < 0) ? 0 : ((x > 255) ? 255 : x))
48 #define SWAP(x,y)       { x ^= y; y ^= x; x ^= y; }
49
50 #define RED565(x)    ((((x) >> (11 )) & 0x1f) << 3)
51 #define GREEN565(x)  ((((x) >> (5 )) & 0x3f) << 2)
52 #define BLUE565(x)   ((((x) >> (0)) & 0x1f) << 3)
53
54 #define YFB(x)    ((((x) >> (10)) & 0x3f) << 2)
55 #define CBFB(x)  ((((x) >> (6)) & 0xf) << 4)
56 #define CRFB(x)   ((((x) >> (2)) & 0xf) << 4)
57 #define BFFB(x)   ((((x) >> (0)) & 0x3) << 6)
58
59 #define VIDEO_DEV "/dev/video"
60
61 // dont change SPARE_RAM and DMA_BLOCKSIZE until you really know what you are doing !!!
62 #define SPARE_RAM 252*1024*1024 // the last 4 MB is enough...
63 #define DMA_BLOCKSIZE 0x3FF000 // should be big enough to hold a complete YUV 1920x1080 HD picture, otherwise it will not work properly on DM8000
64
65 // static lookup tables for faster yuv2rgb conversion
66 static const int yuv2rgbtable_y[256] = {
67 0xFFED5EA0, 0xFFEE88B6, 0xFFEFB2CC, 0xFFF0DCE2, 0xFFF206F8, 0xFFF3310E, 0xFFF45B24, 0xFFF5853A, 0xFFF6AF50, 0xFFF7D966, 0xFFF9037C, 0xFFFA2D92, 0xFFFB57A8, 0xFFFC81BE, 0xFFFDABD4, 0xFFFED5EA, 0x0, 0x12A16, 0x2542C, 0x37E42, 0x4A858, 0x5D26E, 0x6FC84, 0x8269A, 0x950B0, 0xA7AC6, 0xBA4DC, 0xCCEF2, 0xDF908, 0xF231E, 0x104D34, 0x11774A, 0x12A160, 0x13CB76, 0x14F58C, 0x161FA2, 0x1749B8, 0x1873CE, 0x199DE4, 0x1AC7FA, 0x1BF210, 0x1D1C26, 0x1E463C, 0x1F7052, 0x209A68, 0x21C47E, 0x22EE94, 0x2418AA, 0x2542C0, 0x266CD6, 0x2796EC, 0x28C102, 0x29EB18, 0x2B152E, 0x2C3F44, 0x2D695A, 0x2E9370, 0x2FBD86, 0x30E79C, 0x3211B2, 0x333BC8, 0x3465DE, 0x358FF4, 0x36BA0A, 0x37E420, 0x390E36, 0x3A384C, 0x3B6262, 0x3C8C78, 0x3DB68E, 0x3EE0A4, 0x400ABA, 0x4134D0, 0x425EE6, 0x4388FC, 0x44B312, 0x45DD28, 0x47073E, 0x483154, 0x495B6A, 0x4A8580, 0x4BAF96, 0x4CD9AC, 0x4E03C2, 0x4F2DD8, 0x5057EE, 0x518204, 0x52AC1A, 0x53D630, 0x550046, 0x562A5C, 0x575472, 0x587E88, 0x59A89E, 0x5AD2B4, 0x5BFCCA, 0x5D26E0, 0x5E50F6, 0x5F7B0C, 0x60A522, 0x61CF38, 0x62F94E, 0x642364, 0x654D7A, 0x667790, 0x67A1A6, 0x68CBBC, 0x69F5D2, 0x6B1FE8, 0x6C49FE, 0x6D7414, 0x6E9E2A, 0x6FC840, 0x70F256, 0x721C6C, 0x734682, 0x747098, 0x759AAE, 0x76C4C4, 0x77EEDA, 0x7918F0, 0x7A4306, 0x7B6D1C, 0x7C9732, 0x7DC148, 0x7EEB5E, 0x801574, 0x813F8A, 0x8269A0, 0x8393B6, 0x84BDCC, 0x85E7E2, 0x8711F8, 0x883C0E, 0x896624, 0x8A903A, 0x8BBA50, 0x8CE466, 0x8E0E7C, 0x8F3892, 0x9062A8, 0x918CBE, 0x92B6D4, 0x93E0EA, 0x950B00, 0x963516, 0x975F2C, 0x988942, 0x99B358, 0x9ADD6E, 0x9C0784, 0x9D319A, 0x9E5BB0, 0x9F85C6, 0xA0AFDC, 0xA1D9F2, 0xA30408, 0xA42E1E, 0xA55834, 0xA6824A, 0xA7AC60, 0xA8D676, 0xAA008C, 0xAB2AA2, 0xAC54B8, 0xAD7ECE, 0xAEA8E4, 0xAFD2FA, 0xB0FD10, 0xB22726, 0xB3513C, 0xB47B52, 0xB5A568, 0xB6CF7E, 0xB7F994, 0xB923AA, 0xBA4DC0, 0xBB77D6, 0xBCA1EC, 0xBDCC02, 0xBEF618, 0xC0202E, 0xC14A44, 0xC2745A, 0xC39E70, 0xC4C886, 0xC5F29C, 0xC71CB2, 0xC846C8, 0xC970DE, 0xCA9AF4, 0xCBC50A, 0xCCEF20, 0xCE1936, 0xCF434C, 0xD06D62, 0xD19778, 0xD2C18E, 0xD3EBA4, 0xD515BA, 0xD63FD0, 0xD769E6, 0xD893FC, 0xD9BE12, 0xDAE828, 0xDC123E, 0xDD3C54, 0xDE666A, 0xDF9080, 0xE0BA96, 0xE1E4AC, 0xE30EC2, 0xE438D8, 0xE562EE, 0xE68D04, 0xE7B71A, 0xE8E130, 0xEA0B46, 0xEB355C, 0xEC5F72, 0xED8988, 0xEEB39E, 0xEFDDB4, 0xF107CA, 0xF231E0, 0xF35BF6, 0xF4860C, 0xF5B022, 0xF6DA38, 0xF8044E, 0xF92E64, 0xFA587A, 0xFB8290, 0xFCACA6, 0xFDD6BC, 0xFF00D2, 0x1002AE8, 0x10154FE, 0x1027F14, 0x103A92A, 0x104D340, 0x105FD56, 0x107276C, 0x1085182, 0x1097B98, 0x10AA5AE, 0x10BCFC4, 0x10CF9DA, 0x10E23F0, 0x10F4E06, 0x110781C, 0x111A232, 0x112CC48, 0x113F65E, 0x1152074, 0x1164A8A
68 };
69 static const int yuv2rgbtable_ru[256] = {
70 0xFEFDA500, 0xFEFFA9B6, 0xFF01AE6C, 0xFF03B322, 0xFF05B7D8, 0xFF07BC8E, 0xFF09C144, 0xFF0BC5FA, 0xFF0DCAB0, 0xFF0FCF66, 0xFF11D41C, 0xFF13D8D2, 0xFF15DD88, 0xFF17E23E, 0xFF19E6F4, 0xFF1BEBAA, 0xFF1DF060, 0xFF1FF516, 0xFF21F9CC, 0xFF23FE82, 0xFF260338, 0xFF2807EE, 0xFF2A0CA4, 0xFF2C115A, 0xFF2E1610, 0xFF301AC6, 0xFF321F7C, 0xFF342432, 0xFF3628E8, 0xFF382D9E, 0xFF3A3254, 0xFF3C370A, 0xFF3E3BC0, 0xFF404076, 0xFF42452C, 0xFF4449E2, 0xFF464E98, 0xFF48534E, 0xFF4A5804, 0xFF4C5CBA, 0xFF4E6170, 0xFF506626, 0xFF526ADC, 0xFF546F92, 0xFF567448, 0xFF5878FE, 0xFF5A7DB4, 0xFF5C826A, 0xFF5E8720, 0xFF608BD6, 0xFF62908C, 0xFF649542, 0xFF6699F8, 0xFF689EAE, 0xFF6AA364, 0xFF6CA81A, 0xFF6EACD0, 0xFF70B186, 0xFF72B63C, 0xFF74BAF2, 0xFF76BFA8, 0xFF78C45E, 0xFF7AC914, 0xFF7CCDCA, 0xFF7ED280, 0xFF80D736, 0xFF82DBEC, 0xFF84E0A2, 0xFF86E558, 0xFF88EA0E, 0xFF8AEEC4, 0xFF8CF37A, 0xFF8EF830, 0xFF90FCE6, 0xFF93019C, 0xFF950652, 0xFF970B08, 0xFF990FBE, 0xFF9B1474, 0xFF9D192A, 0xFF9F1DE0, 0xFFA12296, 0xFFA3274C, 0xFFA52C02, 0xFFA730B8, 0xFFA9356E, 0xFFAB3A24, 0xFFAD3EDA, 0xFFAF4390, 0xFFB14846, 0xFFB34CFC, 0xFFB551B2, 0xFFB75668, 0xFFB95B1E, 0xFFBB5FD4, 0xFFBD648A, 0xFFBF6940, 0xFFC16DF6, 0xFFC372AC, 0xFFC57762, 0xFFC77C18, 0xFFC980CE, 0xFFCB8584, 0xFFCD8A3A, 0xFFCF8EF0, 0xFFD193A6, 0xFFD3985C, 0xFFD59D12, 0xFFD7A1C8, 0xFFD9A67E, 0xFFDBAB34, 0xFFDDAFEA, 0xFFDFB4A0, 0xFFE1B956, 0xFFE3BE0C, 0xFFE5C2C2, 0xFFE7C778, 0xFFE9CC2E, 0xFFEBD0E4, 0xFFEDD59A, 0xFFEFDA50, 0xFFF1DF06, 0xFFF3E3BC, 0xFFF5E872, 0xFFF7ED28, 0xFFF9F1DE, 0xFFFBF694, 0xFFFDFB4A, 0x0, 0x204B6, 0x4096C, 0x60E22, 0x812D8, 0xA178E, 0xC1C44, 0xE20FA, 0x1025B0, 0x122A66, 0x142F1C, 0x1633D2, 0x183888, 0x1A3D3E, 0x1C41F4, 0x1E46AA, 0x204B60, 0x225016, 0x2454CC, 0x265982, 0x285E38, 0x2A62EE, 0x2C67A4, 0x2E6C5A, 0x307110, 0x3275C6, 0x347A7C, 0x367F32, 0x3883E8, 0x3A889E, 0x3C8D54, 0x3E920A, 0x4096C0, 0x429B76, 0x44A02C, 0x46A4E2, 0x48A998, 0x4AAE4E, 0x4CB304, 0x4EB7BA, 0x50BC70, 0x52C126, 0x54C5DC, 0x56CA92, 0x58CF48, 0x5AD3FE, 0x5CD8B4, 0x5EDD6A, 0x60E220, 0x62E6D6, 0x64EB8C, 0x66F042, 0x68F4F8, 0x6AF9AE, 0x6CFE64, 0x6F031A, 0x7107D0, 0x730C86, 0x75113C, 0x7715F2, 0x791AA8, 0x7B1F5E, 0x7D2414, 0x7F28CA, 0x812D80, 0x833236, 0x8536EC, 0x873BA2, 0x894058, 0x8B450E, 0x8D49C4, 0x8F4E7A, 0x915330, 0x9357E6, 0x955C9C, 0x976152, 0x996608, 0x9B6ABE, 0x9D6F74, 0x9F742A, 0xA178E0, 0xA37D96, 0xA5824C, 0xA78702, 0xA98BB8, 0xAB906E, 0xAD9524, 0xAF99DA, 0xB19E90, 0xB3A346, 0xB5A7FC, 0xB7ACB2, 0xB9B168, 0xBBB61E, 0xBDBAD4, 0xBFBF8A, 0xC1C440, 0xC3C8F6, 0xC5CDAC, 0xC7D262, 0xC9D718, 0xCBDBCE, 0xCDE084, 0xCFE53A, 0xD1E9F0, 0xD3EEA6, 0xD5F35C, 0xD7F812, 0xD9FCC8, 0xDC017E, 0xDE0634, 0xE00AEA, 0xE20FA0, 0xE41456, 0xE6190C, 0xE81DC2, 0xEA2278, 0xEC272E, 0xEE2BE4, 0xF0309A, 0xF23550, 0xF43A06, 0xF63EBC, 0xF84372, 0xFA4828, 0xFC4CDE, 0xFE5194, 0x100564A
71 };
72 static const int yuv2rgbtable_gu[256] = {
73 0xFFCDD300, 0xFFCE375A, 0xFFCE9BB4, 0xFFCF000E, 0xFFCF6468, 0xFFCFC8C2, 0xFFD02D1C, 0xFFD09176, 0xFFD0F5D0, 0xFFD15A2A, 0xFFD1BE84, 0xFFD222DE, 0xFFD28738, 0xFFD2EB92, 0xFFD34FEC, 0xFFD3B446, 0xFFD418A0, 0xFFD47CFA, 0xFFD4E154, 0xFFD545AE, 0xFFD5AA08, 0xFFD60E62, 0xFFD672BC, 0xFFD6D716, 0xFFD73B70, 0xFFD79FCA, 0xFFD80424, 0xFFD8687E, 0xFFD8CCD8, 0xFFD93132, 0xFFD9958C, 0xFFD9F9E6, 0xFFDA5E40, 0xFFDAC29A, 0xFFDB26F4, 0xFFDB8B4E, 0xFFDBEFA8, 0xFFDC5402, 0xFFDCB85C, 0xFFDD1CB6, 0xFFDD8110, 0xFFDDE56A, 0xFFDE49C4, 0xFFDEAE1E, 0xFFDF1278, 0xFFDF76D2, 0xFFDFDB2C, 0xFFE03F86, 0xFFE0A3E0, 0xFFE1083A, 0xFFE16C94, 0xFFE1D0EE, 0xFFE23548, 0xFFE299A2, 0xFFE2FDFC, 0xFFE36256, 0xFFE3C6B0, 0xFFE42B0A, 0xFFE48F64, 0xFFE4F3BE, 0xFFE55818, 0xFFE5BC72, 0xFFE620CC, 0xFFE68526, 0xFFE6E980, 0xFFE74DDA, 0xFFE7B234, 0xFFE8168E, 0xFFE87AE8, 0xFFE8DF42, 0xFFE9439C, 0xFFE9A7F6, 0xFFEA0C50, 0xFFEA70AA, 0xFFEAD504, 0xFFEB395E, 0xFFEB9DB8, 0xFFEC0212, 0xFFEC666C, 0xFFECCAC6, 0xFFED2F20, 0xFFED937A, 0xFFEDF7D4, 0xFFEE5C2E, 0xFFEEC088, 0xFFEF24E2, 0xFFEF893C, 0xFFEFED96, 0xFFF051F0, 0xFFF0B64A, 0xFFF11AA4, 0xFFF17EFE, 0xFFF1E358, 0xFFF247B2, 0xFFF2AC0C, 0xFFF31066, 0xFFF374C0, 0xFFF3D91A, 0xFFF43D74, 0xFFF4A1CE, 0xFFF50628, 0xFFF56A82, 0xFFF5CEDC, 0xFFF63336, 0xFFF69790, 0xFFF6FBEA, 0xFFF76044, 0xFFF7C49E, 0xFFF828F8, 0xFFF88D52, 0xFFF8F1AC, 0xFFF95606, 0xFFF9BA60, 0xFFFA1EBA, 0xFFFA8314, 0xFFFAE76E, 0xFFFB4BC8, 0xFFFBB022, 0xFFFC147C, 0xFFFC78D6, 0xFFFCDD30, 0xFFFD418A, 0xFFFDA5E4, 0xFFFE0A3E, 0xFFFE6E98, 0xFFFED2F2, 0xFFFF374C, 0xFFFF9BA6, 0x0, 0x645A, 0xC8B4, 0x12D0E, 0x19168, 0x1F5C2, 0x25A1C, 0x2BE76, 0x322D0, 0x3872A, 0x3EB84, 0x44FDE, 0x4B438, 0x51892, 0x57CEC, 0x5E146, 0x645A0, 0x6A9FA, 0x70E54, 0x772AE, 0x7D708, 0x83B62, 0x89FBC, 0x90416, 0x96870, 0x9CCCA, 0xA3124, 0xA957E, 0xAF9D8, 0xB5E32, 0xBC28C, 0xC26E6, 0xC8B40, 0xCEF9A, 0xD53F4, 0xDB84E, 0xE1CA8, 0xE8102, 0xEE55C, 0xF49B6, 0xFAE10, 0x10126A, 0x1076C4, 0x10DB1E, 0x113F78, 0x11A3D2, 0x12082C, 0x126C86, 0x12D0E0, 0x13353A, 0x139994, 0x13FDEE, 0x146248, 0x14C6A2, 0x152AFC, 0x158F56, 0x15F3B0, 0x16580A, 0x16BC64, 0x1720BE, 0x178518, 0x17E972, 0x184DCC, 0x18B226, 0x191680, 0x197ADA, 0x19DF34, 0x1A438E, 0x1AA7E8, 0x1B0C42, 0x1B709C, 0x1BD4F6, 0x1C3950, 0x1C9DAA, 0x1D0204, 0x1D665E, 0x1DCAB8, 0x1E2F12, 0x1E936C, 0x1EF7C6, 0x1F5C20, 0x1FC07A, 0x2024D4, 0x20892E, 0x20ED88, 0x2151E2, 0x21B63C, 0x221A96, 0x227EF0, 0x22E34A, 0x2347A4, 0x23ABFE, 0x241058, 0x2474B2, 0x24D90C, 0x253D66, 0x25A1C0, 0x26061A, 0x266A74, 0x26CECE, 0x273328, 0x279782, 0x27FBDC, 0x286036, 0x28C490, 0x2928EA, 0x298D44, 0x29F19E, 0x2A55F8, 0x2ABA52, 0x2B1EAC, 0x2B8306, 0x2BE760, 0x2C4BBA, 0x2CB014, 0x2D146E, 0x2D78C8, 0x2DDD22, 0x2E417C, 0x2EA5D6, 0x2F0A30, 0x2F6E8A, 0x2FD2E4, 0x30373E, 0x309B98, 0x30FFF2, 0x31644C, 0x31C8A6
74 };
75 static const int yuv2rgbtable_gv[256] = {
76 0xFF97E900, 0xFF98B92E, 0xFF99895C, 0xFF9A598A, 0xFF9B29B8, 0xFF9BF9E6, 0xFF9CCA14, 0xFF9D9A42, 0xFF9E6A70, 0xFF9F3A9E, 0xFFA00ACC, 0xFFA0DAFA, 0xFFA1AB28, 0xFFA27B56, 0xFFA34B84, 0xFFA41BB2, 0xFFA4EBE0, 0xFFA5BC0E, 0xFFA68C3C, 0xFFA75C6A, 0xFFA82C98, 0xFFA8FCC6, 0xFFA9CCF4, 0xFFAA9D22, 0xFFAB6D50, 0xFFAC3D7E, 0xFFAD0DAC, 0xFFADDDDA, 0xFFAEAE08, 0xFFAF7E36, 0xFFB04E64, 0xFFB11E92, 0xFFB1EEC0, 0xFFB2BEEE, 0xFFB38F1C, 0xFFB45F4A, 0xFFB52F78, 0xFFB5FFA6, 0xFFB6CFD4, 0xFFB7A002, 0xFFB87030, 0xFFB9405E, 0xFFBA108C, 0xFFBAE0BA, 0xFFBBB0E8, 0xFFBC8116, 0xFFBD5144, 0xFFBE2172, 0xFFBEF1A0, 0xFFBFC1CE, 0xFFC091FC, 0xFFC1622A, 0xFFC23258, 0xFFC30286, 0xFFC3D2B4, 0xFFC4A2E2, 0xFFC57310, 0xFFC6433E, 0xFFC7136C, 0xFFC7E39A, 0xFFC8B3C8, 0xFFC983F6, 0xFFCA5424, 0xFFCB2452, 0xFFCBF480, 0xFFCCC4AE, 0xFFCD94DC, 0xFFCE650A, 0xFFCF3538, 0xFFD00566, 0xFFD0D594, 0xFFD1A5C2, 0xFFD275F0, 0xFFD3461E, 0xFFD4164C, 0xFFD4E67A, 0xFFD5B6A8, 0xFFD686D6, 0xFFD75704, 0xFFD82732, 0xFFD8F760, 0xFFD9C78E, 0xFFDA97BC, 0xFFDB67EA, 0xFFDC3818, 0xFFDD0846, 0xFFDDD874, 0xFFDEA8A2, 0xFFDF78D0, 0xFFE048FE, 0xFFE1192C, 0xFFE1E95A, 0xFFE2B988, 0xFFE389B6, 0xFFE459E4, 0xFFE52A12, 0xFFE5FA40, 0xFFE6CA6E, 0xFFE79A9C, 0xFFE86ACA, 0xFFE93AF8, 0xFFEA0B26, 0xFFEADB54, 0xFFEBAB82, 0xFFEC7BB0, 0xFFED4BDE, 0xFFEE1C0C, 0xFFEEEC3A, 0xFFEFBC68, 0xFFF08C96, 0xFFF15CC4, 0xFFF22CF2, 0xFFF2FD20, 0xFFF3CD4E, 0xFFF49D7C, 0xFFF56DAA, 0xFFF63DD8, 0xFFF70E06, 0xFFF7DE34, 0xFFF8AE62, 0xFFF97E90, 0xFFFA4EBE, 0xFFFB1EEC, 0xFFFBEF1A, 0xFFFCBF48, 0xFFFD8F76, 0xFFFE5FA4, 0xFFFF2FD2, 0x0, 0xD02E, 0x1A05C, 0x2708A, 0x340B8, 0x410E6, 0x4E114, 0x5B142, 0x68170, 0x7519E, 0x821CC, 0x8F1FA, 0x9C228, 0xA9256, 0xB6284, 0xC32B2, 0xD02E0, 0xDD30E, 0xEA33C, 0xF736A, 0x104398, 0x1113C6, 0x11E3F4, 0x12B422, 0x138450, 0x14547E, 0x1524AC, 0x15F4DA, 0x16C508, 0x179536, 0x186564, 0x193592, 0x1A05C0, 0x1AD5EE, 0x1BA61C, 0x1C764A, 0x1D4678, 0x1E16A6, 0x1EE6D4, 0x1FB702, 0x208730, 0x21575E, 0x22278C, 0x22F7BA, 0x23C7E8, 0x249816, 0x256844, 0x263872, 0x2708A0, 0x27D8CE, 0x28A8FC, 0x29792A, 0x2A4958, 0x2B1986, 0x2BE9B4, 0x2CB9E2, 0x2D8A10, 0x2E5A3E, 0x2F2A6C, 0x2FFA9A, 0x30CAC8, 0x319AF6, 0x326B24, 0x333B52, 0x340B80, 0x34DBAE, 0x35ABDC, 0x367C0A, 0x374C38, 0x381C66, 0x38EC94, 0x39BCC2, 0x3A8CF0, 0x3B5D1E, 0x3C2D4C, 0x3CFD7A, 0x3DCDA8, 0x3E9DD6, 0x3F6E04, 0x403E32, 0x410E60, 0x41DE8E, 0x42AEBC, 0x437EEA, 0x444F18, 0x451F46, 0x45EF74, 0x46BFA2, 0x478FD0, 0x485FFE, 0x49302C, 0x4A005A, 0x4AD088, 0x4BA0B6, 0x4C70E4, 0x4D4112, 0x4E1140, 0x4EE16E, 0x4FB19C, 0x5081CA, 0x5151F8, 0x522226, 0x52F254, 0x53C282, 0x5492B0, 0x5562DE, 0x56330C, 0x57033A, 0x57D368, 0x58A396, 0x5973C4, 0x5A43F2, 0x5B1420, 0x5BE44E, 0x5CB47C, 0x5D84AA, 0x5E54D8, 0x5F2506, 0x5FF534, 0x60C562, 0x619590, 0x6265BE, 0x6335EC, 0x64061A, 0x64D648, 0x65A676, 0x6676A4, 0x6746D2
77 };
78 static const int yuv2rgbtable_bv[256] = {
79 0xFF33A280, 0xFF353B3B, 0xFF36D3F6, 0xFF386CB1, 0xFF3A056C, 0xFF3B9E27, 0xFF3D36E2, 0xFF3ECF9D, 0xFF406858, 0xFF420113, 0xFF4399CE, 0xFF453289, 0xFF46CB44, 0xFF4863FF, 0xFF49FCBA, 0xFF4B9575, 0xFF4D2E30, 0xFF4EC6EB, 0xFF505FA6, 0xFF51F861, 0xFF53911C, 0xFF5529D7, 0xFF56C292, 0xFF585B4D, 0xFF59F408, 0xFF5B8CC3, 0xFF5D257E, 0xFF5EBE39, 0xFF6056F4, 0xFF61EFAF, 0xFF63886A, 0xFF652125, 0xFF66B9E0, 0xFF68529B, 0xFF69EB56, 0xFF6B8411, 0xFF6D1CCC, 0xFF6EB587, 0xFF704E42, 0xFF71E6FD, 0xFF737FB8, 0xFF751873, 0xFF76B12E, 0xFF7849E9, 0xFF79E2A4, 0xFF7B7B5F, 0xFF7D141A, 0xFF7EACD5, 0xFF804590, 0xFF81DE4B, 0xFF837706, 0xFF850FC1, 0xFF86A87C, 0xFF884137, 0xFF89D9F2, 0xFF8B72AD, 0xFF8D0B68, 0xFF8EA423, 0xFF903CDE, 0xFF91D599, 0xFF936E54, 0xFF95070F, 0xFF969FCA, 0xFF983885, 0xFF99D140, 0xFF9B69FB, 0xFF9D02B6, 0xFF9E9B71, 0xFFA0342C, 0xFFA1CCE7, 0xFFA365A2, 0xFFA4FE5D, 0xFFA69718, 0xFFA82FD3, 0xFFA9C88E, 0xFFAB6149, 0xFFACFA04, 0xFFAE92BF, 0xFFB02B7A, 0xFFB1C435, 0xFFB35CF0, 0xFFB4F5AB, 0xFFB68E66, 0xFFB82721, 0xFFB9BFDC, 0xFFBB5897, 0xFFBCF152, 0xFFBE8A0D, 0xFFC022C8, 0xFFC1BB83, 0xFFC3543E, 0xFFC4ECF9, 0xFFC685B4, 0xFFC81E6F, 0xFFC9B72A, 0xFFCB4FE5, 0xFFCCE8A0, 0xFFCE815B, 0xFFD01A16, 0xFFD1B2D1, 0xFFD34B8C, 0xFFD4E447, 0xFFD67D02, 0xFFD815BD, 0xFFD9AE78, 0xFFDB4733, 0xFFDCDFEE, 0xFFDE78A9, 0xFFE01164, 0xFFE1AA1F, 0xFFE342DA, 0xFFE4DB95, 0xFFE67450, 0xFFE80D0B, 0xFFE9A5C6, 0xFFEB3E81, 0xFFECD73C, 0xFFEE6FF7, 0xFFF008B2, 0xFFF1A16D, 0xFFF33A28, 0xFFF4D2E3, 0xFFF66B9E, 0xFFF80459, 0xFFF99D14, 0xFFFB35CF, 0xFFFCCE8A, 0xFFFE6745, 0x0, 0x198BB, 0x33176, 0x4CA31, 0x662EC, 0x7FBA7, 0x99462, 0xB2D1D, 0xCC5D8, 0xE5E93, 0xFF74E, 0x119009, 0x1328C4, 0x14C17F, 0x165A3A, 0x17F2F5, 0x198BB0, 0x1B246B, 0x1CBD26, 0x1E55E1, 0x1FEE9C, 0x218757, 0x232012, 0x24B8CD, 0x265188, 0x27EA43, 0x2982FE, 0x2B1BB9, 0x2CB474, 0x2E4D2F, 0x2FE5EA, 0x317EA5, 0x331760, 0x34B01B, 0x3648D6, 0x37E191, 0x397A4C, 0x3B1307, 0x3CABC2, 0x3E447D, 0x3FDD38, 0x4175F3, 0x430EAE, 0x44A769, 0x464024, 0x47D8DF, 0x49719A, 0x4B0A55, 0x4CA310, 0x4E3BCB, 0x4FD486, 0x516D41, 0x5305FC, 0x549EB7, 0x563772, 0x57D02D, 0x5968E8, 0x5B01A3, 0x5C9A5E, 0x5E3319, 0x5FCBD4, 0x61648F, 0x62FD4A, 0x649605, 0x662EC0, 0x67C77B, 0x696036, 0x6AF8F1, 0x6C91AC, 0x6E2A67, 0x6FC322, 0x715BDD, 0x72F498, 0x748D53, 0x76260E, 0x77BEC9, 0x795784, 0x7AF03F, 0x7C88FA, 0x7E21B5, 0x7FBA70, 0x81532B, 0x82EBE6, 0x8484A1, 0x861D5C, 0x87B617, 0x894ED2, 0x8AE78D, 0x8C8048, 0x8E1903, 0x8FB1BE, 0x914A79, 0x92E334, 0x947BEF, 0x9614AA, 0x97AD65, 0x994620, 0x9ADEDB, 0x9C7796, 0x9E1051, 0x9FA90C, 0xA141C7, 0xA2DA82, 0xA4733D, 0xA60BF8, 0xA7A4B3, 0xA93D6E, 0xAAD629, 0xAC6EE4, 0xAE079F, 0xAFA05A, 0xB13915, 0xB2D1D0, 0xB46A8B, 0xB60346, 0xB79C01, 0xB934BC, 0xBACD77, 0xBC6632, 0xBDFEED, 0xBF97A8, 0xC13063, 0xC2C91E, 0xC461D9, 0xC5FA94, 0xC7934F, 0xC92C0A, 0xCAC4C5
80 };
81
82 static bool getvideo(unsigned char *video, unsigned int *xres, unsigned int *yres);
83 static bool getosd(unsigned char *osd, unsigned int *xres, unsigned int *yres);
84
85 static void smooth_resize(const unsigned char *source, unsigned char *dest,
86                           unsigned int xsource, unsigned int ysource,
87                           unsigned int xdest, unsigned int ydest,
88                           unsigned int colors);
89
90 static void fast_resize(const unsigned char *source, unsigned char *dest,
91                         unsigned int xsource, unsigned int ysource,
92                         unsigned int xdest, unsigned int ydest,
93                         unsigned int colors);
94
95 static void (*resize)(const unsigned char *source, unsigned char *dest,
96                       unsigned int xsource, unsigned int ysource,
97                       unsigned int xdest, unsigned int ydest,
98                       unsigned int colors);
99
100 static void combine(unsigned char *output,
101                     const unsigned char *video, const unsigned char *osd,
102                     unsigned int xres, unsigned int yres);
103
104 enum {UNKNOWN,PALLAS,VULCAN,XILLEON,BRCM7401,BRCM7400,BRCM7405,BRCM7435,BRCM73625,BRCM7439};
105 enum {BGR,RGB};
106 static const char *stb_name[]={"unknown","Pallas","Vulcan","Xilleon","Brcm7401","Brcm7400","Brcm7405","Brcm7435","Brcm73625","Brcm7439"};
107 static int stb_type=UNKNOWN;
108 static int byte_order=BGR;
109
110 static const char *file_getline(const char *filename)
111 {
112         static char *line = NULL;
113         static size_t n = 0;
114         ssize_t ret;
115         FILE *f;
116
117         f = fopen(filename, "r");
118         if (f == NULL) {
119                 perror(filename);
120                 return NULL;
121         }
122
123         ret = getline(&line, &n, f);
124
125         fclose(f);
126
127         if (ret < 0)
128                 return NULL;
129
130         while (ret-- > 0) {
131                 if ((line[ret] != '\n') &&
132                     (line[ret] != '\r'))
133                         break;
134                 line[ret] = '\0';
135         }
136
137         return line;
138 }
139
140 static int file_scanf_line(const char *filename, const char *fmt, ...)
141 {
142         const char *line = file_getline(filename);
143         va_list ap;
144         int ret;
145
146         if (line == NULL)
147                 return -1;
148
149         va_start(ap, fmt);
150         ret = vsscanf(line, fmt, ap);
151         va_end(ap);
152
153         return ret;
154 }
155
156 static int file_scanf_lines(const char *filename, const char *fmt, ...)
157 {
158         char *line = NULL;
159         size_t n = 0;
160         int ret = 0;
161         va_list ap;
162         FILE *f;
163
164         f = fopen(filename, "r");
165         if (f == NULL) {
166                 perror(filename);
167                 return -1;
168         }
169
170         va_start(ap, fmt);
171
172         while (getline(&line, &n, f) >= 0) {
173                 ret = vsscanf(line, fmt, ap);
174                 if (ret > 0)
175                         break;
176         }
177
178         if (line)
179                 free(line);
180
181         va_end(ap);
182
183         fclose(f);
184
185         return ret;
186 }
187
188 // main program
189
190 int main(int argc, char **argv) {
191
192         printf("AiO Dreambox Screengrabber " PACKAGE_VERSION "\n\n");
193
194         unsigned int xres_v = 0,yres_v = 0,xres_o,yres_o,xres,yres,aspect,width;
195         int c,osd_only,video_only,use_osd_res,use_png,use_jpg,jpg_quality,no_aspect,use_letterbox;
196
197         // we use fast resize as standard now
198         resize = &fast_resize;
199
200         osd_only=video_only=use_osd_res=width=use_png=use_jpg=no_aspect=use_letterbox=0;
201         jpg_quality=50;
202         aspect=1;
203
204         unsigned char *video, *osd, *output;
205         unsigned int output_bytes = 3;
206
207         char filename[256] = { "/tmp/screenshot.bmp" };
208
209         // detect STB
210         const char *line = file_getline("/proc/fb");
211         if (line == NULL)
212                 return 1;
213
214         if (strstr(line, "bcmfb")) {
215                 line = file_getline("/proc/stb/info/model");
216                 if (line == NULL)
217                         return 1;
218                 if (!strcmp(line, "dm8000"))
219                         stb_type = BRCM7400;
220                 else if (!strcmp(line, "dm800"))
221                         stb_type = BRCM7401;
222                 else if (!strcmp(line, "dm500hdv2") ||
223                          !strcmp(line, "dm500hd") ||
224                          !strcmp(line, "dm800sev2") ||
225                          !strcmp(line, "dm800se") ||
226                          !strcmp(line, "dm7020hd"))
227                         stb_type = BRCM7405;
228                 else if (!strcmp(line, "dm820") ||
229                          !strcmp(line, "dm7080"))
230                         stb_type = BRCM7435;
231                 else if (!strcmp(line, "dm520") ||
232                          !strcmp(line, "dm525"))
233                         stb_type = BRCM73625;
234                 else if (!strcmp(line, "dm900") ||
235                          !strcmp(line, "dm920"))
236                         stb_type = BRCM7439;
237
238         } else if (strstr(line, "xilleonfb")) {
239                 stb_type = XILLEON;
240         } else if (strstr(line, "Pallas FB")) {
241                 stb_type = PALLAS;
242         } else if (strstr(line, "vulcanfb")) {
243                 stb_type = VULCAN;
244         }
245
246         if (stb_type == UNKNOWN) {
247                 printf("Unknown STB .. quit.\n");
248                 return 1;
249         }
250
251         printf("Detected STB: %s\n",stb_name[stb_type]);
252
253         // process command line
254         while ((c = getopt (argc, argv, "dhj:lbnopr:v")) != -1)
255         {
256                 switch (c)
257                 {
258                         case 'h':
259                         case '?':
260                                 printf("Usage: grab [commands] [filename]\n\n");
261                                 printf("command:\n");
262                                 printf("-o only grab osd (framebuffer) when using this with png or bmp\n   fileformat you will get a 32bit pic with alphachannel\n");
263                                 printf("-v only grab video\n");
264                                 printf("-d always use osd resolution (good for skinshots)\n");
265                                 printf("-n dont correct 16:9 aspect ratio\n");
266                                 printf("-r (size) resize to a fixed width, maximum: 1920\n");
267                                 printf("-l always 4:3, create letterbox if 16:9\n");
268                                 printf("-b use bicubic picture resize (slow but smooth)\n");
269                                 printf("-j (quality) produce jpg files instead of bmp (quality 0-100)\n");      
270                                 printf("-p produce png files instead of bmp\n");
271                                 printf("-h this help screen\n\n");
272
273                                 printf("If no command is given the complete picture will be grabbed.\n");
274                                 printf("If no filename is given /tmp/screenshot.[bmp/jpg/png] will be used.\n");
275                                 return 0;
276                                 break;
277                         case 'o': // OSD only
278                                 osd_only=1;
279                                 video_only=0;   
280                                 break;
281                         case 'v': // Video only
282                                 video_only=1;
283                                 osd_only=0;
284                                 break;
285                         case 'd': // always use OSD resolution
286                                 use_osd_res=1;
287                                 no_aspect=1;
288                                 break;
289                         case 'r': // use given resolution
290                                 width=atoi(optarg);
291                                 if (width > 1920)
292                                 {
293                                         printf("Error: -r (size) ist limited to 1920 pixel !\n");
294                                         return 1;
295                                 }
296                                 break;
297                         case 'l': // create letterbox
298                                 use_letterbox=1;
299                                 break;
300                         case 'b': // use bicubic resizing
301                                 resize = &smooth_resize;
302                                 break;                  
303                         case 'p': // use png file format
304                                 use_png=1;
305                                 use_jpg=0;      
306                                 strcpy(filename,"/tmp/screenshot.png");
307                                 break;
308                         case 'j': // use jpg file format
309                                 use_jpg=1;
310                                 use_png=0;
311                                 jpg_quality=atoi(optarg);
312                                 strcpy(filename,"/tmp/screenshot.jpg");
313                                 break;
314                         case 'n':
315                                 no_aspect=1;
316                                 break;
317                 } 
318         }
319         if (optind < argc) // filename
320                 strcpy(filename, argv[optind]);
321
322         unsigned int mallocsize = 1920 * 1080;
323         if (stb_type == VULCAN || stb_type == PALLAS)
324                 mallocsize = 720 * 576;
325
326         video = malloc(mallocsize * 3);
327         assert(video);
328         osd = malloc(mallocsize * 4);
329         assert(osd);
330
331         if ((stb_type == VULCAN || stb_type == PALLAS) && width > 720)
332                 mallocsize = width * (width * 0.8 + 1);
333         
334         output = malloc(mallocsize * 4);
335         assert(output);
336
337         // get osd
338         xres_o = yres_o = 0;
339         if (!video_only && !getosd(osd, &xres_o, &yres_o))
340                 return 1;
341
342         // get video
343         if (!osd_only && !getvideo(video, &xres_v, &yres_v))
344                 return 1;
345
346         // get aspect ratio
347         if (stb_type == VULCAN || stb_type == PALLAS)
348                 file_scanf_lines("/proc/bus/bitstream", "A_RATIO: %d", &aspect);
349         else
350                 file_scanf_line("/proc/stb/vmpeg/0/aspect", "%x", &aspect);
351
352         // resizing
353         if (video_only)
354         {
355                 xres=xres_v;
356                 yres=yres_v;
357         } else if (osd_only)
358         {
359                 xres=xres_o;
360                 yres=yres_o;
361         } else if (xres_o == xres_v && yres_o == yres_v)
362         {
363                 xres=xres_v;
364                 yres=yres_v;
365         } else
366         {
367                 if (xres_v > xres_o && !use_osd_res && (width == 0 || width > xres_o))
368                 {
369                         // resize osd to video size
370                         printf("Resizing OSD to %d x %d ...\n",xres_v,yres_v);  
371                         resize(osd,output,xres_o,yres_o,xres_v,yres_v,4);
372                         memcpy(osd,output,xres_v*yres_v*4);
373                         xres=xres_v;
374                         yres=yres_v;
375                 } else
376                 {
377                         // resize video to osd size
378                         printf("Resizing Video to %d x %d ...\n",xres_o,yres_o);        
379                         resize(video,output,xres_v,yres_v,xres_o,yres_o,3);
380                         memcpy(video,output,xres_o*yres_o*3);
381                         xres=xres_o;
382                         yres=yres_o;
383                 }       
384         }
385         
386
387         // merge video and osd if neccessary
388         if (osd_only)
389         {
390                 memcpy(output,osd,xres*yres*4);
391                 output_bytes=4;
392         }
393         else if (video_only)
394                 memcpy(output,video,xres*yres*3);
395         else 
396         {
397                 printf("Merge Video with Framebuffer ...\n");
398                 combine(output,video,osd,xres,yres);
399         }
400
401         
402         // resize to specific width ?
403         if (width)
404         {
405                 printf("Resizing Screenshot to %d x %d ...\n",width,yres*width/xres);
406                 resize(output,osd,xres,yres,width,(yres*width/xres),output_bytes);
407                 yres=yres*width/xres;
408                 xres=width;
409                 memcpy(output,osd,xres*yres*output_bytes);
410         }
411         
412
413         // correct aspect ratio
414         if (!no_aspect && aspect == 3 && ((float)xres/(float)yres)<1.5)
415         {
416                 printf("Correct aspect ratio to 16:9 ...\n");
417                 resize(output,osd,xres,yres,xres,yres/1.42,output_bytes);
418                 yres/=1.42;
419                 memcpy(output,osd,xres*yres*output_bytes);
420         }
421
422         // use letterbox ?
423         if (use_letterbox && xres*0.8 != yres && xres*0.8 <= 1080)
424         {
425                 unsigned int yres_neu = xres * 0.8;
426                 printf("Create letterbox %d x %d ...\n",xres,yres_neu);         
427                 if (yres_neu > yres) {
428                         unsigned int ofs = (yres_neu - yres) >> 1;
429                         memmove(output+ofs*xres*output_bytes,output,xres*yres*output_bytes);
430                         memset(output,0,ofs*xres*output_bytes);
431                         memset(output+ofs*xres*3+xres*yres*output_bytes,0,ofs*xres*output_bytes);
432                 }
433                 yres = yres_neu;
434         }
435
436         // saving picture
437         printf("Saving %d bit %s ...\n",(use_jpg?3*8:output_bytes*8),filename);
438         FILE *fd2 = fopen(filename, "wr");
439         if (!fd2) {
440                 perror(filename);
441                 return 1;
442         }
443
444         if (!use_png && !use_jpg)
445         {
446                 // write bmp
447                 unsigned char hdr[14 + 40];
448                 unsigned int i = 0;
449 #define PUT32(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); hdr[i++] = (((x)>>16)&0xFF); hdr[i++] = (((x)>>24)&0xFF);
450 #define PUT16(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF);
451 #define PUT8(x) hdr[i++] = ((x)&0xFF);
452                 PUT8('B'); PUT8('M');
453                 PUT32((((xres * yres) * 3 + 3) &~ 3) + 14 + 40);
454                 PUT16(0); PUT16(0); PUT32(14 + 40);
455                 PUT32(40); PUT32(xres); PUT32(yres);
456                 PUT16(1);
457                 PUT16(output_bytes*8); // bits
458                 PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0);
459 #undef PUT32
460 #undef PUT16
461 #undef PUT8
462                 fwrite(hdr, 1, i, fd2);
463                 
464                 int y;
465                 if (byte_order == RGB) {
466                         unsigned int x, x2, xres1, xres2;
467                         for (y=0; (unsigned int)y<yres; y++) {
468                                 xres1=y*xres*output_bytes;
469                                 xres2=xres1+2;
470                                 for (x=0; x<xres; x++) {
471                                         x2=x*output_bytes;
472                                         SWAP(output[x2+xres1],output[x2+xres2]);
473                                 }
474                         }
475                 }
476                 for (y=yres-1; y>=0 ; y-=1) {
477                         fwrite(output+(y*xres*output_bytes),xres*output_bytes,1,fd2);
478                 }
479         } else if (use_png)
480         {       
481                 // write png
482                 png_bytep *row_pointers;
483                 png_structp png_ptr;
484                 png_infop info_ptr;
485           
486                 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
487                 info_ptr = png_create_info_struct(png_ptr);
488                 png_init_io(png_ptr, fd2);
489
490                 row_pointers = malloc(sizeof(png_bytep) * yres);
491                 assert(row_pointers);
492
493                 unsigned int y;
494                 for (y=0; y<yres; y++)
495                         row_pointers[y]=output+(y*xres*output_bytes);
496                 
497                 if (byte_order == BGR)
498                         png_set_bgr(png_ptr);
499                 png_set_IHDR(png_ptr, info_ptr, xres, yres, 8, ((output_bytes<4)?PNG_COLOR_TYPE_RGB:PNG_COLOR_TYPE_RGBA) , PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
500                 png_write_info(png_ptr, info_ptr);
501                 png_write_image(png_ptr, row_pointers);
502                 png_write_end(png_ptr, info_ptr);
503                 png_destroy_write_struct(&png_ptr, &info_ptr);
504                 
505                 free(row_pointers);
506         } else 
507         {
508                 // write jpg
509 #if !defined(JCS_EXTENSIONS)
510                 unsigned int x,y,xres1,xres2,x2;
511                 if (output_bytes == 3 && byte_order == BGR) // swap bgr<->rgb
512                 {
513                         for (y=0; y<yres; y++)
514                         {
515                                 xres1=y*xres*3;
516                                 xres2=xres1+2;
517                                 for (x=0; x<xres; x++)
518                                 {
519                                         x2=x*3;
520                                         SWAP(output[x2+xres1],output[x2+xres2]);
521                                 }
522                         }
523                 }
524                 else if (output_bytes == 4) // swap bgr<->rgb and eliminate alpha channel jpgs are always saved with 24bit without alpha channel
525                 {
526                         for (y=0; y<yres; y++)
527                         {
528                                 xres1=y*xres*3;
529                                 xres2=xres1+2;                          
530                                 for (x=0; x<xres; x++)
531                                 {
532                                         x2=x*3;
533                                         memcpy(output+x2+xres1,output+x*4+y*xres*4,3);
534                                         if (byte_order == BGR)
535                                                 SWAP(output[x2+xres1],output[x2+xres2]);
536                                 }
537                         }
538                         output_bytes = 3;
539                 }
540 #endif
541
542                 struct jpeg_compress_struct cinfo;
543                 struct jpeg_error_mgr jerr;
544                 JSAMPROW row_pointer[1];        
545                 unsigned int row_stride;                
546                 cinfo.err = jpeg_std_error(&jerr);
547
548                 jpeg_create_compress(&cinfo);
549                 jpeg_stdio_dest(&cinfo, fd2);
550                 cinfo.image_width = xres;       
551                 cinfo.image_height = yres;
552                 cinfo.input_components = output_bytes;
553 #if defined(JCS_EXTENSIONS)
554                 if (output_bytes == 3)
555                         cinfo.in_color_space = (byte_order == BGR) ? JCS_EXT_BGR : JCS_EXT_RGB;
556                 else
557                         cinfo.in_color_space = (byte_order == BGR) ? JCS_EXT_BGRA : JCS_EXT_RGBA;
558 #else
559                 cinfo.in_color_space = JCS_RGB;
560 #endif
561                 cinfo.dct_method = JDCT_IFAST;
562                 jpeg_set_defaults(&cinfo);
563                 jpeg_set_quality(&cinfo,jpg_quality, TRUE);
564                 jpeg_start_compress(&cinfo, TRUE);
565                 row_stride = xres * output_bytes;
566                 while (cinfo.next_scanline < cinfo.image_height) 
567                 {
568                         row_pointer[0] = & output[cinfo.next_scanline * row_stride];
569                         (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
570                 }
571                 jpeg_finish_compress(&cinfo);
572                 jpeg_destroy_compress(&cinfo);
573         }
574         
575         fclose(fd2);    
576         
577         // Thats all folks 
578         printf("... Done !\n");
579         
580         // clean up
581         free(video);
582         free(osd);
583         free(output);
584
585         return 0;
586 }
587
588 // grabing the video picture
589
590 static bool getvideo(unsigned char *video, unsigned int *xres, unsigned int *yres)
591 {
592         unsigned char *luma = NULL, *chroma = NULL;
593         unsigned int stride = 0, res = 0;
594         int mem_fd;
595
596         printf("Grabbing Video ...\n");
597
598         mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
599         if (mem_fd < 0) {
600                 perror("/dev/mem");
601                 return false;
602         }
603
604         if (stb_type == BRCM7401 || stb_type == BRCM7400 || stb_type == BRCM7405 || stb_type == BRCM7435 || stb_type == BRCM73625 || stb_type == BRCM7439)
605         {
606                 // grab brcm7401 pic from decoder memory
607                 unsigned long base;
608                 if (stb_type == BRCM7435 || stb_type == BRCM73625)
609                         base = 0x10600000;
610                 else if (stb_type == BRCM7439)
611                         base = 0xf0600000;
612                 else
613                         base = 0x10100000;
614
615                 unsigned char *memory = mmap(0, 0x1000, PROT_READ, MAP_SHARED, mem_fd, base);
616                 if (memory == MAP_FAILED) {
617                         perror("mmap");
618                         return false;
619                 }
620
621                 unsigned char data[100];
622
623                 unsigned int adr,adr2,ofs,ofs2,offset/*,vert_start,vert_end*/;
624                 unsigned int xsub,ytmp;
625                 unsigned int xtmp;
626
627                 memcpy(data,memory,100);
628
629                 //vert_start=data[0x1B]<<8|data[0x1A];
630                 //vert_end=data[0x19]<<8|data[0x18];
631                 if (stb_type == BRCM7435) {
632                         stride=data[0x15]<<8|data[0x14];
633                         ofs=((data[0x3d]<<8|data[0x3c])&0x3ff)<<4;
634                         ofs2=((data[0x41]<<8|data[0x40])&0x3ff)<<4;
635                         adr=(data[0x1f]<<24|data[0x1e]<<16|data[0x1d]<<8|data[0x1c])&0xFFFFFF00;
636                         adr2=(data[0x37]<<24|data[0x36]<<16|data[0x35]<<8|data[0x34])&0xFFFFFF00;
637                 } else if (stb_type == BRCM73625 || stb_type == BRCM7439) {
638                         stride=data[0x19]<<8|data[0x18];
639                         ofs=((data[0x55]<<8|data[0x54])&0x3ff)<<4;
640                         ofs2=((data[0x59]<<8|data[0x58])&0x3ff)<<4;
641                         adr=(data[0x37]<<24|data[0x36]<<16|data[0x35]<<8|data[0x34])&0xFFFFFF00;
642                         adr2=(data[0x3f]<<24|data[0x3e]<<16|data[0x3d]<<8|data[0x3c])&0xFFFFFF00;
643                 } else {
644                         stride=data[0x15]<<8|data[0x14];
645                         ofs=((data[0x29]<<8|data[0x28])&0x3ff)<<4;
646                         ofs2=((data[0x2d]<<8|data[0x2c])&0x3ff)<<4;
647                         adr=(data[0x1f]<<24|data[0x1e]<<16|data[0x1d]<<8|data[0x1c])&0xFFFFFF00;
648                         adr2=(data[0x23]<<24|data[0x22]<<16|data[0x21]<<8|data[0x20])&0xFFFFFF00;
649                 }
650
651                 offset=adr2-adr;
652
653                 munmap(memory, 100);
654
655 //              printf("Stride: %d Res: %d\n",stride,res);
656 //              printf("Adr: %X Adr2: %X OFS: %d %d, offs calced %d(hex %x)\n",adr,adr2,ofs,ofs2,offset,offset);
657
658                 // Check that obtained values are sane and prevent segfaults.
659                 if ((adr == 0) || (adr2 == 0) || (adr2 <= adr))
660                 {
661                         printf("Got or invalid 'adr' offsets, aborting (%x,%x)\n", adr, adr2);
662                         return false;
663                 }
664
665                 file_scanf_line("/proc/stb/vmpeg/0/yres", "%x", &res);
666
667                 luma = malloc(stride * ofs);
668                 assert(luma);
669                 chroma = malloc(stride * (ofs2 + 64));
670                 assert(chroma);
671
672                 // grabbing luma & chroma plane from the decoder memory
673                 if (stb_type == BRCM7401 || stb_type == BRCM7405 || stb_type == BRCM7435 || stb_type == BRCM73625 || stb_type == BRCM7439) {
674                         // on dm800/dm500hd we have direct access to the decoder memory
675                         memory = mmap(0, offset + stride*(ofs2+64), PROT_READ, MAP_SHARED, mem_fd, adr);
676 //                      printf("mapped %d bytes at %08x, end %08x\n",offset + stride * (ofs2 + 64), adr, adr + offset + stride * (ofs2 + 64));
677                         if (memory == MAP_FAILED) {
678                                 perror("mmap");
679                                 return false;
680                         }
681                         
682                         usleep(50000);  // we try to get a full picture, its not possible to get a sync from the decoder so we use a delay
683                                         // and hope we get a good timing. dont ask me why, but every DM800 i tested so far produced a good
684                                         // result with a 50ms delay
685                 } else if (stb_type == BRCM7400) { 
686                         // on dm8000 we have to use dma, so dont change anything here until you really know what you are doing !
687                         
688                         unsigned int i = 0;
689                         unsigned int tmp_len = DMA_BLOCKSIZE;
690                         unsigned int tmp_size = offset + stride * (ofs2 + 64);
691                         if (tmp_size > 2 * DMA_BLOCKSIZE)
692                         {
693                                 printf("DMA length exceeds maximum (0x%x)\n", tmp_size);
694                                 return false;
695                         }
696
697                         memory = mmap(0, DMA_BLOCKSIZE + 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, SPARE_RAM);
698                         if (memory == MAP_FAILED) {
699                                 perror("mmap");
700                                 return false;
701                         }
702
703                         volatile unsigned long *mem_dma;
704                         mem_dma = mmap(0, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x10c02000);
705                         if (mem_dma == MAP_FAILED) {
706                                 perror("mmap");
707                                 return false;
708                         }
709
710                         for (i=0; i < tmp_size; i += DMA_BLOCKSIZE)
711                         {
712                                 unsigned long *descriptor = (void*)memory;
713
714                                 if (i + DMA_BLOCKSIZE > tmp_size)
715                                         tmp_len = tmp_size - i;
716                                 
717                                 descriptor[0] = /* READ */ adr + i;
718                                 descriptor[1] = /* WRITE */ SPARE_RAM + 0x1000;
719                                 descriptor[2] = 0x40000000 | /* LEN */ tmp_len;
720                                 descriptor[3] = 2;
721                                 descriptor[4] = 0;
722                                 descriptor[5] = 0;
723                                 descriptor[6] = 0;
724                                 descriptor[7] = 0;
725                                 mem_dma[1] = /* FIRST_DESCRIPTOR */ SPARE_RAM;
726                                 mem_dma[3] = /* DMA WAKE CTRL */ 3;
727                                 mem_dma[2] = 1;
728                                 while (mem_dma[5] == 1)
729                                         usleep(2);
730                                 mem_dma[2] = 0;
731                         }
732
733                         munmap((void *)mem_dma, 0x1000);
734                         memory += 0x1000;
735                 }
736
737                 unsigned int t = 0, t2 = 0, dat1 = 0;
738                 unsigned int chr_luma_stride = 0x40;
739
740                 if (stb_type == BRCM7405 || stb_type == BRCM7435 || stb_type == BRCM7439)
741                         chr_luma_stride *= 2;
742
743                 xsub = chr_luma_stride;
744
745                 // decode luma & chroma plane or lets say sort it
746                 for (xtmp=0; xtmp < stride; xtmp += chr_luma_stride)
747                 {
748                         if ((stride-xtmp) <= chr_luma_stride)
749                                 xsub=stride-xtmp;
750
751                         dat1 = xtmp;
752
753                         for (ytmp = 0; ytmp < ofs; ytmp++)
754                         {
755 #if defined(__arm__)
756                                 if (t & 0x100)
757                                 {
758                                         int cp = xsub % 0x20 ?: 0x20; // cp = xsub % 0x20 ? xsub % 0x20 : 0x20;
759                                         switch (xsub)
760                                         {
761                                                 case 0x61 ... 0x80:
762                                                         memcpy(luma + dat1 + 0x60, memory + t + 0x40, cp);
763                                                         cp = 0x20;
764                                                 case 0x41 ... 0x60:
765                                                         memcpy(luma + dat1 + 0x40, memory + t + 0x60, cp);
766                                                         cp = 0x20;
767                                                 case 0x21 ... 0x40:
768                                                         memcpy(luma + dat1 + 0x20, memory + t + 0x00, cp);
769                                                         cp = 0x20;
770                                                 default:
771                                                         memcpy(luma + dat1 + 0x00, memory + t + 0x20, cp);
772                                         }
773                                 }
774                                 else
775 #endif
776                                         memcpy(luma + dat1, memory + t, xsub); // luma
777
778                                 if ((int)(ofs2-ytmp) > 0)
779                                 {
780 #if defined(__arm__)
781                                         if (t2 & 0x100)
782                                         {
783                                                 int cp = xsub % 0x20 ?: 0x20;
784                                                 switch (xsub)
785                                                 {
786                                                         case 0x61 ... 0x80:
787                                                                 memcpy(chroma + dat1 + 0x60, memory + offset + t2 + 0x40, cp);
788                                                                 cp = 0x20;
789                                                         case 0x41 ... 0x60:
790                                                                 memcpy(chroma + dat1 + 0x40, memory + offset + t2 + 0x60, cp);
791                                                                 cp = 0x20;
792                                                         case 0x21 ... 0x40:
793                                                                 memcpy(chroma + dat1 + 0x20, memory + offset + t2 + 0x00, cp);
794                                                                 cp = 0x20;
795                                                         default:
796                                                                 memcpy(chroma + dat1 + 0x00, memory + offset + t2 + 0x20, cp);
797                                                 }
798                                         }
799                                         else
800 #endif
801                                                 memcpy(chroma + dat1, memory + offset + t2, xsub); // chroma
802
803                                                 t2 += chr_luma_stride;
804                                 }
805
806                                 t += chr_luma_stride;
807                                 dat1 += stride;
808                         }
809                 }
810
811                 if (stb_type == BRCM7401 || stb_type == BRCM7405 || stb_type == BRCM7435 || stb_type == BRCM73625 || stb_type == BRCM7439)
812                         munmap(memory, offset + stride * (ofs2 + 64));
813                 else if (stb_type == BRCM7400) {
814                         memory -= 0x1000;
815                         munmap(memory, DMA_BLOCKSIZE + 0x1000);
816                 }
817
818                 if (stb_type != BRCM7400) {
819                         for (t = 0; t < stride * ofs; t += 4) {
820                                 SWAP(luma[t    ], luma[t + 3]);
821                                 SWAP(luma[t + 1], luma[t + 2]);
822
823                                 if (t < stride * (ofs >> 1)) {
824                                         SWAP(chroma[t    ], chroma[t + 3]);
825                                         SWAP(chroma[t + 1], chroma[t + 2]);
826                                 }
827                         }
828                 }
829         } else if (stb_type == XILLEON) {
830                 // grab xilleon pic from decoder memory
831                 unsigned char *memory = mmap(0, 1920*1152*6, PROT_READ, MAP_SHARED, mem_fd, 0x6000000);
832                 if (memory == MAP_FAILED) {
833                         perror("mmap");
834                         return false;
835                 }
836
837                 luma = malloc(1920 * 1152);
838                 assert(luma);
839                 chroma = malloc(1920 * 576);
840                 assert(chroma);
841
842                 unsigned int offset = 1920 * 1152 * 5;  // offset for chroma buffer
843
844                 file_scanf_line("/proc/stb/vmpeg/0/xres", "%x", &stride);
845                 file_scanf_line("/proc/stb/vmpeg/0/yres", "%x", &res);
846
847                 unsigned char *frame_l = malloc(1920 * 1080); // luma frame from video decoder
848                 assert(frame_l);
849                 unsigned char *frame_c = malloc(1920 * 540); // chroma frame from video decoder
850                 assert(frame_c);
851
852                 // grab luma buffer from decoder memory 
853                 memcpy(frame_l,memory,1920*1080); 
854                 // grab chroma buffer from decoder memory
855                 memcpy(frame_c,memory+offset,1920*540);
856
857                 munmap(memory, 1920*1152*6);
858
859                 unsigned int xtmp, ytmp, xsub, ysub;
860                 const unsigned int ypart = 32;
861                 const unsigned int xpart = 128;
862                 unsigned int t = 0, t2 = 0, odd_even = 0;
863                 int oe2 = 0;
864
865                 // "decode" luma/chroma, there are 128x32pixel blocks inside the decoder mem
866                 for (ysub=0; ysub<(res/32)+1; ysub++) 
867                 {
868                         for (xsub=0; xsub<15; xsub++) // 1920/128=15
869                         {
870                                 for (ytmp=0; ytmp<ypart; ytmp++)
871                                 {
872                                         for (xtmp=0; xtmp< xpart; xtmp++)
873                                         {
874                                                 if (odd_even == 0)
875                                                         oe2=0;
876                                                 if (odd_even == 1 && xtmp < 64)
877                                                         oe2=64;
878                                                 if (odd_even == 1 && xtmp >= 64)
879                                                         oe2=-64;
880                                                 if (xsub*xpart+xtmp+oe2 < stride) 
881                                                         memcpy(luma+((xsub*xpart+oe2))+xtmp+(stride*(ytmp+(ysub*ypart))),frame_l+t,1); // luma
882                                                 if (ysub < (res/64)+1)
883                                                 {
884                                                         if (xsub*xpart+xtmp+oe2 < stride) 
885                                                                 memcpy(chroma+((xsub*xpart+oe2))+xtmp+(stride*(ytmp+(ysub*ypart))),frame_c+t,1); // chroma
886                                                         t2++;
887                                                 }
888                                                 t++;
889                                         }
890                                 }
891                         }
892                         odd_even^=1;
893                 }
894                 free(frame_l);
895                 free(frame_c);
896         } else if (stb_type == VULCAN || stb_type == PALLAS)
897         {
898                 // grab via v4l device (ppc boxes)
899                 
900                 unsigned char *memory = malloc(720 * 576 * 3 + 16);
901                 assert(memory);
902
903                 int fd_video = open(VIDEO_DEV, O_RDONLY);
904                 if (fd_video < 0) {
905                         perror(VIDEO_DEV);
906                         return false;
907                 }
908
909                 ssize_t r = read(fd_video, memory, 720 * 576 * 3 + 16);
910                 if (r < 16) {
911                         perror("read");
912                         close(fd_video);
913                         return false;
914                 }
915                 close(fd_video);
916
917                 int *size = (int*)memory;
918                 stride = size[0];
919                 res = size[1];
920
921                 luma = malloc(stride * res);
922                 assert(luma);
923                 chroma = malloc(stride * res);
924                 assert(chroma);
925
926                 memcpy(luma, memory + 16, stride * res);
927                 memcpy(chroma, memory + 16 + stride * res, stride * res);
928
929                 free(memory);
930         }
931
932         close(mem_fd);  
933         
934         int Y, U, V, y ,x, out1, pos, RU, GU, GV, BV, rgbstride, t;
935         Y=U=V=0;
936                 
937         // yuv2rgb conversion (4:2:0)
938         printf("... converting Video from YUV to RGB color space\n");
939         out1=pos=t=0;
940         rgbstride=stride*3;
941
942         unsigned int rpos, gpos, bpos;
943         if (byte_order == BGR) {
944                 rpos = 0;
945                 gpos = 1;
946                 bpos = 2;
947         } else {
948                 rpos = 2;
949                 gpos = 1;
950                 bpos = 0;
951         }
952
953         for (y=res; y != 0; y-=2)
954         {
955                 for (x=stride; x != 0; x-=2)
956                 {
957                         U=chroma[t++];
958                         V=chroma[t++];
959                         
960                         RU=yuv2rgbtable_ru[U]; // use lookup tables to speedup the whole thing
961                         GU=yuv2rgbtable_gu[U];
962                         GV=yuv2rgbtable_gv[V];
963                         BV=yuv2rgbtable_bv[V];
964                         
965                         // now we do 4 pixels on each iteration this is more code but much faster 
966                         Y=yuv2rgbtable_y[luma[pos]]; 
967
968                         video[out1+rpos]=CLAMP((Y + RU)>>16);
969                         video[out1+gpos]=CLAMP((Y - GV - GU)>>16);
970                         video[out1+bpos]=CLAMP((Y + BV)>>16);
971                         
972                         Y=yuv2rgbtable_y[luma[stride+pos]];
973
974                         video[out1+rpos+rgbstride]=CLAMP((Y + RU)>>16);
975                         video[out1+gpos+rgbstride]=CLAMP((Y - GV - GU)>>16);
976                         video[out1+bpos+rgbstride]=CLAMP((Y + BV)>>16);
977
978                         pos++;
979                         out1+=3;
980                         
981                         Y=yuv2rgbtable_y[luma[pos]];
982
983                         video[out1+rpos]=CLAMP((Y + RU)>>16);
984                         video[out1+gpos]=CLAMP((Y - GV - GU)>>16);
985                         video[out1+bpos]=CLAMP((Y + BV)>>16);
986                         
987                         Y=yuv2rgbtable_y[luma[stride+pos]];
988
989                         video[out1+rpos+rgbstride]=CLAMP((Y + RU)>>16);
990                         video[out1+gpos+rgbstride]=CLAMP((Y - GV - GU)>>16);
991                         video[out1+bpos+rgbstride]=CLAMP((Y + BV)>>16);
992                         
993                         out1+=3;
994                         pos++;
995                 }
996                 out1+=rgbstride;
997                 pos+=stride;
998
999         }
1000
1001         *xres=stride;
1002         *yres=res;
1003         printf("... Video-Size: %d x %d\n",*xres,*yres);
1004         if (luma)
1005                 free(luma);
1006         if (chroma)
1007                 free(chroma);
1008
1009         return true;
1010 }
1011
1012 // grabing the osd picture
1013
1014 static bool getosd(unsigned char *osd, unsigned int *xres, unsigned int *yres)
1015 {
1016         int fb,pos1,pos2,ofs;
1017         unsigned int x, y;
1018         unsigned char *lfb;
1019         struct fb_fix_screeninfo fix_screeninfo;
1020         struct fb_var_screeninfo var_screeninfo;
1021
1022         fb = open("/dev/fb0", O_RDWR);
1023         if (fb == -1) {
1024                 fb = open("/dev/fb/0", O_RDWR);
1025                 if (fb == -1) {
1026                         perror("fbdev");
1027                         return false;
1028                 }
1029         }
1030
1031         if (ioctl(fb, FBIOGET_FSCREENINFO, &fix_screeninfo) == -1) {
1032                 perror("FBIOGET_FSCREENINFO");
1033                 return false;
1034         }
1035
1036         if (ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) == -1) {
1037                 perror("FBIOGET_VSCREENINFO");
1038                 return false;
1039         }
1040         
1041         lfb = mmap(0, fix_screeninfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
1042         if (lfb == MAP_FAILED) {
1043                 perror("mmap");
1044                 return false;
1045         }
1046
1047         lfb += var_screeninfo.yoffset * fix_screeninfo.line_length;
1048
1049         if (var_screeninfo.red.offset < var_screeninfo.blue.offset)
1050                 byte_order = RGB;
1051
1052         if ( var_screeninfo.bits_per_pixel == 32 ) 
1053         {
1054                 printf("Grabbing 32bit Framebuffer ...\n");
1055         
1056                 // get 32bit framebuffer
1057                 pos1=pos2=0;
1058                 ofs=fix_screeninfo.line_length-(var_screeninfo.xres*4);
1059                 
1060                 if (ofs == 0) // we have no offset ? so do it the easy and fast way
1061                 {
1062                         memcpy(osd,lfb,fix_screeninfo.line_length*var_screeninfo.yres);
1063                 }
1064                 else // DM7025 have an offset, so we have to do it line for line
1065                 {
1066                         unsigned char *memory; // use additional buffer to speed up especially when using hd skins
1067                         memory = malloc(fix_screeninfo.line_length*var_screeninfo.yres);
1068                         assert(memory);
1069                         memcpy(memory,lfb,fix_screeninfo.line_length*var_screeninfo.yres);
1070                         for (y=0; y < var_screeninfo.yres; y+=1)
1071                                 memcpy(osd+y*var_screeninfo.xres*4,memory+y*fix_screeninfo.line_length,var_screeninfo.xres*4);
1072                         free(memory);
1073                 }
1074         } else if ( var_screeninfo.bits_per_pixel == 16 )
1075         {
1076                 printf("Grabbing 16bit Framebuffer ...\n");
1077                 unsigned short color;
1078                 
1079                 // get 16bit framebuffer
1080                 pos1=pos2=0;
1081                 ofs=fix_screeninfo.line_length-(var_screeninfo.xres*2);         
1082                 for (y=0; y < var_screeninfo.yres; y+=1)
1083                 {
1084                         for (x=0; x < var_screeninfo.xres; x+=1)
1085                         {
1086                                 color = lfb[pos2] << 8 | lfb[pos2+1];
1087                                 pos2+=2;
1088                                 
1089                                 osd[pos1++] = BLUE565(color); // b
1090                                 osd[pos1++] = GREEN565(color); // g
1091                                 osd[pos1++] = RED565(color); // r
1092                                 osd[pos1++]=0x00; // tr - there is no transparency in 16bit mode
1093                         }
1094                         pos2+=ofs;
1095                 } 
1096         } else if ( var_screeninfo.bits_per_pixel == 8 )
1097         {
1098                 printf("Grabbing 8bit Framebuffer ...\n");
1099                 unsigned short color;
1100         
1101                 // Read Color Palette directly from the main memory, because the FBIOGETCMAP is buggy on dream and didnt
1102                 // gives you the correct colortable !
1103                 int mem_fd;
1104                 unsigned char *memory;
1105                 unsigned short rd[256], gn[256], bl[256], tr[256];
1106                 
1107                 mem_fd = open("/dev/mem", O_RDWR);
1108                 if (mem_fd < 0) {
1109                         perror("/dev/mem");
1110                         return false;
1111                 }
1112
1113                 memory = mmap(0, fix_screeninfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, fix_screeninfo.smem_start - 0x1000);
1114                 if (memory == MAP_FAILED) {
1115                         perror("mmap");
1116                         return false;
1117                 }
1118
1119                 if (stb_type == VULCAN) // DM500/5620 stores the colors as a 16bit word with yuv values, so we have to convert :(
1120                 {
1121                         unsigned short yuv;
1122                         pos2 = 0;
1123                         for (pos1=16; pos1<(256*2)+16; pos1+=2)
1124                         {
1125                                 
1126                                 yuv = memory[pos1] << 8 | memory[pos1+1];
1127                         
1128                                 rd[pos2]=CLAMP((76310*(YFB(yuv)-16) + 104635*(CRFB(yuv)-128))>>16);
1129                                 gn[pos2]=CLAMP((76310*(YFB(yuv)-16) - 53294*(CRFB(yuv)-128) - 25690*(CBFB(yuv)-128))>>16);
1130                                 bl[pos2]=CLAMP((76310*(YFB(yuv)-16) + 132278*(CBFB(yuv)-128))>>16);
1131                         
1132                                 if (yuv == 0) // transparency is a bit tricky, there is a 2 bit blending value BFFB(yuv), but not really used
1133                                 {
1134                                         rd[pos2]=gn[pos2]=bl[pos2]=0;
1135                                         tr[pos2]=0x00;
1136                                 } else
1137                                         tr[pos2]=0xFF;
1138                                 
1139                                 pos2++;
1140                         }
1141                 } else if (stb_type == PALLAS) // DM70x0 stores the colors in plain rgb values
1142                 {
1143                         pos2 = 0;
1144                         for (pos1=32; pos1<(256*4)+32; pos1+=4)
1145                         {
1146                                 rd[pos2]=memory[pos1+1];
1147                                 gn[pos2]=memory[pos1+2];
1148                                 bl[pos2]=memory[pos1+3];
1149                                 tr[pos2]=memory[pos1];
1150                                 pos2++;
1151                         }
1152                 } else
1153                 {
1154                         printf("unsupported framebuffermode\n");
1155                         return false;
1156                 }
1157                 close(mem_fd);
1158                 
1159                 // get 8bit framebuffer
1160                 pos1=pos2=0;
1161                 ofs=fix_screeninfo.line_length-(var_screeninfo.xres);           
1162                 for (y=0; y < var_screeninfo.yres; y+=1)
1163                 {
1164                         for (x=0; x < var_screeninfo.xres; x+=1)
1165                         {
1166                                 color = lfb[pos2++];
1167                                 
1168                                 osd[pos1++] = bl[color]; // b
1169                                 osd[pos1++] = gn[color]; // g
1170                                 osd[pos1++] = rd[color]; // r
1171                                 osd[pos1++] = tr[color]; // tr
1172                         }
1173                         pos2+=ofs;
1174                 } 
1175         }
1176         close(fb);
1177
1178         *xres=var_screeninfo.xres;
1179         *yres=var_screeninfo.yres;
1180         printf("... Framebuffer-Size: %d x %d\n",*xres,*yres);
1181         return true;
1182 }
1183
1184 // bicubic pixmap resizing
1185
1186 static void smooth_resize(const unsigned char *source, unsigned char *dest,
1187                           unsigned int xsource, unsigned int ysource,
1188                           unsigned int xdest, unsigned int ydest,
1189                           unsigned int colors)
1190 {
1191         unsigned int xs,ys,xd,yd,dpixel,fx,fy;
1192         unsigned int c,tmp_i;
1193         unsigned int t,t1;
1194         unsigned int x, y;
1195         xs=xsource; // x-resolution source
1196         ys=ysource; // y-resolution source
1197         xd=xdest; // x-resolution destination
1198         yd=ydest; // y-resolution destination
1199         
1200         // get x scale factor, use bitshifting to get rid of floats
1201         fx=((xs-1)<<16)/xd;
1202
1203         // get y scale factor, use bitshifting to get rid of floats
1204         fy=((ys-1)<<16)/yd;
1205
1206         unsigned int sx1[xd],sx2[xd],sy1,sy2;
1207         
1208         // pre calculating sx1/sx2 for faster resizing
1209         for (x=0; x<xd; x++) 
1210         {
1211                 // first x source pixel for calculating destination pixel
1212                 sx1[x]=(fx*x)>>16; //floor()
1213
1214                 // last x source pixel for calculating destination pixel
1215                 sx2[x]=sx1[x]+(fx>>16);
1216                 if (fx & 0x7FFF) //ceil()
1217                         sx2[x]++;               
1218         }
1219         
1220         // Scale
1221         for (y=0; y<yd; y++) 
1222         {
1223
1224                 // first y source pixel for calculating destination pixel
1225                 sy1=(fy*y)>>16; //floor()
1226
1227                 // last y source pixel for calculating destination pixel
1228                 sy2=sy1+(fy>>16);
1229                 if (fy & 0x7FFF) //ceil()
1230                         sy2++;
1231
1232                 for (x=0; x<xd; x++) 
1233                 {
1234                         // we do this for every color
1235                         for (c=0; c<colors; c++) 
1236                         {
1237                                 // calculationg destination pixel
1238                                 tmp_i=0;
1239                                 dpixel=0;
1240                 
1241                                 for (t1=sy1; t1<sy2; t1++) 
1242                                 {
1243                                         for (t=sx1[x]; t<=sx2[x]; t++) 
1244                                         {
1245                                                 tmp_i+=(int)source[(t*colors)+c+(t1*xs*colors)];
1246                                                 dpixel++;
1247                                         }
1248                                 }
1249                                 // writing calculated pixel into destination pixmap
1250                                 dest[(x*colors)+c+(y*xd*colors)]=tmp_i/dpixel;
1251                         }
1252                 }
1253         }
1254 }
1255
1256 // "nearest neighbor" pixmap resizing
1257
1258 static void fast_resize(const unsigned char *source, unsigned char *dest,
1259                         unsigned int xsource, unsigned int ysource,
1260                         unsigned int xdest, unsigned int ydest,
1261                         unsigned int colors)
1262 {
1263         unsigned int x_ratio = (xsource << 16) / xdest;
1264         unsigned int y_ratio = (ysource << 16) / ydest;
1265
1266         unsigned int x2, i ,j, y2_xsource, i_xdest, y2_x2_colors, i_x_colors;
1267         unsigned int c;
1268     for (i=0;i<ydest;i++) 
1269         {
1270                 y2_xsource = ((i*y_ratio)>>16)*xsource; // do some precalculations
1271                 i_xdest = i*xdest;
1272         for (j=0;j<xdest;j++) 
1273                 {
1274             x2 = ((j*x_ratio)>>16) ;
1275                         y2_x2_colors = (y2_xsource+x2)*colors;
1276                         i_x_colors = (i_xdest+j)*colors;
1277             for (c=0; c<colors; c++)
1278                                 dest[i_x_colors + c] = source[y2_x2_colors + c] ;
1279         }                
1280     }          
1281 }
1282
1283 // combining pixmaps by using an alphamap
1284
1285 static void combine(unsigned char *output,
1286                     const unsigned char *video, const unsigned char *osd,
1287                     unsigned int xres, unsigned int yres)
1288 {
1289         unsigned int a,apos,a2,pos1,vpos1;
1290         
1291         apos=pos1=vpos1=0;
1292         for (a=xres*yres; a != 0; a--)
1293         {       
1294                 apos=pos1+3;
1295                 a2=0xFF-osd[apos];
1296                 output[vpos1] =  ( ( video[vpos1] * a2 ) + ( osd[pos1++] * osd[apos] ) ) >>8;
1297                 vpos1++;
1298                 output[vpos1] =  ( ( video[vpos1] * a2 ) + ( osd[pos1++] * osd[apos] ) ) >>8;
1299                 vpos1++;
1300                 output[vpos1] =  ( ( video[vpos1] * a2 ) + ( osd[pos1++] * osd[apos] ) ) >>8;
1301                 vpos1++;
1302                 pos1++; // skip alpha byte
1303         }
1304 }
1305