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 $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
32 #define SDL_TITLE "xyuv: %s - %d/%d - %.2ffps"
51 /* Constructed picture */
52 int i_wall_width; /* in picture count */
59 FILE *f; /* handles */
60 int i_frames; /* frames count */
62 /* Position in the whole picture */
102 static void help( void )
105 "Syntax: xyuv [options] file [file2 ...]\n"
107 " --help Print this help\n"
109 " -s, --size <WIDTHxHEIGHT> Set input size\n"
110 " -w, --width <integer> Set width\n"
111 " -h, --height <integer> Set height\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"
117 " -y <float> Set Y factor\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"
126 static void xyuv_display( xyuv_t *xyuv, int i_frame );
128 int main( int argc, char **argv )
132 /* Parse commande line */
133 for( i = 1; i < argc; i++ ) {
134 if( !strcasecmp( argv[i], "--help" ) ) {
138 if( !strcmp( argv[i], "-d" ) || !strcasecmp( argv[i], "--diff" ) ) {
140 } else if( !strcmp( argv[i], "-S" ) || !strcasecmp( argv[i], "--split" ) ) {
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" ) ) {
154 if( i >= argc -1 ) goto err_missing_arg;
156 xyuv.i_width = strtol( argv[++i], &p, 0 );
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" ) ) {
171 FILE *f = fopen( argv[i], "rb" );
173 fprintf( stderr, "cannot open YUV %s\n", argv[i] );
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;
184 if( xyuv.i_yuv == 0 ) {
185 fprintf( stderr, "no file to display\n" );
188 if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
189 char *psz = xyuv.yuv[0].name;
192 /* See if we find widthxheight in the file name */
195 if( !( x = strchr( psz+1, 'x' ) ) )
200 while( num > psz && num[-1] >= '0' && num[-1] <= '9' )
203 if( num != x && x[1] >= '0' && x[1] <= '9' )
205 xyuv.i_width = atoi( num );
206 xyuv.i_height = atoi( x+1 );
211 fprintf( stderr, "file name gives %dx%d\n", xyuv.i_width, xyuv.i_height );
213 if( xyuv.i_width == 0 || xyuv.i_height == 0 ) {
214 fprintf( stderr, "invalid or missing frames size\n" );
217 if( xyuv.b_diff && xyuv.i_yuv != 2 ) {
218 fprintf( stderr, "--diff works only with 2 files\n" );
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" );
225 if( xyuv.i_join % 2 != 0 ) {
226 if( xyuv.i_join + 1 < xyuv.i_width )
232 /* Now check frames */
233 fprintf( stderr, "displaying :\n" );
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 );
240 xyuv.yuv[i].i_frames = ftell( xyuv.yuv[i].f ) / xyuv.i_frame_size;
242 fseek( xyuv.yuv[i].f, 0, SEEK_SET );
244 fprintf( stderr, " - '%s' : %d frames\n", xyuv.yuv[i].name, xyuv.yuv[i].i_frames );
246 if( xyuv.i_frames < xyuv.yuv[i].i_frames )
247 xyuv.i_frames = xyuv.yuv[i].i_frames;
250 if( xyuv.i_frames == 0 ) {
251 fprintf( stderr, "no frames to display\n" );
254 xyuv.pic = malloc( xyuv.i_frame_size );
256 /* calculate SDL view */
257 if( xyuv.i_wall_width > xyuv.i_yuv ) {
258 xyuv.i_wall_width = xyuv.i_yuv;
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 ) {
266 for( i = 0; i < xyuv.i_yuv; i++ ) {
267 if( xyuv.b_diff || xyuv.i_join > 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;
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;
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 );
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 );
291 xyuv.i_display_width = xyuv.i_sdl_width;
292 xyuv.i_display_height = xyuv.i_sdl_height;
295 if( SDL_Init( SDL_INIT_EVENTTHREAD|SDL_INIT_NOPARACHUTE|SDL_INIT_VIDEO) ) {
296 fprintf( stderr, "cannot init SDL\n" );
300 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 100 );
301 SDL_EventState( SDL_KEYUP, SDL_IGNORE );
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" );
311 SDL_LockSurface( xyuv.screen );
312 xyuv.overlay = SDL_CreateYUVOverlay( xyuv.i_sdl_width, xyuv.i_sdl_height,
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 );
321 if( xyuv.overlay == NULL ) {
322 fprintf( stderr, "recon: SDL_CreateYUVOverlay failed\n" );
328 int64_t i_start = SDL_GetTicks();
331 if( !xyuv.b_pause ) {
332 xyuv_display( &xyuv, xyuv.i_frame );
337 while( SDL_PollEvent( &event ) ) {
344 switch( event.key.keysym.sym )
351 SDL_WM_ToggleFullScreen( xyuv.screen );
370 if( xyuv.i_frame > 1 ) xyuv.i_frame--;
375 if( xyuv.i_frame < xyuv.i_frames ) xyuv.i_frame++;
386 xyuv.i_frame = xyuv.i_frames;
391 xyuv.i_frame += xyuv.i_frames / 20;
392 if( xyuv.i_frame > xyuv.i_frames )
393 xyuv.i_frame = xyuv.i_frames;
398 xyuv.i_frame -= xyuv.i_frames / 20;
399 if( xyuv.i_frame < 1 )
405 xyuv.i_frame += xyuv.i_frames / 10;
406 if( xyuv.i_frame > xyuv.i_frames )
407 xyuv.i_frame = xyuv.i_frames;
412 xyuv.i_frame -= xyuv.i_frames / 10;
413 if( xyuv.i_frame < 1 )
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 );
437 xyuv_display( &xyuv, xyuv.i_frame );
440 i_wait = 1000 / xyuv.f_fps - ( SDL_GetTicks() - i_start);
443 else if( i_wait > 200 )
450 if( !xyuv.b_pause ) {
452 if( xyuv.i_frame == xyuv.i_frames )
454 else if( xyuv.i_frame < xyuv.i_frames )
463 fprintf( stderr, "missing arg for option=%s\n", argv[i] );
468 static void xyuv_display( xyuv_t *xyuv, int i_frame )
474 if( i_frame > xyuv->i_frames )
477 xyuv->i_frame = i_frame;
479 /* Load and copy pictue data */
480 for( i = 0; i < xyuv->i_yuv; i++ ) {
483 if( i_frame - 1 >= xyuv->yuv[i].i_frames )
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 );
490 SDL_LockYUVOverlay( xyuv->overlay );
492 if( xyuv->b_diff || xyuv->b_split ) {
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 );
497 /* Show diff in Y plane of overlay */
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] );
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];
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 );
518 for( k = 0; k < xyuv->i_width / div; k++ ) {
519 dst[k] = abs( dst[k] - src[k]);
522 src += xyuv->i_width / div;
523 dst += xyuv->overlay->pitches[0];
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;
536 src += 5*xyuv->i_width * xyuv->i_height/4;
537 } else if( i_plane == 2 ) {
538 src += xyuv->i_width * xyuv->i_height;
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;
546 w = xyuv->i_join / div;
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];
558 SDL_UnlockYUVOverlay( xyuv->overlay );
561 if( xyuv->f_y != 0.0 ) {
562 uint8_t *pix = xyuv->overlay->pixels[0];
565 for( j = 0; j < xyuv->i_sdl_height; j++ ) {
567 for( k = 0; k < xyuv->i_sdl_width; k++ ) {
568 int v= pix[k] * xyuv->f_y;
576 pix += xyuv->overlay->pitches[0];
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 )
594 rect.w = xyuv->i_display_width;
595 rect.h = xyuv->i_display_height;
596 SDL_DisplayYUVOverlay( xyuv->overlay, &rect );
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, "" );