8e8063271f8cdba5a5b6caba2887399f5dfd4b06
[x262.git] / tools / xyuv.c
1 /*****************************************************************************
2  * xyuv.c: a SDL yuv 420 planer viewer.
3  *****************************************************************************
4  * Copyright (C) 2004 Laurent Aimar <fenrir@via.ecp.fr>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
19  *****************************************************************************/
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdint.h>
25
26 #include <SDL/SDL.h>
27
28 #define YUV_MAX 20
29 #define SDL_TITLE "xyuv: %s - %d/%d - %.2ffps"
30 typedef struct
31 {
32     /* globals */
33     int     i_width;
34     int     i_height;
35     int     i_frame_size;
36     int     i_frame;
37     int     i_frames;
38     float   f_fps;
39
40     float   f_y;
41
42     int     b_pause;
43     int     b_grid;
44     int     b_split;
45     int     b_diff;
46     int     i_join;
47
48     /* Constructed picture */
49     int     i_wall_width;   /* in picture count */
50
51     /* YUV files */
52     int     i_yuv;
53     struct
54     {
55         char    *name;
56         FILE    *f;         /* handles */
57         int     i_frames;   /* frames count */
58
59         /* Position in the whole picture */
60         int     x, y;
61     } yuv[YUV_MAX];
62
63     /* SDL */
64     int i_sdl_width;
65     int i_sdl_height;
66
67     int i_display_width;
68     int i_display_height;
69     char *title;
70
71     SDL_Surface *screen;
72     SDL_Overlay *overlay;
73
74     /* */
75     uint8_t *pic;
76
77 } xyuv_t;
78
79 xyuv_t xyuv = {
80     .i_width = 0,
81     .i_height = 0,
82     .i_frame  = 1,
83     .i_frames = 0,
84     .f_fps = 25.0,
85     .f_y = 0.0,
86     .i_wall_width = 0,
87
88     .i_yuv = 0,
89
90     .b_pause = 0,
91     .b_split = 0,
92     .b_diff = 0,
93     .i_join = -1,
94
95     .title = NULL,
96     .pic = NULL,
97 };
98
99 static void help( void )
100 {
101     fprintf( stderr,
102              "Syntax: xyuv [options] file [file2 ...]\n"
103              "\n"
104              "      --help                  Print this help\n"
105              "\n"
106              "  -s, --size <WIDTHxHEIGHT>   Set input size\n"
107              "  -w, --width <integer>       Set width\n"
108              "  -h, --height <integer>      Set height\n"
109              "\n"
110              "  -S, --split                 Show splited Y/U/V planes\n"
111              "  -d, --diff                  Show difference (only 2 files) in split mode\n"
112              "  -j, --joint <integer>\n"
113              "\n"
114              "  -y <float>                  Set Y factor\n"
115              "\n"
116              "  -g, --grid                  Show a grid (macroblock 16x16)\n"
117              "  -W <integer>                Set wall width (in picture count)\n"
118              "  -f, --fps <float>           Set fps\n"
119              "\n" );
120 }
121
122 static void xyuv_count_frames( xyuv_t *xyuv );
123 static void xyuv_detect( int *pi_width, int *pi_height );
124 static void xyuv_display( xyuv_t *xyuv, int i_frame );
125
126 int main( int argc, char **argv )
127 {
128     int i;
129
130     /* Parse commande line */
131     for( i = 1; i < argc; i++ ) {
132         if( !strcasecmp( argv[i], "--help" ) ) {
133             help();
134             return 0;
135         }
136         if( !strcmp( argv[i], "-d" ) || !strcasecmp( argv[i], "--diff" ) ) {
137             xyuv.b_diff = 1;
138         } else if( !strcmp( argv[i], "-S" ) || !strcasecmp( argv[i], "--split" ) ) {
139             xyuv.b_split = 1;
140         } else if( !strcmp( argv[i], "-f" ) || !strcasecmp( argv[i], "--fps" ) ) {
141             if( i >= argc -1 ) goto err_missing_arg;
142             xyuv.f_fps = atof( argv[++i] );
143         } else if( !strcmp( argv[i], "-h" ) || !strcasecmp( argv[i], "--height" ) ) {
144             if( i >= argc -1 ) goto err_missing_arg;
145             xyuv.i_height = atoi( argv[++i] );
146         } else if( !strcmp( argv[i], "-w" ) || !strcasecmp( argv[i], "--width" ) ) {
147             if( i >= argc -1 ) goto err_missing_arg;
148             xyuv.i_width = atoi( argv[++i] );
149         } else if( !strcmp( argv[i], "-s" ) || !strcasecmp( argv[i], "--size" ) ) {
150             char *p;
151
152             if( i >= argc -1 ) goto err_missing_arg;
153
154             xyuv.i_width = strtol( argv[++i], &p, 0 );
155             p++;
156             xyuv.i_height = atoi( p );
157         } else if( !strcmp( argv[i], "-W" ) ) {
158             if( i >= argc -1 ) goto err_missing_arg;
159             xyuv.i_wall_width = atoi( argv[++i] );
160         } else if( !strcmp( argv[i], "-y" ) ) {
161             if( i >= argc -1 ) goto err_missing_arg;
162             xyuv.f_y = atof( argv[++i] );
163         } else if( !strcmp( argv[i], "-j" ) || !strcasecmp( argv[i], "--join" ) ) {
164             if( i >= argc -1 ) goto err_missing_arg;
165             xyuv.i_join = atoi( argv[++i] );
166         } else if( !strcmp( argv[i], "-g" ) || !strcasecmp( argv[i], "--grid" ) ) {
167             xyuv.b_grid = 1;
168         } else {
169             FILE *f = fopen( argv[i], "rb" );
170             if( !f ) {
171                 fprintf( stderr, "cannot open YUV %s\n", argv[i] );
172             } else {
173                 xyuv.yuv[xyuv.i_yuv].name = strdup( argv[i] );
174                 xyuv.yuv[xyuv.i_yuv].f = f;
175                 xyuv.yuv[xyuv.i_yuv].i_frames = 0;
176
177                 xyuv.i_yuv++;
178             }
179         }
180     }
181
182     if( xyuv.i_yuv == 0 ) {
183         fprintf( stderr, "no file to display\n" );
184         return -1;
185     }
186     if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
187         char *psz = xyuv.yuv[0].name;
188         char *num;
189         char *x;
190         /* See if we find widthxheight in the file name */
191         for( ;; ) {
192             if( !( x = strchr( psz+1, 'x' ) ) ) {
193                 break;
194             }
195             num = x;
196             while( num > psz && num[-1] >= '0' && num[-1] <= '9' )
197                 num--;
198
199             if( num != x && x[1] >= '0' && x[1] <= '9' ) {
200                 xyuv.i_width = atoi( num );
201                 xyuv.i_height = atoi( x+1 );
202                 break;
203             }
204             psz = x;
205         }
206         fprintf( stderr, "file name gives %dx%d\n", xyuv.i_width, xyuv.i_height );
207     }
208
209     if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
210         xyuv_detect( &xyuv.i_width, &xyuv.i_height );
211     }
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_frame_size = 3 * xyuv.i_width * xyuv.i_height / 2;
235     xyuv_count_frames( &xyuv );
236     for( i = 0; i < xyuv.i_yuv; i++ ) {
237         fprintf( stderr, " - '%s' : %d frames\n", xyuv.yuv[i].name, xyuv.yuv[i].i_frames );
238     }
239
240     if( xyuv.i_frames == 0 ) {
241         fprintf( stderr, "no frames to display\n" );
242     }
243
244     xyuv.pic = malloc( xyuv.i_frame_size );
245
246     /* calculate SDL view */
247     if( xyuv.i_wall_width > xyuv.i_yuv ) {
248         xyuv.i_wall_width = xyuv.i_yuv;
249     }
250     if( xyuv.i_wall_width == 0 ) {
251         while( xyuv.i_wall_width < xyuv.i_yuv && xyuv.i_wall_width * xyuv.i_wall_width < xyuv.i_yuv ) {
252             xyuv.i_wall_width++;
253         }
254     }
255
256     for( i = 0; i < xyuv.i_yuv; i++ ) {
257         if( xyuv.b_diff || xyuv.i_join > 0 ) {
258             xyuv.yuv[i].x = 0;
259             xyuv.yuv[i].y = 0;
260         } else if( xyuv.b_split ) {
261             xyuv.yuv[i].x = (i%xyuv.i_wall_width) * 3 * xyuv.i_width / 2;
262             xyuv.yuv[i].y = (i/xyuv.i_wall_width) * xyuv.i_height;
263         } else {
264             xyuv.yuv[i].x = (i%xyuv.i_wall_width) * xyuv.i_width;
265             xyuv.yuv[i].y = (i/xyuv.i_wall_width) * xyuv.i_height;
266         }
267     }
268     if( xyuv.b_diff ) {
269         xyuv.i_sdl_width = 3 * xyuv.i_width / 2;
270         xyuv.i_sdl_height= xyuv.i_height;
271     } else if( xyuv.i_join > 0 ) {
272         xyuv.i_sdl_width = xyuv.i_width;
273         xyuv.i_sdl_height= xyuv.i_height;
274     } else if( xyuv.b_split ) {
275         xyuv.i_sdl_width = xyuv.i_wall_width * 3 * xyuv.i_width / 2;
276         xyuv.i_sdl_height= xyuv.i_height * ( ( xyuv.i_yuv  + xyuv.i_wall_width - 1 ) / xyuv.i_wall_width );
277     } else {
278         xyuv.i_sdl_width = xyuv.i_wall_width * xyuv.i_width;
279         xyuv.i_sdl_height= xyuv.i_height * ( ( xyuv.i_yuv  + xyuv.i_wall_width - 1 ) / xyuv.i_wall_width );
280     }
281     xyuv.i_display_width = xyuv.i_sdl_width;
282     xyuv.i_display_height = xyuv.i_sdl_height;
283
284     /* Open SDL */
285     if( SDL_Init( SDL_INIT_EVENTTHREAD|SDL_INIT_NOPARACHUTE|SDL_INIT_VIDEO) ) {
286         fprintf( stderr, "cannot init SDL\n" );
287         return -1;
288     }
289
290     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 100 );
291     SDL_EventState( SDL_KEYUP, SDL_IGNORE );
292
293     xyuv.screen = SDL_SetVideoMode( xyuv.i_sdl_width, xyuv.i_sdl_height, 0,
294                                     SDL_HWSURFACE|SDL_RESIZABLE|
295                                     SDL_ASYNCBLIT|SDL_HWACCEL );
296     if( xyuv.screen == NULL ) {
297         fprintf( stderr, "SDL_SetVideoMode failed\n" );
298         return -1;
299     }
300
301     SDL_LockSurface( xyuv.screen );
302     xyuv.overlay = SDL_CreateYUVOverlay( xyuv.i_sdl_width, xyuv.i_sdl_height,
303                                          SDL_YV12_OVERLAY,
304                                          xyuv.screen );
305     /* reset with black */
306     memset( xyuv.overlay->pixels[0],   0, xyuv.overlay->pitches[0] * xyuv.i_sdl_height );
307     memset( xyuv.overlay->pixels[1], 128, xyuv.overlay->pitches[1] * xyuv.i_sdl_height / 2);
308     memset( xyuv.overlay->pixels[2], 128, xyuv.overlay->pitches[2] * xyuv.i_sdl_height / 2);
309     SDL_UnlockSurface( xyuv.screen );
310
311     if( xyuv.overlay == NULL ) {
312         fprintf( stderr, "recon: SDL_CreateYUVOverlay failed\n" );
313         return -1;
314     }
315
316     for( ;; ) {
317         SDL_Event event;
318         static int b_fullscreen = 0;
319         int64_t i_start = SDL_GetTicks();
320         int i_wait;
321
322         if( !xyuv.b_pause ) {
323             xyuv_display( &xyuv, xyuv.i_frame );
324         }
325
326         for( ;; ) {
327             int b_refresh = 0;
328             while( SDL_PollEvent( &event ) )  {
329                 switch( event.type )
330                 {
331                     case SDL_QUIT:
332                         if( b_fullscreen )
333                             SDL_WM_ToggleFullScreen( xyuv.screen );
334                         exit( 1 );
335
336                     case SDL_KEYDOWN:
337                         switch( event.key.keysym.sym )
338                         {
339                             case SDLK_q:
340                             case SDLK_ESCAPE:
341                                 if( b_fullscreen )
342                                     SDL_WM_ToggleFullScreen( xyuv.screen );
343                                 exit(1);
344
345                             case SDLK_f:
346                                 if( SDL_WM_ToggleFullScreen( xyuv.screen ) )
347                                     b_fullscreen = 1 - b_fullscreen;
348                                 break;
349
350                             case SDLK_g:
351                                 if( xyuv.b_grid )
352                                     xyuv.b_grid = 0;
353                                 else
354                                     xyuv.b_grid = 1;
355                                 if( xyuv.b_pause )
356                                     b_refresh = 1;
357                                 break;
358
359                             case SDLK_SPACE:
360                                 if( xyuv.b_pause )
361                                     xyuv.b_pause = 0;
362                                 else
363                                     xyuv.b_pause = 1;
364                                 break;
365                             case SDLK_LEFT:
366                                 if( xyuv.i_frame > 1 ) xyuv.i_frame--;
367                                 b_refresh = 1;
368                                 break;
369
370                             case SDLK_RIGHT:
371                                 if( xyuv.i_frame >= xyuv.i_frames )
372                                     xyuv_count_frames( &xyuv );
373                                 if( xyuv.i_frame < xyuv.i_frames ) xyuv.i_frame++;
374                                 b_refresh = 1;
375                                 break;
376
377                             case SDLK_HOME:
378                                 xyuv.i_frame = 1;
379                                 if( xyuv.b_pause )
380                                     b_refresh = 1;
381                                 break;
382
383                             case SDLK_END:
384                                 xyuv_count_frames( &xyuv );
385                                 xyuv.i_frame = xyuv.i_frames;
386                                 b_refresh = 1;
387                                 break;
388
389                             case SDLK_UP:
390                                 xyuv.i_frame += xyuv.i_frames / 20;
391
392                                 if( xyuv.i_frame >= xyuv.i_frames )
393                                     xyuv_count_frames( &xyuv );
394
395                                 if( xyuv.i_frame > xyuv.i_frames )
396                                     xyuv.i_frame = xyuv.i_frames;
397                                 b_refresh = 1;
398                                 break;
399
400                             case SDLK_DOWN:
401                                 xyuv.i_frame -= xyuv.i_frames / 20;
402                                 if( xyuv.i_frame < 1 )
403                                     xyuv.i_frame = 1;
404                                 b_refresh = 1;
405                                 break;
406
407                             case SDLK_PAGEUP:
408                                 xyuv.i_frame += xyuv.i_frames / 10;
409
410                                 if( xyuv.i_frame >= xyuv.i_frames )
411                                     xyuv_count_frames( &xyuv );
412
413                                 if( xyuv.i_frame > xyuv.i_frames )
414                                     xyuv.i_frame = xyuv.i_frames;
415                                 b_refresh = 1;
416                                 break;
417
418                             case SDLK_PAGEDOWN:
419                                 xyuv.i_frame -= xyuv.i_frames / 10;
420                                 if( xyuv.i_frame < 1 )
421                                     xyuv.i_frame = 1;
422                                 b_refresh = 1;
423                                 break;
424
425                             default:
426                                 break;
427                         }
428                         break;
429                     case SDL_VIDEORESIZE:
430                         xyuv.i_display_width = event.resize.w;
431                         xyuv.i_display_height = event.resize.h;
432                         xyuv.screen = SDL_SetVideoMode( xyuv.i_display_width, xyuv.i_display_height, 0,
433                                                         SDL_HWSURFACE|SDL_RESIZABLE|
434                                                         SDL_ASYNCBLIT|SDL_HWACCEL );
435                         xyuv_display( &xyuv, xyuv.i_frame );
436                         break;
437
438                     default:
439                         break;
440                 }
441             }
442             if( b_refresh ) {
443                 xyuv.b_pause = 1;
444                 xyuv_display( &xyuv, xyuv.i_frame );
445             }
446             /* wait */
447             i_wait = 1000 / xyuv.f_fps - ( SDL_GetTicks() - i_start);
448             if( i_wait < 0 )
449                 break;
450             else if( i_wait > 200 )
451                 SDL_Delay( 200 );
452             else {
453                 SDL_Delay( i_wait );
454                 break;
455             }
456         }
457         if( !xyuv.b_pause ) {
458             /* next frame */
459             if( xyuv.i_frame == xyuv.i_frames )
460                     xyuv.b_pause = 1;
461             else if( xyuv.i_frame < xyuv.i_frames )
462                 xyuv.i_frame++;
463         }
464     }
465
466
467     return 0;
468
469 err_missing_arg:
470     fprintf( stderr, "missing arg for option=%s\n", argv[i] );
471     return -1;
472 }
473
474
475 static void xyuv_display( xyuv_t *xyuv, int i_frame )
476 {
477     SDL_Rect rect;
478     int i_picture = 0;
479     int i;
480
481     if( i_frame > xyuv->i_frames )
482         return;
483
484     xyuv->i_frame = i_frame;
485
486     /* Load and copy pictue data */
487     for( i = 0; i < xyuv->i_yuv; i++ ) {
488         int i_plane;
489
490         fprintf( stderr, "yuv[%d] %d/%d\n", i, i_frame, xyuv->yuv[i].i_frames );
491         if( i_frame - 1 >= xyuv->yuv[i].i_frames ) {
492             xyuv_count_frames( xyuv );
493             if( i_frame - 1 >= xyuv->yuv[i].i_frames )
494                 continue;
495         }
496         i_picture++;
497
498         fseek( xyuv->yuv[i].f, (xyuv->i_frame-1) * xyuv->i_frame_size, SEEK_SET );
499         fread( xyuv->pic, xyuv->i_frame_size, 1, xyuv->yuv[i].f );
500
501         SDL_LockYUVOverlay( xyuv->overlay );
502
503         if( xyuv->b_diff || xyuv->b_split ) {
504             /* Reset UV */
505             for( i_plane = 1; i_plane < 3; i_plane++ ) {
506                 memset( xyuv->overlay->pixels[i_plane], 128, xyuv->overlay->pitches[i_plane] * xyuv->overlay->h / 2 );
507             }
508             /* Show diff in Y plane of overlay */
509
510             for( i_plane = 0; i_plane < 3; i_plane++ ) {
511                 int div = i_plane == 0 ? 1 : 2;
512                 uint8_t *src = xyuv->pic;
513                 uint8_t *dst = xyuv->overlay->pixels[0] +
514                                 (xyuv->yuv[i].x + xyuv->yuv[i].y * xyuv->overlay->pitches[0] );
515                 int j;
516                 if( i_plane == 1 ) {
517                     src +=  5*xyuv->i_width * xyuv->i_height/4;
518                     dst += xyuv->i_width;
519                 } else if( i_plane == 2 ) {
520                     src += xyuv->i_width * xyuv->i_height;
521                     dst += xyuv->i_width + xyuv->i_height / 2 * xyuv->overlay->pitches[0];
522                 }
523
524                 for( j = 0; j < xyuv->i_height / div; j++ ) {
525                     if( i_picture == 1 || xyuv->b_split ) {
526                         memcpy( dst, src, xyuv->i_width / div );
527                     } else {
528                         int k;
529                         for( k = 0; k < xyuv->i_width / div; k++ ) {
530                             dst[k] = abs( dst[k] - src[k]);
531                         }
532                     }
533                     src += xyuv->i_width / div;
534                     dst += xyuv->overlay->pitches[0];
535                 }
536             }
537         } else {
538             for( i_plane = 0; i_plane < 3; i_plane++ ) {
539                 int div = i_plane == 0 ? 1 : 2;
540                 uint8_t *src = xyuv->pic;
541                 uint8_t *dst = xyuv->overlay->pixels[i_plane] +
542                                 ((xyuv->yuv[i].x + xyuv->yuv[i].y * xyuv->overlay->pitches[i_plane] ) / div );
543                 int w = xyuv->i_width / div;
544                 int j;
545
546                 if( i_plane == 1 ) {
547                     src +=  5*xyuv->i_width * xyuv->i_height/4;
548                 } else if( i_plane == 2 ) {
549                     src += xyuv->i_width * xyuv->i_height;
550                 }
551                 if( xyuv->i_join > 0 ) {
552                     if( i_picture > 1 ) {
553                         src += xyuv->i_join / div;
554                         dst += xyuv->i_join / div;
555                         w = (xyuv->i_width - xyuv->i_join) /div;
556                     } else {
557                         w = xyuv->i_join / div;
558                     }
559                 }
560
561                 for( j = 0; j < xyuv->i_height / div; j++ ) {
562                     memcpy( dst, src, w );
563                     src += xyuv->i_width / div;
564                     dst += xyuv->overlay->pitches[i_plane];
565                 }
566             }
567         }
568
569         SDL_UnlockYUVOverlay( xyuv->overlay );
570     }
571
572     if( xyuv->f_y != 0.0 ) {
573         uint8_t *pix = xyuv->overlay->pixels[0];
574         int j;
575
576         for( j = 0; j < xyuv->i_sdl_height; j++ ) {
577             int k;
578             for( k = 0; k < xyuv->i_sdl_width; k++ ) {
579                 int v= pix[k] * xyuv->f_y;
580                 if( v > 255 )
581                     pix[k] = 255;
582                 else if( v < 0 )
583                     pix[k] = 0;
584                 else
585                     pix[k] = v;
586             }
587             pix += xyuv->overlay->pitches[0];
588         }
589     }
590     if( xyuv->b_grid ) {
591         int x, y;
592
593         for( y = 0; y < xyuv->i_sdl_height; y += 4 ) {
594             uint8_t *p = xyuv->overlay->pixels[0] + y * xyuv->overlay->pitches[0];
595             for( x = 0; x < xyuv->i_sdl_width; x += 4 ) {
596                 if( x%16== 0 || y%16 == 0 )
597                     p[x] = 0;
598             }
599         }
600     }
601
602     /* Update display */
603     rect.x = 0;
604     rect.y = 0;
605     rect.w = xyuv->i_display_width;
606     rect.h = xyuv->i_display_height;
607     SDL_DisplayYUVOverlay( xyuv->overlay, &rect );
608
609     /* Display title */
610     if( xyuv->title )
611         free( xyuv->title );
612     asprintf( &xyuv->title, SDL_TITLE, xyuv->yuv[0].name, xyuv->i_frame, xyuv->i_frames, xyuv->f_fps );
613     SDL_WM_SetCaption( xyuv->title, "" );
614 }
615
616 static void xyuv_count_frames( xyuv_t *xyuv )
617 {
618     int i;
619
620     xyuv->i_frames = 0;
621     if( xyuv->i_frame_size <= 0 )
622         return;
623
624     for( i = 0; i < xyuv->i_yuv; i++ ) {
625         /* Beurk but avoid using fstat */
626         fseek( xyuv->yuv[i].f, 0, SEEK_END );
627
628         xyuv->yuv[i].i_frames = ftell( xyuv->yuv[i].f ) / xyuv->i_frame_size;
629         fprintf( stderr, "count (%d) -> %d\n", i, xyuv->yuv[i].i_frames );
630
631         fseek( xyuv->yuv[i].f, 0, SEEK_SET );
632
633         if( xyuv->i_frames < xyuv->yuv[i].i_frames )
634             xyuv->i_frames = xyuv->yuv[i].i_frames;
635     }
636 }
637
638 static inline int ssd( int a ) { return a*a; }
639
640 static void xyuv_detect( int *pi_width, int *pi_height )
641 {
642     static const int pi_size[][2] = {
643         {128, 96},
644         {160,120},
645         {320,244},
646         {320,288},
647
648         /* PAL */
649         {176,144},  // QCIF
650         {352,288},  // CIF
651         {352,576},  // 1/2 D1
652         {480,576},  // 2/3 D1
653         {544,576},
654         {640,576},  // VGA
655         {704,576},  // D1
656         {720,576},  // D1
657
658         /* NTSC */
659         {176,112},  // QCIF
660         {320,240},  // MPEG I
661         {352,240},  // CIF
662         {352,480},  // 1/2 D1
663         {480,480},  // 2/3 D1
664         {544,480},
665         {640,480},  // VGA
666         {704,480},  // D1
667         {720,480},  // D1
668
669         /* */
670         {0,0},
671     };
672     int i_max;
673     int i_size_max;
674     uint8_t *pic;
675     int i;
676
677     *pi_width = 0;
678     *pi_height = 0;
679
680     /* Compute size max */
681     for( i_max = 0, i_size_max = 0;
682             pi_size[i_max][0] != 0 && pi_size[i_max][1] != 0; i_max++ ) {
683         int s = pi_size[i_max][0] * pi_size[i_max][1] * 3 / 2;
684
685         if( i_size_max < s )
686             i_size_max = s;
687     }
688
689     /* Temporary buffer */
690     i_size_max *= 3;
691     pic = malloc( i_size_max );
692
693     fprintf( stderr, "guessing size for:\n" );
694     for( i = 0; i < xyuv.i_yuv; i++ ) {
695         int j;
696         int i_read;
697         double dbest = 255*255;
698         int    i_best = i_max;
699         int64_t t;
700
701         fprintf( stderr, " - %s\n", xyuv.yuv[i].name );
702
703         i_read = fread( pic, 1, i_size_max, xyuv.yuv[i].f );
704         if( i_read < 0 )
705             continue;
706
707         /* Check if file size is at least compatible with one format
708          * (if not, ignore file size)*/
709         fseek( xyuv.yuv[i].f, 0, SEEK_END );
710         t = ftell( xyuv.yuv[i].f );
711         fseek( xyuv.yuv[i].f, 0, SEEK_SET );
712         for( j = 0; j < i_max; j++ ) {
713             const int w = pi_size[j][0];
714             const int h = pi_size[j][1];
715             const int s = w * h * 3 / 2;
716
717             if( t % s == 0 )
718                 break;
719         }
720         if( j == i_max )
721             t = 0;
722
723
724         /* Try all size */
725         for( j = 0; j < i_max; j++ ) {
726             const int w = pi_size[j][0];
727             const int h = pi_size[j][1];
728             const int s = w * h * 3 / 2;
729             double dd;
730
731             int x, y, n;
732             int64_t d;
733
734             /* To small */
735             if( i_read < 3*s )
736                 continue;
737             /* Check file size */
738             if( ( t > 0 && (t % s) != 0  ) ) {
739                 fprintf( stderr, "  * %dx%d ignored (incompatible file size)\n", w, h );
740                 continue;
741             }
742
743
744             /* We do a simple ssd between 2 consecutives lines */
745             d = 0;
746             for( n = 0; n < 3; n++ ) {
747                 uint8_t *p;
748
749                 /* Y */
750                 p = &pic[n*s];
751                 for( y = 0; y < h-1; y++ ) {
752                     for( x = 0; x < w; x++ )
753                         d += ssd( p[x] - p[w+x] );
754                     p += w;
755                 }
756
757                 /* U */
758                 p = &pic[n*s+w*h];
759                 for( y = 0; y < h/2-1; y++ ) {
760                     for( x = 0; x < w/2; x++ )
761                         d += ssd( p[x] - p[(w/2)+x] );
762                     p += w/2;
763                 }
764
765                 /* V */
766                 p = &pic[n*s+5*w*h/4];
767                 for( y = 0; y < h/2-1; y++ ) {
768                     for( x = 0; x < w/2; x++ )
769                         d += ssd( p[x] - p[(w/2)+x] );
770                     p += w/2;
771                 }
772             }
773             dd = (double)d / (3*w*h*3/2);
774             fprintf( stderr, "  * %dx%d d=%f\n", w, h, dd );
775
776             if( dd < dbest ) {
777                 i_best = j;
778                 dbest = dd;
779             }
780         }
781
782         fseek( xyuv.yuv[i].f, 0, SEEK_SET );
783
784         if( i_best < i_max ) {
785             fprintf( stderr, "  -> %dx%d\n", pi_size[i_best][0], pi_size[i_best][1] );
786             *pi_width = pi_size[i_best][0];
787             *pi_height = pi_size[i_best][1];
788         }
789     }
790
791     free( pic );
792 }