+ const char *ext = get_filename_extension( filename );
+ if( !strcmp( filename, "-" ) || strcasecmp( muxer, "auto" ) )
+ ext = muxer;
+
+ if( !strcasecmp( ext, "mp4" ) )
+ {
+#if HAVE_GPAC
+ output = mp4_output;
+ param->b_annexb = 0;
+ param->b_repeat_headers = 0;
+ if( param->i_nal_hrd == X264_NAL_HRD_CBR )
+ {
+ x264_cli_log( "x264", X264_LOG_WARNING, "cbr nal-hrd is not compatible with mp4\n" );
+ param->i_nal_hrd = X264_NAL_HRD_VBR;
+ }
+#else
+ x264_cli_log( "x264", X264_LOG_ERROR, "not compiled with MP4 output support\n" );
+ return -1;
+#endif
+ }
+ else if( !strcasecmp( ext, "mkv" ) )
+ {
+ output = mkv_output;
+ param->b_annexb = 0;
+ param->b_repeat_headers = 0;
+ }
+ else if( !strcasecmp( ext, "flv" ) )
+ {
+ output = flv_output;
+ param->b_annexb = 0;
+ param->b_repeat_headers = 0;
+ }
+ else
+ output = raw_output;
+ return 0;
+}
+
+static int select_input( const char *demuxer, char *used_demuxer, char *filename,
+ hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
+{
+ int b_auto = !strcasecmp( demuxer, "auto" );
+ const char *ext = b_auto ? get_filename_extension( filename ) : "";
+ int b_regular = strcmp( filename, "-" );
+ if( !b_regular && b_auto )
+ ext = "raw";
+ b_regular = b_regular && x264_is_regular_file_path( filename );
+ if( b_regular )
+ {
+ FILE *f = fopen( filename, "r" );
+ if( f )
+ {
+ b_regular = x264_is_regular_file( f );
+ fclose( f );
+ }
+ }
+ const char *module = b_auto ? ext : demuxer;
+
+ if( !strcasecmp( module, "avs" ) || !strcasecmp( ext, "d2v" ) || !strcasecmp( ext, "dga" ) )
+ {
+#if HAVE_AVS
+ input = avs_input;
+ module = "avs";
+#else
+ x264_cli_log( "x264", X264_LOG_ERROR, "not compiled with AVS input support\n" );
+ return -1;
+#endif
+ }
+ else if( !strcasecmp( module, "y4m" ) )
+ input = y4m_input;
+ else if( !strcasecmp( module, "raw" ) || !strcasecmp( ext, "yuv" ) )
+ input = raw_input;
+ else
+ {
+#if HAVE_FFMS
+ if( b_regular && (b_auto || !strcasecmp( demuxer, "ffms" )) &&
+ !ffms_input.open_file( filename, p_handle, info, opt ) )
+ {
+ module = "ffms";
+ b_auto = 0;
+ input = ffms_input;
+ }
+#endif
+#if HAVE_LAVF
+ if( (b_auto || !strcasecmp( demuxer, "lavf" )) &&
+ !lavf_input.open_file( filename, p_handle, info, opt ) )
+ {
+ module = "lavf";
+ b_auto = 0;
+ input = lavf_input;
+ }
+#endif
+#if HAVE_AVS
+ if( b_regular && (b_auto || !strcasecmp( demuxer, "avs" )) &&
+ !avs_input.open_file( filename, p_handle, info, opt ) )
+ {
+ module = "avs";
+ b_auto = 0;
+ input = avs_input;
+ }
+#endif
+ if( b_auto && !raw_input.open_file( filename, p_handle, info, opt ) )
+ {
+ module = "raw";
+ b_auto = 0;
+ input = raw_input;
+ }
+
+ FAIL_IF_ERROR( !(*p_handle), "could not open input file `%s' via any method!\n", filename )
+ }
+ strcpy( used_demuxer, module );
+
+ return 0;
+}
+
+static int init_vid_filters( char *sequence, hnd_t *handle, video_info_t *info, x264_param_t *param )
+{
+ x264_register_vid_filters();
+
+ /* intialize baseline filters */
+ if( x264_init_vid_filter( "source", handle, &filter, info, param, NULL ) ) /* wrap demuxer into a filter */
+ return -1;
+ if( x264_init_vid_filter( "resize", handle, &filter, info, param, "normcsp" ) ) /* normalize csps to be of a known/supported format */
+ return -1;
+ if( x264_init_vid_filter( "fix_vfr_pts", handle, &filter, info, param, NULL ) ) /* fix vfr pts */
+ return -1;
+
+ /* parse filter chain */
+ for( char *p = sequence; p && *p; )
+ {
+ int tok_len = strcspn( p, "/" );
+ int p_len = strlen( p );
+ p[tok_len] = 0;
+ int name_len = strcspn( p, ":" );
+ p[name_len] = 0;
+ name_len += name_len != tok_len;
+ if( x264_init_vid_filter( p, handle, &filter, info, param, p + name_len ) )
+ return -1;
+ p += X264_MIN( tok_len+1, p_len );
+ }
+
+ /* force end result resolution */
+ if( !param->i_width && !param->i_height )
+ {
+ param->i_height = info->height;
+ param->i_width = info->width;
+ }
+ /* if the current csp is supported by libx264, have libx264 use this csp.
+ * otherwise change the csp to I420 and have libx264 use this.
+ * when more colorspaces are supported, this decision will need to be updated. */
+ int csp = info->csp & X264_CSP_MASK;
+ if( csp > X264_CSP_NONE && csp < X264_CSP_MAX )
+ param->i_csp = info->csp;
+ else
+ param->i_csp = X264_CSP_I420 | ( info->csp & X264_CSP_HIGH_DEPTH );
+ if( x264_init_vid_filter( "resize", handle, &filter, info, param, NULL ) )
+ return -1;
+
+ char args[20];
+ sprintf( args, "bit_depth=%d", x264_bit_depth );
+
+ if( x264_init_vid_filter( "depth", handle, &filter, info, param, args ) )
+ return -1;
+
+ return 0;
+}
+
+static int parse_enum_name( const char *arg, const char * const *names, const char **dst )
+{
+ for( int i = 0; names[i]; i++ )
+ if( !strcasecmp( arg, names[i] ) )
+ {
+ *dst = names[i];
+ return 0;
+ }
+ return -1;
+}
+
+static int parse_enum_value( const char *arg, const char * const *names, int *dst )
+{
+ for( int i = 0; names[i]; i++ )
+ if( !strcasecmp( arg, names[i] ) )
+ {
+ *dst = i;
+ return 0;
+ }
+ return -1;
+}
+
+static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
+{
+ char *input_filename = NULL;
+ const char *demuxer = demuxer_names[0];
+ char *output_filename = NULL;
+ const char *muxer = muxer_names[0];
+ char *tcfile_name = NULL;
+ x264_param_t defaults;