]> git.sesse.net Git - x264/blob - tools/xyuv.c
* all: re-import of the CVS.
[x264] / tools / xyuv.c
1 /*****************************************************************************
2  * xyuv.c: a SDL yuv 420 planer viewer.
3  *****************************************************************************
4  * Copyright (C) 2004 Laurent Aimar
5  * $Id: xyuv.c,v 1.1 2004/06/03 19:27:08 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdint.h>
28
29 #include <SDL/SDL.h>
30
31 #define YUV_MAX 20
32 #define SDL_TITLE "xyuv: %s - %d/%d - %.2ffps"
33 typedef struct
34 {
35     /* globals */
36     int     i_width;
37     int     i_height;
38     int     i_frame_size;
39     int     i_frame;
40     int     i_frames;
41     float   f_fps;
42
43     float   f_y;
44
45     int     b_pause;
46     int     b_grid;
47     int     b_split;
48     int     b_diff;
49     int     i_join;
50
51     /* Constructed picture */
52     int     i_wall_width;   /* in picture count */
53
54     /* YUV files */
55     int     i_yuv;
56     struct
57     {
58         char    *name;
59         FILE    *f;         /* handles */
60         int     i_frames;   /* frames count */
61
62         /* Position in the whole picture */
63         int     x, y;
64     } yuv[YUV_MAX];
65
66     /* SDL */
67     int i_sdl_width;
68     int i_sdl_height;
69
70     int i_display_width;
71     int i_display_height;
72     char *title;
73
74     SDL_Surface *screen;
75     SDL_Overlay *overlay;
76
77     /* */
78     uint8_t *pic;
79
80 } xyuv_t;
81
82 xyuv_t xyuv = {
83     .i_width = 0,
84     .i_height = 0,
85     .i_frame  = 1,
86     .i_frames = 0,
87     .f_fps = 25.0,
88     .f_y = 0.0,
89     .i_wall_width = 0,
90
91     .i_yuv = 0,
92
93     .b_pause = 0,
94     .b_split = 0,
95     .b_diff = 0,
96     .i_join = -1,
97
98     .title = NULL,
99     .pic = NULL,
100 };
101
102 static void help( void )
103 {
104     fprintf( stderr,
105              "Syntax: xyuv [options] file [file2 ...]\n"
106              "\n"
107              "      --help                  Print this help\n"
108              "\n"
109              "  -s, --size <WIDTHxHEIGHT>   Set input size\n"
110              "  -w, --width <integer>       Set width\n"
111              "  -h, --height <integer>      Set height\n"
112              "\n"
113              "  -S, --split                 Show splited Y/U/V planes\n"
114              "  -d, --diff                  Show difference (only 2 files) in split mode\n"
115              "  -j, --joint <integer>\n"
116              "\n"
117              "  -y <float>                  Set Y factor\n"
118              "\n"
119              "  -g, --grid                  Show a grid (macroblock 16x16)\n"
120              "  -W <integer>                Set wall width (in picture count)\n"
121              "  -f, --fps <float>           Set fps\n"
122              "\n" );
123 }
124
125
126 static void xyuv_display( xyuv_t *xyuv, int i_frame );
127
128 int main( int argc, char **argv )
129 {
130     int i;
131
132     /* Parse commande line */
133     for( i = 1; i < argc; i++ ) {
134         if( !strcasecmp( argv[i], "--help" ) ) {
135             help();
136             return 0;
137         }
138         if( !strcmp( argv[i], "-d" ) || !strcasecmp( argv[i], "--diff" ) ) {
139             xyuv.b_diff = 1;
140         } else if( !strcmp( argv[i], "-S" ) || !strcasecmp( argv[i], "--split" ) ) {
141             xyuv.b_split = 1;
142         } else if( !strcmp( argv[i], "-f" ) || !strcasecmp( argv[i], "--fps" ) ) {
143             if( i >= argc -1 ) goto err_missing_arg;
144             xyuv.f_fps = atof( argv[++i] );
145         } else if( !strcmp( argv[i], "-h" ) || !strcasecmp( argv[i], "--height" ) ) {
146             if( i >= argc -1 ) goto err_missing_arg;
147             xyuv.i_height = atoi( argv[++i] );
148         } else if( !strcmp( argv[i], "-w" ) || !strcasecmp( argv[i], "--width" ) ) {
149             if( i >= argc -1 ) goto err_missing_arg;
150             xyuv.i_width = atoi( argv[++i] );
151         } else if( !strcmp( argv[i], "-s" ) || !strcasecmp( argv[i], "--size" ) ) {
152             char *p;
153
154             if( i >= argc -1 ) goto err_missing_arg;
155
156             xyuv.i_width = strtol( argv[++i], &p, 0 );
157             p++;
158             xyuv.i_height = atoi( p );
159         } else if( !strcmp( argv[i], "-W" ) ) {
160             if( i >= argc -1 ) goto err_missing_arg;
161             xyuv.i_wall_width = atoi( argv[++i] );
162         } else if( !strcmp( argv[i], "-y" ) ) {
163             if( i >= argc -1 ) goto err_missing_arg;
164             xyuv.f_y = atof( argv[++i] );
165         } else if( !strcmp( argv[i], "-j" ) || !strcasecmp( argv[i], "--join" ) ) {
166             if( i >= argc -1 ) goto err_missing_arg;
167             xyuv.i_join = atoi( argv[++i] );
168         } else if( !strcmp( argv[i], "-g" ) || !strcasecmp( argv[i], "--grid" ) ) {
169             xyuv.b_grid = 1;
170         } else {
171             FILE *f = fopen( argv[i], "rb" );
172             if( !f ) {
173                 fprintf( stderr, "cannot open YUV %s\n", argv[i] );
174             } else {
175                 xyuv.yuv[xyuv.i_yuv].name = strdup( argv[i] );
176                 xyuv.yuv[xyuv.i_yuv].f = f;
177                 xyuv.yuv[xyuv.i_yuv].i_frames = 0;
178
179                 xyuv.i_yuv++;
180             }
181         }
182     }
183
184     if( xyuv.i_yuv == 0 ) {
185         fprintf( stderr, "no file to display\n" );
186         return -1;
187     }
188     if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
189         char *psz = xyuv.yuv[0].name;
190         char *num;
191         char *x;
192         /* See if we find widthxheight in the file name */
193         for( ;; )
194         {
195             if( !( x = strchr( psz+1, 'x' ) ) )
196             {
197                 break;
198             }
199             num = x;
200             while( num > psz && num[-1] >= '0' && num[-1] <= '9' )
201                 num--;
202
203             if( num != x && x[1] >= '0' && x[1] <= '9' )
204             {
205                 xyuv.i_width = atoi( num );
206                 xyuv.i_height = atoi( x+1 );
207                 break;
208             }
209             psz = x;
210         }
211         fprintf( stderr, "file name gives %dx%d\n", xyuv.i_width, xyuv.i_height );
212     }
213     if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
214         fprintf( stderr, "invalid or missing frames size\n" );
215         return -1;
216     }
217     if( xyuv.b_diff && xyuv.i_yuv != 2 ) {
218         fprintf( stderr, "--diff works only with 2 files\n" );
219         return -1;
220     }
221     if( (xyuv.i_join == 0 || xyuv.i_join >= xyuv.i_width) && xyuv.i_yuv != 2 ) {
222         fprintf( stderr, "--join woeks only with two files and range is [1, width-1]\n" );
223         return -1;
224     }
225     if( xyuv.i_join % 2 != 0 ) {
226         if( xyuv.i_join + 1 < xyuv.i_width )
227             xyuv.i_join++;
228         else
229             xyuv.i_join--;
230     }
231
232     /* Now check frames */
233     fprintf( stderr, "displaying :\n" );
234     xyuv.i_frames = 0;
235     xyuv.i_frame_size = 3 * xyuv.i_width * xyuv.i_height / 2;
236     for( i = 0; i < xyuv.i_yuv; i++ ) {
237         /* Beurk but avoid using fstat */
238         fseek( xyuv.yuv[i].f, 0, SEEK_END );
239
240         xyuv.yuv[i].i_frames = ftell( xyuv.yuv[i].f ) / xyuv.i_frame_size;
241
242         fseek( xyuv.yuv[i].f, 0, SEEK_SET );
243
244         fprintf( stderr, " - '%s' : %d frames\n", xyuv.yuv[i].name, xyuv.yuv[i].i_frames );
245
246         if( xyuv.i_frames < xyuv.yuv[i].i_frames )
247             xyuv.i_frames = xyuv.yuv[i].i_frames;
248     }
249
250     if( xyuv.i_frames == 0 ) {
251         fprintf( stderr, "no frames to display\n" );
252     }
253
254     xyuv.pic = malloc( xyuv.i_frame_size );
255
256     /* calculate SDL view */
257     if( xyuv.i_wall_width > xyuv.i_yuv ) {
258         xyuv.i_wall_width = xyuv.i_yuv;
259     }
260     if( xyuv.i_wall_width == 0 ) {
261         while( xyuv.i_wall_width < xyuv.i_yuv && xyuv.i_wall_width * xyuv.i_wall_width < xyuv.i_yuv ) {
262             xyuv.i_wall_width++;
263         }
264     }
265
266     for( i = 0; i < xyuv.i_yuv; i++ ) {
267         if( xyuv.b_diff || xyuv.i_join > 0 ) {
268             xyuv.yuv[i].x = 0;
269             xyuv.yuv[i].y = 0;
270         } else if( xyuv.b_split ) {
271             xyuv.yuv[i].x = (i%xyuv.i_wall_width) * 3 * xyuv.i_width / 2;
272             xyuv.yuv[i].y = (i/xyuv.i_wall_width) * xyuv.i_height;
273         } else {
274             xyuv.yuv[i].x = (i%xyuv.i_wall_width) * xyuv.i_width;
275             xyuv.yuv[i].y = (i/xyuv.i_wall_width) * xyuv.i_height;
276         }
277     }
278     if( xyuv.b_diff ) {
279         xyuv.i_sdl_width = 3 * xyuv.i_width / 2;
280         xyuv.i_sdl_height= xyuv.i_height;
281     } else if( xyuv.i_join > 0 ) {
282         xyuv.i_sdl_width = xyuv.i_width;
283         xyuv.i_sdl_height= xyuv.i_height;
284     } else if( xyuv.b_split ) {
285         xyuv.i_sdl_width = xyuv.i_wall_width * 3 * xyuv.i_width / 2;
286         xyuv.i_sdl_height= xyuv.i_height * ( ( xyuv.i_yuv  + xyuv.i_wall_width - 1 ) / xyuv.i_wall_width );
287     } else {
288         xyuv.i_sdl_width = xyuv.i_wall_width * xyuv.i_width;
289         xyuv.i_sdl_height= xyuv.i_height * ( ( xyuv.i_yuv  + xyuv.i_wall_width - 1 ) / xyuv.i_wall_width );
290     }
291     xyuv.i_display_width = xyuv.i_sdl_width;
292     xyuv.i_display_height = xyuv.i_sdl_height;
293
294     /* Open SDL */
295     if( SDL_Init( SDL_INIT_EVENTTHREAD|SDL_INIT_NOPARACHUTE|SDL_INIT_VIDEO) ) {
296         fprintf( stderr, "cannot init SDL\n" );
297         return -1;
298     }
299
300     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 100 );
301     SDL_EventState( SDL_KEYUP, SDL_IGNORE );
302
303     xyuv.screen = SDL_SetVideoMode( xyuv.i_sdl_width, xyuv.i_sdl_height, 0,
304                                     SDL_HWSURFACE|SDL_RESIZABLE|
305                                     SDL_ASYNCBLIT|SDL_HWACCEL );
306     if( xyuv.screen == NULL ) {
307         fprintf( stderr, "SDL_SetVideoMode failed\n" );
308         return -1;
309     }
310
311     SDL_LockSurface( xyuv.screen );
312     xyuv.overlay = SDL_CreateYUVOverlay( xyuv.i_sdl_width, xyuv.i_sdl_height,
313                                          SDL_YV12_OVERLAY,
314                                          xyuv.screen );
315     /* reset with black */
316     memset( xyuv.overlay->pixels[0],   0, xyuv.overlay->pitches[0] * xyuv.i_sdl_height );
317     memset( xyuv.overlay->pixels[1], 128, xyuv.overlay->pitches[1] * xyuv.i_sdl_height / 2);
318     memset( xyuv.overlay->pixels[2], 128, xyuv.overlay->pitches[2] * xyuv.i_sdl_height / 2);
319     SDL_UnlockSurface( xyuv.screen );
320
321     if( xyuv.overlay == NULL ) {
322         fprintf( stderr, "recon: SDL_CreateYUVOverlay failed\n" );
323         return -1;
324     }
325
326     for( ;; ) {
327         SDL_Event event;
328         int64_t i_start = SDL_GetTicks();
329         int i_wait;
330
331         if( !xyuv.b_pause ) {
332             xyuv_display( &xyuv, xyuv.i_frame );
333         }
334
335         for( ;; ) {
336             int b_refresh = 0;
337             while( SDL_PollEvent( &event ) )  {
338                 switch( event.type )
339                 {
340                     case SDL_QUIT:
341                         exit( 1 );
342
343                     case SDL_KEYDOWN:
344                         switch( event.key.keysym.sym )
345                         {
346                             case SDLK_q:
347                             case SDLK_ESCAPE:
348                                 exit(1);
349
350                             case SDLK_f:
351                                 SDL_WM_ToggleFullScreen( xyuv.screen );
352                                 break;
353
354                             case SDLK_g:
355                                 if( xyuv.b_grid )
356                                     xyuv.b_grid = 0;
357                                 else
358                                     xyuv.b_grid = 1;
359                                 if( xyuv.b_pause )
360                                     b_refresh = 1;
361                                 break;
362
363                             case SDLK_SPACE:
364                                 if( xyuv.b_pause )
365                                     xyuv.b_pause = 0;
366                                 else
367                                     xyuv.b_pause = 1;
368                                 break;
369                             case SDLK_LEFT:
370                                 if( xyuv.i_frame > 1 ) xyuv.i_frame--;
371                                 b_refresh = 1;
372                                 break;
373
374                             case SDLK_RIGHT:
375                                 if( xyuv.i_frame < xyuv.i_frames ) xyuv.i_frame++;
376                                 b_refresh = 1;
377                                 break;
378
379                             case SDLK_HOME:
380                                 xyuv.i_frame = 1;
381                                 if( xyuv.b_pause )
382                                     b_refresh = 1;
383                                 break;
384
385                             case SDLK_END:
386                                 xyuv.i_frame = xyuv.i_frames;
387                                 b_refresh = 1;
388                                 break;
389
390                             case SDLK_UP:
391                                 xyuv.i_frame += xyuv.i_frames / 20;
392                                 if( xyuv.i_frame > xyuv.i_frames )
393                                     xyuv.i_frame = xyuv.i_frames;
394                                 b_refresh = 1;
395                                 break;
396
397                             case SDLK_DOWN:
398                                 xyuv.i_frame -= xyuv.i_frames / 20;
399                                 if( xyuv.i_frame < 1 )
400                                     xyuv.i_frame = 1;
401                                 b_refresh = 1;
402                                 break;
403
404                             case SDLK_PAGEUP:
405                                 xyuv.i_frame += xyuv.i_frames / 10;
406                                 if( xyuv.i_frame > xyuv.i_frames )
407                                     xyuv.i_frame = xyuv.i_frames;
408                                 b_refresh = 1;
409                                 break;
410
411                             case SDLK_PAGEDOWN:
412                                 xyuv.i_frame -= xyuv.i_frames / 10;
413                                 if( xyuv.i_frame < 1 )
414                                     xyuv.i_frame = 1;
415                                 b_refresh = 1;
416                                 break;
417
418                             default:
419                                 break;
420                         }
421                         break;
422                     case SDL_VIDEORESIZE:
423                         xyuv.i_display_width = event.resize.w;
424                         xyuv.i_display_height = event.resize.h;
425                         xyuv.screen = SDL_SetVideoMode( xyuv.i_display_width, xyuv.i_display_height, 0,
426                                                         SDL_HWSURFACE|SDL_RESIZABLE|
427                                                         SDL_ASYNCBLIT|SDL_HWACCEL );
428                         xyuv_display( &xyuv, xyuv.i_frame );
429                         break;
430
431                     default:
432                         break;
433                 }
434             }
435             if( b_refresh ) {
436                 xyuv.b_pause = 1;
437                 xyuv_display( &xyuv, xyuv.i_frame );
438             }
439             /* wait */
440             i_wait = 1000 / xyuv.f_fps - ( SDL_GetTicks() - i_start);
441             if( i_wait < 0 )
442                 break;
443             else if( i_wait > 200 )
444                 SDL_Delay( 200 );
445             else {
446                 SDL_Delay( i_wait );
447                 break;
448             }
449         }
450         if( !xyuv.b_pause ) {
451             /* next frame */
452             if( xyuv.i_frame == xyuv.i_frames )
453                 xyuv.b_pause = 1;
454             else if( xyuv.i_frame < xyuv.i_frames )
455                 xyuv.i_frame++;
456         }
457     }
458
459
460     return 0;
461
462 err_missing_arg:
463     fprintf( stderr, "missing arg for option=%s\n", argv[i] );
464     return -1;
465 }
466
467
468 static void xyuv_display( xyuv_t *xyuv, int i_frame )
469 {
470     SDL_Rect rect;
471     int i_picture = 0;
472     int i;
473
474     if( i_frame > xyuv->i_frames )
475         return;
476
477     xyuv->i_frame = i_frame;
478
479     /* Load and copy pictue data */
480     for( i = 0; i < xyuv->i_yuv; i++ ) {
481         int i_plane;
482
483         if( i_frame - 1 >= xyuv->yuv[i].i_frames )
484             continue;
485         i_picture++;
486
487         fseek( xyuv->yuv[i].f, (xyuv->i_frame-1) * xyuv->i_frame_size, SEEK_SET );
488         fread( xyuv->pic, xyuv->i_frame_size, 1, xyuv->yuv[i].f );
489
490         SDL_LockYUVOverlay( xyuv->overlay );
491
492         if( xyuv->b_diff || xyuv->b_split ) {
493             /* Reset UV */
494             for( i_plane = 1; i_plane < 3; i_plane++ ) {
495                 memset( xyuv->overlay->pixels[i_plane], 128, xyuv->overlay->pitches[i_plane] * xyuv->overlay->h / 2 );
496             }
497             /* Show diff in Y plane of overlay */
498
499             for( i_plane = 0; i_plane < 3; i_plane++ ) {
500                 int div = i_plane == 0 ? 1 : 2;
501                 uint8_t *src = xyuv->pic;
502                 uint8_t *dst = xyuv->overlay->pixels[0] +
503                                 (xyuv->yuv[i].x + xyuv->yuv[i].y * xyuv->overlay->pitches[0] );
504                 int j;
505                 if( i_plane == 1 ) {
506                     src +=  5*xyuv->i_width * xyuv->i_height/4;
507                     dst += xyuv->i_width;
508                 } else if( i_plane == 2 ) {
509                     src += xyuv->i_width * xyuv->i_height;
510                     dst += xyuv->i_width + xyuv->i_height / 2 * xyuv->overlay->pitches[0];
511                 }
512
513                 for( j = 0; j < xyuv->i_height / div; j++ ) {
514                     if( i_picture == 1 || xyuv->b_split ) {
515                         memcpy( dst, src, xyuv->i_width / div );
516                     } else {
517                         int k;
518                         for( k = 0; k < xyuv->i_width / div; k++ ) {
519                             dst[k] = abs( dst[k] - src[k]);
520                         }
521                     }
522                     src += xyuv->i_width / div;
523                     dst += xyuv->overlay->pitches[0];
524                 }
525             }
526         } else {
527             for( i_plane = 0; i_plane < 3; i_plane++ ) {
528                 int div = i_plane == 0 ? 1 : 2;
529                 uint8_t *src = xyuv->pic;
530                 uint8_t *dst = xyuv->overlay->pixels[i_plane] +
531                                 ((xyuv->yuv[i].x + xyuv->yuv[i].y * xyuv->overlay->pitches[i_plane] ) / div );
532                 int w = xyuv->i_width / div;
533                 int j;
534
535                 if( i_plane == 1 ) {
536                     src +=  5*xyuv->i_width * xyuv->i_height/4;
537                 } else if( i_plane == 2 ) {
538                     src += xyuv->i_width * xyuv->i_height;
539                 }
540                 if( xyuv->i_join > 0 ) {
541                     if( i_picture > 1 ) {
542                         src += xyuv->i_join / div;
543                         dst += xyuv->i_join / div;
544                         w = (xyuv->i_width - xyuv->i_join) /div;
545                     } else {
546                         w = xyuv->i_join / div;
547                     }
548                 }
549
550                 for( j = 0; j < xyuv->i_height / div; j++ ) {
551                     memcpy( dst, src, w );
552                     src += xyuv->i_width / div;
553                     dst += xyuv->overlay->pitches[i_plane];
554                 }
555             }
556         }
557
558         SDL_UnlockYUVOverlay( xyuv->overlay );
559     }
560
561     if( xyuv->f_y != 0.0 ) {
562         uint8_t *pix = xyuv->overlay->pixels[0];
563         int j;
564
565         for( j = 0; j < xyuv->i_sdl_height; j++ ) {
566             int k;
567             for( k = 0; k < xyuv->i_sdl_width; k++ ) {
568                 int v= pix[k] * xyuv->f_y;
569                 if( v > 255 )
570                     pix[k] = 255;
571                 else if( v < 0 )
572                     pix[k] = 0;
573                 else
574                     pix[k] = v;
575             }
576             pix += xyuv->overlay->pitches[0];
577         }
578     }
579     if( xyuv->b_grid ) {
580         int x, y;
581
582         for( y = 0; y < xyuv->i_sdl_height; y += 4 ) {
583             uint8_t *p = xyuv->overlay->pixels[0] + y * xyuv->overlay->pitches[0];
584             for( x = 0; x < xyuv->i_sdl_width; x += 4 ) {
585                 if( x%16== 0 || y%16 == 0 )
586                     p[x] = 0;
587             }
588         }
589     }
590
591     /* Update display */
592     rect.x = 0;
593     rect.y = 0;
594     rect.w = xyuv->i_display_width;
595     rect.h = xyuv->i_display_height;
596     SDL_DisplayYUVOverlay( xyuv->overlay, &rect );
597
598     /* Display title */
599     if( xyuv->title )
600         free( xyuv->title );
601     asprintf( &xyuv->title, SDL_TITLE, xyuv->yuv[0].name, xyuv->i_frame, xyuv->i_frames, xyuv->f_fps );
602     SDL_WM_SetCaption( xyuv->title, "" );
603 }
604
605
606
607