source: tools/grab/main.c @ 4899

Last change on this file since 4899 was 4899, checked in by nit, 13 years ago

add grab source

File size: 17.7 KB
Line 
1/*
2AiO Screengrabber v0.81
3
4written 2006 - 2008 by Seddi
5Contact: seddi@ihad.tv / http://www.ihad.tv
6
7This standalone binary will grab the video-picture convert it from
8yuv to rgb and resize it, if neccesary, to the same size as the framebuffer or
9vice versa. For the DM7025 (Xilleon) and DM800/DM8000 (Broadcom) the video will be
10grabbed directly from the decoder memory.
11It also grabs the framebuffer picture in 32Bit, 16Bit or in 8Bit mode with the
12correct colortable in 8Bit mode from the main graphics memory, because the
13FBIOGETCMAP is buggy on Vulcan/Pallas boxes and didnt give you the correct color
14map.
15Finally it will combine the pixmaps to one final picture by using the framebuffer
16alphamap and save it as bmp, jpeg or png file. So you will get the same picture
17as you can see on your TV Screen.
18
19There are a few command line switches, use "grab -h" to get them listed.
20
21A special Thanx to tmbinc and ghost for the needed decoder memory information and
22the great support.
23
24Feel free to use the code for your own projects. See LICENSE file for details.
25*/
26
27#define GRAB_VERSION "v0.81"
28
29#include <unistd.h>
30#include <fcntl.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <ctype.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/ioctl.h>
38#include <sys/mman.h>
39#include <linux/types.h>
40#include <linux/videodev.h>
41#include <linux/fb.h>
42#include "png.h"
43#include "jpeglib.h"
44
45#define SWAP(x,y)       { x ^= y; y ^= x; x ^= y; }
46
47#define RED565(x)    ((((x) >> (11 )) & 0x1f) << 3)
48#define GREEN565(x)  ((((x) >> (5 )) & 0x3f) << 2)
49#define BLUE565(x)   ((((x) >> (0)) & 0x1f) << 3)
50
51void getvideo(unsigned char *video, int *xres, int *yres);
52void getosd(unsigned char *osd, unsigned char *osd_alpha, int *xres, int *yres);
53void smooth_resize(unsigned char *source, unsigned char *dest, int xsource, int ysource, int xdest, int ydest, int colors);
54void fast_resize(unsigned char *source, unsigned char *dest, int xsource, int ysource, int xdest, int ydest, int colors);
55void (*resize)(unsigned char *source, unsigned char *dest, int xsource, int ysource, int xdest, int ydest, int colors);
56void combine(unsigned char *output, unsigned char *video, unsigned char *osd, unsigned char *osd_alpha, int xres, int yres);
57char* upcase(char* mixedstr);
58
59char pngfile[256]="";
60unsigned char *image_data, bg_red=0, bg_green=0, bg_blue=0;
61static unsigned long image_width, image_height, image_rowbytes;
62static int image_channels;
63
64void convertpng(unsigned char *video)
65{
66        unsigned char *src, r, g, b;
67        unsigned long color, i, row;
68
69        for (row = 0; row < image_height; ++row) {
70                src = image_data + row*image_rowbytes;
71                for (i = 0; i<image_width; i++) {
72                        r = *src++;
73                        g = *src++;
74                        b = *src++;
75                        color = (r << 16) | (g << 8) | b;
76                        memcpy(video + (i*3)+(row*image_rowbytes), &color, 3);
77                }
78        }
79}
80
81int openpng(void)
82{
83        FILE *infile;
84        int rc;
85
86        if (!(infile = fopen(pngfile, "rb"))) {
87                printf("[grab] can't open PNG file [%s]\n", pngfile);
88                return(1);
89        }
90        if ((rc = readpng_init(infile, &image_width, &image_height)) != 0) {
91                switch (rc) {
92                        case 1:
93                                printf("[grab] %s is not a PNG file:\n", pngfile);
94                                fclose(infile);
95                                return(1);
96                        case 2:
97                                printf("[grab] %s has bad IHDR (libpng longjmp)\n", pngfile);
98                                fclose(infile);
99                                return(1);
100                        case 4:
101                                printf("[grab] insufficient memory\n");
102                                fclose(infile);
103                                return(1);
104                        default:
105                                printf("[grab] unknown readpng_init() error\n");
106                                fclose(infile);
107                                return(1);
108                        }
109                }
110                image_data = readpng_get_image(2.2 , &image_channels, &image_rowbytes);
111                readpng_cleanup(0);
112                fclose(infile);
113
114                if (!image_data) {
115                        printf("[grab] unable to decode PNG image\n");
116                        return(1);
117                }
118
119                printf("[grab] image hight = %ld\n", image_height);
120                printf("[grab] image width = %ld\n", image_width);
121                printf("[grab] image channels = %d\n", image_channels);
122                printf("[grab] image rowbytes = %ld\n", image_rowbytes);
123                return(0);
124}
125
126int main(int argc, char **argv) {
127        FILE *pipe;
128        char buf[256];
129
130        printf("[grab] AiO Screengrabber "GRAB_VERSION"\n\n");
131
132        int xres_v,yres_v,xres_o,yres_o,xres,yres,aspect;
133        int c,osd_only,video_only,use_osd_res,width,use_png,use_jpg,jpg_quality,no_aspect,use_letterbox;
134
135        // we use fast resize as standard now
136        resize = &fast_resize;
137       
138        osd_only=video_only=use_osd_res=width=use_png=use_jpg=no_aspect=use_letterbox=0;
139        jpg_quality=50;
140        aspect=1;
141       
142        unsigned char *video, *osd, *osd_alpha, *output;
143
144        char filename[256];
145        sprintf(filename,"/tmp/screenshot.bmp");
146       
147        // process command line
148        while ((c = getopt (argc, argv, "dhj:lbnopr:vf:")) != -1)
149        {
150                switch (c)
151                {
152                        case 'h':
153                        case '?':
154                                printf("Usage: grab [commands] [filename]\n\n");
155                                printf("command:\n");
156                                printf("-f (videofile) png video screenshot\n");
157                                printf("-o only grab osd (framebuffer)\n");
158                                printf("-v only grab video\n");
159                                printf("-d always use osd resolution (good for skinshots)\n");
160                                printf("-n dont correct 16:9 aspect ratio\n");
161                                printf("-r (size) resize to a fixed width, maximum: 1920\n");
162                                printf("-l always 4:3, create letterbox if 16:9\n");
163                                printf("-b use bicubic picture resize (slow but smooth)\n");
164                                printf("-j (quality) produce jpg files instead of bmp (quality 0-100)\n");     
165                                printf("-p produce png files instead of bmp\n");
166                                printf("-h this help screen\n\n");
167
168                                printf("If no command is given the complete picture will be grabbed.\n");
169                                printf("If no filename is given /tmp/screenshot.[bmp/jpg/png] will be used.\n");
170                                return 0;
171                                break;
172                        case 'o': // OSD only
173                                osd_only=1;
174                                video_only=0;   
175                                break;
176                        case 'v': // Video only
177                                video_only=1;
178                                osd_only=0;
179                                break;
180                        case 'd': // always use OSD resolution
181                                use_osd_res=1;
182                                no_aspect=1;
183                                break;
184                        case 'r': // use given resolution
185                                width=atoi(optarg);
186                                if (width > 1920)
187                                {
188                                        printf("[grab] Error: -r (size) ist limited to 1920 pixel !\n");
189                                        return 1;
190                                }
191                                break;
192                        case 'l': // create letterbox
193                                use_letterbox=1;
194                                break;
195                        case 'b': // use bicubic resizing
196                                resize = &smooth_resize;
197                                break;                 
198                        case 'p': // use png file format
199                                use_png=1;
200                                use_jpg=0;     
201                                sprintf(filename,"/tmp/screenshot.png");
202                                break;
203                        case 'f':
204                                sprintf(pngfile, "%s", optarg);
205                                break;
206                        case 'j': // use jpg file format
207                                use_jpg=1;
208                                use_png=0;
209                                jpg_quality=atoi(optarg);
210                                sprintf(filename,"/tmp/screenshot.jpg");
211                                break;
212                        case 'n':
213                                no_aspect=1;
214                                break;
215                }
216        }
217        if (optind < argc) // filename
218                sprintf(filename,"%s",argv[optind]);
219
220        int mallocsize=1920*1080;
221       
222        video = (unsigned char *)malloc(mallocsize*3);
223        osd = (unsigned char *)malloc(mallocsize*3);   
224        osd_alpha = (unsigned char *)malloc(mallocsize);       
225
226        output = (unsigned char *)malloc(mallocsize*3);
227
228        // get osd
229        if (!video_only)
230                getosd(osd,osd_alpha,&xres_o,&yres_o);
231       
232        // get video
233        if (!osd_only)
234                getvideo(video,&xres_v,&yres_v);
235       
236        pipe=popen("cat /proc/stb/vmpeg/0/aspect","r");
237        while (fgets(buf,sizeof(buf),pipe))
238                sscanf(buf,"%x",&aspect);
239        pclose(pipe);
240       
241        // resizing
242        if (video_only)
243        {
244                xres=xres_v;
245                yres=yres_v;
246        } else if (osd_only)
247        {
248                xres=xres_o;
249                yres=yres_o;
250        } else if (xres_o == xres_v && yres_o == yres_v)
251        {
252                xres=xres_v;
253                yres=yres_v;
254        } else
255        {
256                if (xres_v > xres_o && !use_osd_res && (width == 0 || width > xres_o))
257                {
258                        // resize osd to video size
259                        printf("[grab] Resizing OSD to %d x %d ...\n",xres_v,yres_v);   
260                        resize(osd,output,xres_o,yres_o,xres_v,yres_v,3);
261                        memcpy(osd,output,xres_v*yres_v*3);
262                        resize(osd_alpha,output,xres_o,yres_o,xres_v,yres_v,1);
263                        memcpy(osd_alpha,output,xres_v*yres_v);
264                        xres=xres_v;
265                        yres=yres_v;
266                } else
267                {
268                        // resize video to osd size
269                        printf("[grab] Resizing Video to %d x %d ...\n",xres_o,yres_o);
270                        resize(video,output,xres_v,yres_v,xres_o,yres_o,3);
271                        memcpy(video,output,xres_o*yres_o*3);
272                        xres=xres_o;
273                        yres=yres_o;
274                }       
275        }
276       
277
278        // merge video and osd if neccessary
279        if (osd_only)
280                memcpy(output,osd,xres*yres*3);
281        else if (video_only)
282                memcpy(output,video,xres*yres*3);
283        else
284        {
285                printf("[grab] Merge Video with Framebuffer ...\n");
286                combine(output,video,osd,osd_alpha,xres,yres);
287        }
288
289       
290        // resize to specific width ?
291        if (width)
292        {
293                printf("[grab] Resizing Screenshot to %d x %d ...\n",width,yres*width/xres);
294                resize(output,video,xres,yres,width,(yres*width/xres),3);
295                yres=yres*width/xres;
296                xres=width;
297                memcpy(output,video,xres*yres*3);
298        }
299       
300
301        // correct aspect ratio
302        if (!no_aspect && aspect == 3 && ((float)xres/(float)yres)<1.5)
303        {
304                printf("[grab] Correct aspect ratio to 16:9 ...\n");
305                resize(output,video,xres,yres,xres,yres/1.42,3);
306                yres/=1.42;
307                memcpy(output,video,xres*yres*3);
308        }
309       
310       
311        // use letterbox ?
312        if (use_letterbox && xres*0.8 != yres && xres*0.8 <= 1080)
313        {
314                int yres_neu;
315                yres_neu=xres*0.8;
316                printf("[grab] Create letterbox %d x %d ...\n",xres,yres_neu);         
317                if (yres_neu > yres)
318                {
319                        int ofs;
320                        ofs=(yres_neu-yres)>>1;
321                        memmove(output+ofs*xres*3,output,xres*yres*3);
322                        memset(output,0,ofs*xres*3);
323                        memset(output+ofs*xres*3+xres*yres*3,0,ofs*xres*3);
324                }
325                yres=yres_neu;
326        }
327       
328       
329        // saving picture
330        printf("[grab] Saving %s ...\n",filename);
331        FILE *fd2 = fopen(filename, "wr");
332       
333       
334        if (!use_png && !use_jpg)
335        {
336                // write bmp
337                unsigned char hdr[14 + 40];
338                int i = 0;
339#define PUT32(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF); hdr[i++] = (((x)>>16)&0xFF); hdr[i++] = (((x)>>24)&0xFF);
340#define PUT16(x) hdr[i++] = ((x)&0xFF); hdr[i++] = (((x)>>8)&0xFF);
341#define PUT8(x) hdr[i++] = ((x)&0xFF);
342                PUT8('B'); PUT8('M');
343                PUT32((((xres * yres) * 3 + 3) &~ 3) + 14 + 40);
344                PUT16(0); PUT16(0); PUT32(14 + 40);
345                PUT32(40); PUT32(xres); PUT32(yres);
346                PUT16(1);
347                PUT16(24);
348                PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0); PUT32(0);
349#undef PUT32
350#undef PUT16
351#undef PUT8
352                fwrite(hdr, 1, i, fd2);
353               
354                int y;
355                for (y=yres-1; y>=0 ; y-=1) {
356                        fwrite(output+(y*xres*3),xres*3,1,fd2);
357                }
358        } else if (use_png)
359        {       
360                // write png
361                png_bytep *row_pointers;
362                png_structp png_ptr;
363                png_infop info_ptr;
364         
365                png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL);
366                info_ptr = png_create_info_struct(png_ptr);
367                png_init_io(png_ptr, fd2);
368
369                row_pointers=(png_bytep*)malloc(sizeof(png_bytep)*yres);
370
371                int y;
372                for (y=0; y<yres; y++)
373                        row_pointers[y]=output+(y*xres*3);
374               
375                png_set_bgr(png_ptr);
376                png_set_IHDR(png_ptr, info_ptr, xres, yres, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
377                png_write_info(png_ptr, info_ptr);
378                png_write_image(png_ptr, row_pointers);
379                png_write_end(png_ptr, info_ptr);
380                png_destroy_write_struct(&png_ptr, &info_ptr);
381               
382                free(row_pointers);
383        } else
384        {
385                // write jpg
386                int x,y;
387                for (y=0; y<yres; y++)
388                        for (x=0; x<xres; x++)
389                                SWAP(output[x*3+y*xres*3],output[x*3+y*xres*3+2]);
390
391                struct jpeg_compress_struct cinfo;
392                struct jpeg_error_mgr jerr;
393                JSAMPROW row_pointer[1];       
394                int row_stride;         
395                cinfo.err = jpeg_std_error(&jerr);
396
397                jpeg_create_compress(&cinfo);
398                jpeg_stdio_dest(&cinfo, fd2);
399                cinfo.image_width = xres;       
400                cinfo.image_height = yres;
401                cinfo.input_components = 3;     
402                cinfo.in_color_space = JCS_RGB;
403                jpeg_set_defaults(&cinfo);
404                jpeg_set_quality(&cinfo,jpg_quality, TRUE);
405                jpeg_start_compress(&cinfo, TRUE);
406                row_stride = xres * 3;
407                while (cinfo.next_scanline < cinfo.image_height)
408                {
409                        row_pointer[0] = & output[cinfo.next_scanline * row_stride];
410                        (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
411                }
412                jpeg_finish_compress(&cinfo);
413                jpeg_destroy_compress(&cinfo);
414        }
415       
416        fclose(fd2);   
417       
418        // Thats all folks
419        printf("[grab] ... Done !\n");
420       
421        // clean up
422        free(video);
423        free(osd);
424        free(osd_alpha);
425        free(output);
426
427        return 0;
428}
429
430// grabing the video picture
431
432void getvideo(unsigned char *video, int *xres, int *yres)
433{
434        printf("[grab] Grabbing Video ...\n");
435
436        if(openpng() != 0)
437                exit(1);       
438        convertpng(video);
439        *yres=image_height;
440        *xres=image_width;
441}
442
443// grabing the osd picture
444
445void getosd(unsigned char *osd, unsigned char *osd_alpha, int *xres, int *yres)
446{
447        int fb,x,y,pos,pos1,pos2,ofs;
448        unsigned char *lfb;
449        struct fb_fix_screeninfo fix_screeninfo;
450        struct fb_var_screeninfo var_screeninfo;
451       
452        fb=open("/dev/fb/0", O_RDWR);
453        if (fb == -1)
454        {
455                fb=open("/dev/fb0", O_RDWR);
456                if (fb == -1)
457                {
458                        printf("[grab] Framebuffer failed\n");
459                        return;
460                }
461        }
462       
463        if(ioctl(fb, FBIOGET_FSCREENINFO, &fix_screeninfo) == -1)
464        {
465                printf("[grab] Framebuffer: <FBIOGET_FSCREENINFO failed>\n");
466                return;
467        }
468
469        if(ioctl(fb, FBIOGET_VSCREENINFO, &var_screeninfo) == -1)
470        {
471                printf("[grab] Framebuffer: <FBIOGET_VSCREENINFO failed>\n");
472                return;
473        }
474       
475        if(!(lfb = (unsigned char*)mmap(0, fix_screeninfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0)))
476        {
477                printf("[grab] Framebuffer: <Memmapping failed>\n");
478                return;
479        }
480       
481        if ( var_screeninfo.bits_per_pixel == 32 )
482        {
483                printf("[grab] Grabbing 32bit Framebuffer ...\n");
484       
485                // get 32bit framebuffer
486                pos=pos1=pos2=0;
487                ofs=fix_screeninfo.line_length-(var_screeninfo.xres*4);
488               
489                unsigned char *memory; // use additional buffer to speed up especially when using hd skins
490                memory = (unsigned char *)malloc(fix_screeninfo.line_length*var_screeninfo.yres);
491                memcpy(memory,lfb,fix_screeninfo.line_length*var_screeninfo.yres);
492               
493                for (y=0; y < var_screeninfo.yres; y+=1)
494                {
495                        for (x=0; x < var_screeninfo.xres; x+=1)
496                        {
497                                memcpy(osd+pos1,memory+pos2,3);// bgr
498                                pos1+=3;
499                                pos2+=3;
500                                osd_alpha[pos++]=memory[pos2++];// tr
501                        }
502                        pos2+=ofs;
503                }
504               
505                free(memory);
506        } else if ( var_screeninfo.bits_per_pixel == 16 )
507        {
508                printf("[grab] Grabbing 16bit Framebuffer ...\n");
509                unsigned short color;
510               
511                // get 16bit framebuffer
512                pos=pos1=pos2=0;
513                ofs=fix_screeninfo.line_length-(var_screeninfo.xres*2);         
514                for (y=0; y < var_screeninfo.yres; y+=1)
515                {
516                        for (x=0; x < var_screeninfo.xres; x+=1)
517                        {
518                                color = lfb[pos2] << 8 | lfb[pos2+1];
519                                pos2+=2;
520                               
521                                osd[pos1++] = BLUE565(color); // b
522                                osd[pos1++] = GREEN565(color); // g
523                                osd[pos1++] = RED565(color); // r
524                                osd_alpha[pos++]=0x00; // tr - there is no transparency in 16bit mode
525                        }
526                        pos2+=ofs;
527                }
528        }
529        close(fb);
530
531        *xres=var_screeninfo.xres;
532        *yres=var_screeninfo.yres;
533        printf("[grab] ... Framebuffer-Size: %d x %d\n",*xres,*yres);
534}
535
536// bicubic pixmap resizing
537
538void smooth_resize(unsigned char *source, unsigned char *dest, int xsource, int ysource, int xdest, int ydest, int colors)
539{
540        unsigned int xs,ys,xd,yd,dpixel,fx,fy;
541        unsigned int c,tmp_i;
542        int x,y,t,t1;
543        xs=xsource; // x-resolution source
544        ys=ysource; // y-resolution source
545        xd=xdest; // x-resolution destination
546        yd=ydest; // y-resolution destination
547       
548        // get x scale factor, use bitshifting to get rid of floats
549        fx=((xs-1)<<16)/xd;
550
551        // get y scale factor, use bitshifting to get rid of floats
552        fy=((ys-1)<<16)/yd;
553
554        unsigned int sx1[xd],sx2[xd],sy1,sy2;
555       
556        // pre calculating sx1/sx2 for faster resizing
557        for (x=0; x<xd; x++)
558        {
559                // first x source pixel for calculating destination pixel
560                sx1[x]=(fx*x)>>16; //floor()
561
562                // last x source pixel for calculating destination pixel
563                sx2[x]=sx1[x]+(fx>>16);
564                if (fx & 0x7FFF) //ceil()
565                        sx2[x]++;               
566        }
567       
568        // Scale
569        for (y=0; y<yd; y++)
570        {
571
572                // first y source pixel for calculating destination pixel
573                sy1=(fy*y)>>16; //floor()
574
575                // last y source pixel for calculating destination pixel
576                sy2=sy1+(fy>>16);
577                if (fy & 0x7FFF) //ceil()
578                        sy2++;
579
580                for (x=0; x<xd; x++)
581                {
582                        // we do this for every color
583                        for (c=0; c<colors; c++)
584                        {
585                                // calculationg destination pixel
586                                tmp_i=0;
587                                dpixel=0;
588               
589                                for (t1=sy1; t1<sy2; t1++)
590                                {
591                                        for (t=sx1[x]; t<=sx2[x]; t++)
592                                        {
593                                                tmp_i+=(int)source[(t*colors)+c+(t1*xs*colors)];
594                                                dpixel++;
595                                        }
596                                }
597                                // writing calculated pixel into destination pixmap
598                                dest[(x*colors)+c+(y*xd*colors)]=tmp_i/dpixel;
599                        }
600                }
601        }
602}
603
604// "nearest neighbor" pixmap resizing
605
606void fast_resize(unsigned char *source, unsigned char *dest, int xsource, int ysource, int xdest, int ydest, int colors)
607{
608    int x_ratio = (int)((xsource<<16)/xdest) ;
609    int y_ratio = (int)((ysource<<16)/ydest) ;
610
611    int x2, y2, c, i ,j;
612    for (i=0;i<ydest;i++) {
613        for (j=0;j<xdest;j++) {
614            x2 = ((j*x_ratio)>>16) ;
615            y2 = ((i*y_ratio)>>16) ;
616            for (c=0; c<colors; c++)
617                                dest[((i*xdest)+j)*colors + c] = source[((y2*xsource)+x2)*colors + c] ;
618        }               
619    }         
620}
621
622// combining pixmaps by using an alphamap
623
624void combine(unsigned char *output, unsigned char *video, unsigned char *osd, unsigned char *osd_alpha, int xres, int yres)
625{
626        int x,y,pos,pos1;
627       
628        pos=pos1=0;
629        for (y=0; y < yres; y+=1)
630        {
631                for (x=0; x < xres; x+=1)
632                {
633                        output[pos1] =  ( ( video[pos1] * ( 0xFF-osd_alpha[pos] ) ) + ( osd[pos1] * osd_alpha[pos] ) ) >>8;
634                        pos1++;
635                        output[pos1] =  ( ( video[pos1] * ( 0xFF-osd_alpha[pos] ) ) + ( osd[pos1] * osd_alpha[pos] ) ) >>8;
636                        pos1++;
637                        output[pos1] =  ( ( video[pos1] * ( 0xFF-osd_alpha[pos] ) ) + ( osd[pos1] * osd_alpha[pos] ) ) >>8;
638                        pos1++;
639                        pos++;
640                }
641        }
642}
643
644// helpers
645
646char* upcase(char* mixedstr)
647{
648        int j;
649        for (j=0; j< strlen(mixedstr); ++j)
650        {
651                mixedstr[j]=toupper(mixedstr[j]);
652        }
653        return mixedstr;
654}
Note: See TracBrowser for help on using the repository browser.