1 /*****************************************************************************
2 * frameshot: a frame-accurate screenshot generator.
3 *****************************************************************************
6 * Authors: Nathan Caldwell <saintdev@gmail.com>
7 * Various parts taken from x264.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 *****************************************************************************/
30 #include <sys/types.h>
59 /* input file function pointers */
60 int (*p_open_infile
)( char *psz_filename
, hnd_t
*p_handle
, config_t
*p_config
);
61 int (*p_read_frame
)( hnd_t handle
, picture_t
*p_pic
, int i_frame
);
62 int (*p_close_infile
)( hnd_t handle
);
64 /* output file function pointers */
65 static int (*p_open_outfile
)( char *psz_filename
, hnd_t
*p_handle
, int i_compression
);
66 // static int (*p_set_outfile_param)( hnd_t handle, config_t *p_config );
67 static int (*p_write_image
)( hnd_t handle
, picture_t
*p_pic
, config_t
*p_config
);
68 static int (*p_close_outfile
)( hnd_t handle
);
70 static int parse_options( int argc
, char **argv
, config_t
*config
, cli_opt_t
*opt
);
71 static int grab_frames( config_t
*config
, cli_opt_t
*opt
);
73 int main(int argc
, char **argv
)
79 parse_options(argc
, argv
, &config
, &opt
);
81 ret
= grab_frames( &config
, &opt
);
86 static void show_help(void)
89 HELP( "Syntax: frameshot [options] infile\n"
91 "Infile is a raw bitstream of one of the following codecs:\n"
92 " YUV4MPEG(*.y4m), Dirac(*.drc)\n"
96 " -h, --help Displays this message.\n"
98 HELP( " -f, --frames <int,int,...> Frames numbers to grab.\n" );
99 HELP( " -o, --outdir <string> Output directory for images.\n" );
100 HELP( " -z, --compression <integer> Ammount of compression to use.\n" );
101 HELP( " -1, --fast Use fastest compression.\n" );
102 HELP( " -9, --best Use best (slowest) compression.\n" );
106 static int parse_options( int argc
, char **argv
, config_t
*config
, cli_opt_t
*opt
)
108 char *psz_filename
= NULL
;
109 int i_zlevel
= Z_DEFAULT_COMPRESSION
;
110 char *psz
, *psz_token
;
115 memset( opt
, 0, sizeof(*opt
) );
117 /* Default input driver */
118 p_open_infile
= open_file_y4m
;
119 p_read_frame
= read_frame_y4m
;
120 p_close_infile
= close_file_y4m
;
122 /* Default output driver */
123 p_open_outfile
= open_file_png
;
124 p_write_image
= write_image_png
;
125 p_close_outfile
= close_file_png
;
129 int long_options_index
= -1;
130 static struct option long_options
[] =
132 { "fast", no_argument
, NULL
, '1' },
133 { "best", no_argument
, NULL
, '9' },
134 { "frames", required_argument
, NULL
, 'f' },
135 { "help", no_argument
, NULL
, 'h' },
136 { "outdir", required_argument
, NULL
, 'o' },
137 { "compression", required_argument
, NULL
, 'z' },
141 int c
= getopt_long( argc
, argv
, "19f:ho:z:",
142 long_options
, &long_options_index
);
152 i_zlevel
= Z_BEST_SPEED
;
155 i_zlevel
= Z_BEST_COMPRESSION
;
158 for( config
->i_frames
= 0; config
->i_frames
< MAX_FRAMES
; config
->i_frames
++, optarg
= NULL
)
160 psz_token
= strtok(optarg
, ",");
161 if( psz_token
== NULL
)
163 config
->frames
[config
->i_frames
] = atoi(psz_token
);
165 qsort(config
->frames
, config
->i_frames
, sizeof(*config
->frames
), intcmp
);
168 opt
->psz_outdir
= strdup(optarg
);
169 if( stat( opt
->psz_outdir
, &sb
) < 0 )
171 if( mkdir( opt
->psz_outdir
, S_IRWXU
) < 0 )
173 fprintf( stderr
, "ERROR: Unable to create output directory.\n" );
178 if( !S_ISDIR(sb
.st_mode
) )
180 fprintf(stderr
, "ERROR: Outdir exists, and is not a directory." );
186 if( optarg
== NULL
|| optarg
[0] < '0' || optarg
[0] > '9' )
188 opt
->i_zlevel
= Z_DEFAULT_COMPRESSION
;
191 opt
->i_zlevel
= atoi(optarg
);
200 /* Get the input file name */
201 if( optind
> argc
- 1 )
203 fprintf( stderr
, "ERROR: No input file.\n" );
207 psz_filename
= argv
[optind
++];
209 psz
= strrchr( psz_filename
, '.' );
210 if( !strncasecmp( psz
, ".y4m", 4 ) )
212 else if( !strncasecmp( psz
, ".drc", 4 ) )
215 if( !opt
->psz_outdir
)
216 opt
->psz_outdir
= getcwd(NULL
, 0);
220 p_open_infile
= open_file_y4m
;
221 p_read_frame
= read_frame_y4m
;
222 p_close_infile
= close_file_y4m
;
227 p_open_infile
= open_file_dirac
;
228 p_read_frame
= read_frame_dirac
;
229 p_close_infile
= close_file_dirac
;
232 if( p_open_infile( psz_filename
, &opt
->hin
, config
) )
234 fprintf( stderr
, "ERROR: could not open input file '%s'\n", psz_filename
);
241 static int grab_frames( config_t
*config
, cli_opt_t
*opt
)
248 pic
.img
.plane
[0] = calloc(1, 3 * config
->i_width
* config
->i_height
/ 2);
249 pic
.img
.plane
[1] = pic
.img
.plane
[0] + config
->i_width
* config
->i_height
;
250 pic
.img
.plane
[2] = pic
.img
.plane
[1] + config
->i_width
* config
->i_height
/ 4;
251 pic
.img
.plane
[3] = NULL
;
253 pic
.img
.i_stride
[0] = config
->i_width
;
254 pic
.img
.i_stride
[1] = pic
.img
.i_stride
[2] = config
->i_width
/ 2;
255 pic
.img
.i_stride
[3] = 0;
257 for(i
= 0; i
< config
->i_frames
; i
++ )
259 p_read_frame( opt
->hin
, &pic
, config
->frames
[i
] );
261 snprintf(tmp
, PATH_MAX
, "%s/%05d.png", opt
->psz_outdir
, config
->frames
[i
]);
262 p_open_outfile( tmp
, &hout
, opt
->i_zlevel
);
263 p_write_image( hout
, &pic
, config
);
264 p_close_outfile( hout
);
267 p_close_infile( opt
->hin
);
269 if( opt
->psz_outdir
)
270 free(opt
->psz_outdir
);