Commit 133ee69d authored by Steven Walters's avatar Steven Walters Committed by Fiona Glaser

Fix issues relating to input/output files being pipes/FIFOs

parent 53a5772a
......@@ -63,6 +63,7 @@ do {\
/****************************************************************************
* Includes
****************************************************************************/
#include <sys/stat.h>
#include "osdep.h"
#include <stdarg.h>
#include <stddef.h>
......
......@@ -226,4 +226,12 @@ static int ALWAYS_INLINE x264_clz( uint32_t x )
#define x264_lower_thread_priority(p)
#endif
static inline uint8_t x264_is_regular_file( FILE *filehandle )
{
struct stat file_stat;
if( fstat( fileno( filehandle ), &file_stat ) )
return 0;
return S_ISREG( file_stat.st_mode );
}
#endif /* X264_OSDEP_H */
......@@ -920,13 +920,17 @@ x264_t *x264_encoder_open( x264_param_t *param )
{
/* create or truncate the reconstructed video file */
FILE *f = fopen( h->param.psz_dump_yuv, "w" );
if( f )
fclose( f );
else
if( !f )
{
x264_log( h, X264_LOG_ERROR, "dump_yuv: can't write to %s\n", h->param.psz_dump_yuv );
goto fail;
}
else if( !x264_is_regular_file( f ) )
{
x264_log( h, X264_LOG_ERROR, "dump_yuv: incompatible with non-regular file %s\n", h->param.psz_dump_yuv );
goto fail;
}
fclose( f );
}
x264_log( h, X264_LOG_INFO, "profile %s, level %d.%d\n",
......
......@@ -880,11 +880,13 @@ void x264_ratecontrol_delete( x264_t *h )
{
x264_ratecontrol_t *rc = h->rc;
int i;
int b_regular_file;
if( rc->p_stat_file_out )
{
b_regular_file = x264_is_regular_file( rc->p_stat_file_out );
fclose( rc->p_stat_file_out );
if( h->i_frame >= rc->num_entries )
if( h->i_frame >= rc->num_entries && b_regular_file )
if( rename( rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out ) != 0 )
{
x264_log( h, X264_LOG_ERROR, "failed to rename \"%s\" to \"%s\"\n",
......@@ -894,8 +896,9 @@ void x264_ratecontrol_delete( x264_t *h )
}
if( rc->p_mbtree_stat_file_out )
{
b_regular_file = x264_is_regular_file( rc->p_mbtree_stat_file_out );
fclose( rc->p_mbtree_stat_file_out );
if( h->i_frame >= rc->num_entries )
if( h->i_frame >= rc->num_entries && b_regular_file )
if( rename( rc->psz_mbtree_stat_file_tmpname, rc->psz_mbtree_stat_file_name ) != 0 )
{
x264_log( h, X264_LOG_ERROR, "failed to rename \"%s\" to \"%s\"\n",
......
......@@ -33,6 +33,16 @@ typedef struct
static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
{
FILE *fh = fopen( psz_filename, "r" );
if( !fh )
return -1;
else if( !x264_is_regular_file( fh ) )
{
fprintf( stderr, "avis [error]: AVIS input is incompatible with non-regular file `%s'\n", psz_filename );
return -1;
}
fclose( fh );
avis_hnd_t *h = malloc( sizeof(avis_hnd_t) );
if( !h )
return -1;
......
......@@ -160,10 +160,11 @@ static int get_frame_total( hnd_t handle )
{
y4m_hnd_t *h = handle;
int i_frame_total = 0;
uint64_t init_pos = ftell( h->fh );
if( !fseek( h->fh, 0, SEEK_END ) )
if( x264_is_regular_file( h->fh ) )
{
uint64_t init_pos = ftell( h->fh );
fseek( h->fh, 0, SEEK_END );
uint64_t i_size = ftell( h->fh );
fseek( h->fh, init_pos, SEEK_SET );
i_frame_total = (int)((i_size - h->seq_header_len) /
......@@ -173,20 +174,12 @@ static int get_frame_total( hnd_t handle )
return i_frame_total;
}
static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
static int read_frame_internal( x264_picture_t *p_pic, y4m_hnd_t *h )
{
y4m_hnd_t *h = handle;
int slen = strlen( Y4M_FRAME_MAGIC );
int i = 0;
char header[16];
if( i_frame != h->next_frame )
{
if( fseek( h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
+ h->seq_header_len, SEEK_SET ) )
return -1;
}
/* Read frame header - without terminating '\n' */
if( fread( header, 1, slen, h->fh ) != slen )
return -1;
......@@ -209,13 +202,36 @@ static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
}
h->frame_header_len = i+slen+1;
if( fread( p_pic->img.plane[0], 1, h->width*h->height, h->fh ) <= 0
|| fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
|| fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
if( fread( p_pic->img.plane[0], h->width * h->height, 1, h->fh ) <= 0
|| fread( p_pic->img.plane[1], h->width * h->height / 4, 1, h->fh ) <= 0
|| fread( p_pic->img.plane[2], h->width * h->height / 4, 1, h->fh ) <= 0 )
return -1;
h->next_frame = i_frame+1;
return 0;
}
static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
{
y4m_hnd_t *h = handle;
if( i_frame > h->next_frame )
{
if( x264_is_regular_file( h->fh ) )
fseek( h->fh, (uint64_t)i_frame*(3*(h->width*h->height)/2+h->frame_header_len)
+ h->seq_header_len, SEEK_SET );
else
while( i_frame > h->next_frame )
{
if( read_frame_internal( p_pic, h ) )
return -1;
h->next_frame++;
}
}
if( read_frame_internal( p_pic, h ) )
return -1;
h->next_frame = i_frame+1;
return 0;
}
......
......@@ -55,8 +55,9 @@ static int get_frame_total( hnd_t handle )
yuv_hnd_t *h = handle;
int i_frame_total = 0;
if( !fseek( h->fh, 0, SEEK_END ) )
if( x264_is_regular_file( h->fh ) )
{
fseek( h->fh, 0, SEEK_END );
uint64_t i_size = ftell( h->fh );
fseek( h->fh, 0, SEEK_SET );
i_frame_total = (int)(i_size / ( h->width * h->height * 3 / 2 ));
......@@ -65,21 +66,34 @@ static int get_frame_total( hnd_t handle )
return i_frame_total;
}
static int read_frame_internal( x264_picture_t *p_pic, yuv_hnd_t *h )
{
return fread( p_pic->img.plane[0], h->width * h->height, 1, h->fh ) <= 0
|| fread( p_pic->img.plane[1], h->width * h->height / 4, 1, h->fh ) <= 0
|| fread( p_pic->img.plane[2], h->width * h->height / 4, 1, h->fh ) <= 0;
}
static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
{
yuv_hnd_t *h = handle;
if( i_frame != h->next_frame )
if( fseek( h->fh, (uint64_t)i_frame * h->width * h->height * 3 / 2, SEEK_SET ) )
return -1;
if( i_frame > h->next_frame )
{
if( x264_is_regular_file( h->fh ) )
fseek( h->fh, (uint64_t)i_frame * h->width * h->height * 3 / 2, SEEK_SET );
else
while( i_frame > h->next_frame )
{
if( read_frame_internal( p_pic, h ) )
return -1;
h->next_frame++;
}
}
if( fread( p_pic->img.plane[0], 1, h->width * h->height, h->fh ) <= 0
|| fread( p_pic->img.plane[1], 1, h->width * h->height / 4, h->fh ) <= 0
|| fread( p_pic->img.plane[2], 1, h->width * h->height / 4, h->fh ) <= 0 )
if( read_frame_internal( p_pic, h ) )
return -1;
h->next_frame = i_frame+1;
return 0;
}
......
......@@ -18,9 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
*****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "common/osdep.h"
#include "muxers.h"
#include "matroska_ebml.h"
#define CLSIZE 1048576
......@@ -346,7 +344,10 @@ mk_writer *mk_create_writer( const char *filename )
return NULL;
}
w->fp = fopen( filename, "wb" );
if( !strcmp( filename, "-" ) )
w->fp = stdout;
else
w->fp = fopen( filename, "wb" );
if( !w->fp )
{
mk_destroy_contexts( w );
......@@ -545,7 +546,7 @@ int mk_close( mk_writer *w )
int ret = 0;
if( mk_flush_frame( w ) < 0 || mk_close_cluster( w ) < 0 )
ret = -1;
if( w->wrote_header )
if( w->wrote_header && x264_is_regular_file( w->fp ) )
{
fseek( w->fp, w->duration_ptr, SEEK_SET );
if( mk_write_float_raw( w->root, (float)((double)(w->max_frame_tc+w->def_duration) / w->timescale) ) < 0 ||
......
......@@ -126,6 +126,15 @@ static int open_file( char *psz_filename, hnd_t *p_handle )
mp4_hnd_t *p_mp4;
*p_handle = NULL;
FILE *fh = fopen( psz_filename, "w" );
if( !fh )
return -1;
else if( !x264_is_regular_file( fh ) )
{
fprintf( stderr, "mp4 [error]: MP4 output is incompatible with non-regular file `%s'\n", psz_filename );
return -1;
}
fclose( fh );
if( !(p_mp4 = malloc( sizeof(mp4_hnd_t) )) )
return -1;
......
......@@ -25,7 +25,9 @@
static int open_file( char *psz_filename, hnd_t *p_handle )
{
if( !(*p_handle = fopen( psz_filename, "w+b" )) )
if( !strcmp( psz_filename, "-" ) )
*p_handle = stdout;
else if( !(*p_handle = fopen( psz_filename, "w+b" )) )
return -1;
return 0;
......
......@@ -64,6 +64,10 @@ typedef struct {
cli_input_t input;
static cli_output_t output;
/* i/o modules that work with pipes (and fifos) */
static const char * const stdin_format_names[] = { "yuv", "y4m", 0 };
static const char * const stdout_format_names[] = { "raw", "mkv", 0 };
static void Help( x264_param_t *defaults, int longhelp );
static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt );
static int Encode( x264_param_t *param, cli_opt_t *opt );
......@@ -355,6 +359,10 @@ static void Help( x264_param_t *defaults, int longhelp )
H0( "Input/Output:\n" );
H0( "\n" );
H0( " -o, --output Specify output file\n" );
H1( " --stdout Specify stdout format [\"%s\"]\n"
" - raw, mkv\n", stdout_format_names[0] );
H1( " --stdin Specify stdin format [\"%s\"]\n"
" - yuv, y4m\n", stdin_format_names[0] );
H0( " --sar width:height Specify Sample Aspect Ratio\n" );
H0( " --fps <float|rational> Specify framerate\n" );
H0( " --seek <integer> First frame to encode\n" );
......@@ -393,6 +401,8 @@ static void Help( x264_param_t *defaults, int longhelp )
#define OPT_SLOWFIRSTPASS 267
#define OPT_FULLHELP 268
#define OPT_FPS 269
#define OPT_STDOUT_FORMAT 270
#define OPT_STDIN_FORMAT 271
static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw";
static struct option long_options[] =
......@@ -437,6 +447,8 @@ static struct option long_options[] =
{ "frames", required_argument, NULL, OPT_FRAMES },
{ "seek", required_argument, NULL, OPT_SEEK },
{ "output", required_argument, NULL, 'o' },
{ "stdout", required_argument, NULL, OPT_STDOUT_FORMAT },
{ "stdin", required_argument, NULL, OPT_STDIN_FORMAT },
{ "analyse", required_argument, NULL, 0 },
{ "partitions", required_argument, NULL, 'A' },
{ "direct", required_argument, NULL, 0 },
......@@ -519,31 +531,100 @@ static struct option long_options[] =
{0, 0, 0, 0}
};
static int select_output( char *filename, const char *pipe_format )
{
char *ext = filename + strlen( filename ) - 1;
while( *ext != '.' && ext > filename )
ext--;
if( !strcasecmp( ext, ".mp4" ) )
{
#ifdef MP4_OUTPUT
output = mp4_output;
#else
fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
return -1;
#endif
}
else if( !strcasecmp( ext, ".mkv" ) || (!strcmp( filename, "-" ) && !strcasecmp( pipe_format, "mkv" )) )
output = mkv_output;
else
output = raw_output;
return 0;
}
static int select_input( char *filename, char *resolution, const char *pipe_format, x264_param_t *param )
{
char *psz = filename + strlen( filename ) - 1;
while( psz > filename && *psz != '.' )
psz--;
if( !strcasecmp( psz, ".avi" ) || !strcasecmp( psz, ".avs" ) )
{
#ifdef AVIS_INPUT
input = avis_input;
#else
fprintf( stderr, "x264 [error]: not compiled with AVIS input support\n" );
return -1;
#endif
}
else if( !strcasecmp( psz, ".y4m" ) || (!strcmp( filename, "-" ) && !strcasecmp( pipe_format, "y4m" )) )
input = y4m_input;
else // yuv
{
if( !resolution )
{
/* try to parse the file name */
for( psz = filename; *psz; psz++ )
if( *psz >= '0' && *psz <= '9' &&
sscanf( psz, "%ux%u", &param->i_width, &param->i_height ) == 2 )
{
if( param->i_log_level >= X264_LOG_INFO )
fprintf( stderr, "x264 [info]: %dx%d (given by file name) @ %.2f fps\n", param->i_width,
param->i_height, (double)param->i_fps_num / param->i_fps_den );
break;
}
}
else
{
sscanf( resolution, "%ux%u", &param->i_width, &param->i_height );
if( param->i_log_level >= X264_LOG_INFO )
fprintf( stderr, "x264 [info]: %dx%d @ %.2f fps\n", param->i_width, param->i_height,
(double)param->i_fps_num / param->i_fps_den );
}
if( !param->i_width || !param->i_height )
{
fprintf( stderr, "x264 [error]: Rawyuv input requires a resolution.\n" );
return -1;
}
input = yuv_input;
}
return 0;
}
/*****************************************************************************
* Parse:
*****************************************************************************/
static int Parse( int argc, char **argv,
x264_param_t *param, cli_opt_t *opt )
{
char *psz_filename = NULL;
char *input_filename = NULL;
const char *stdin_format = stdin_format_names[0];
char *output_filename = NULL;
const char *stdout_format = stdout_format_names[0];
x264_param_t defaults = *param;
char *psz;
char *profile = NULL;
int b_avis = 0;
int b_y4m = 0;
int b_thread_input = 0;
int b_turbo = 1;
int b_pass1 = 0;
int b_user_ref = 0;
int b_user_fps = 0;
int i;
memset( opt, 0, sizeof(cli_opt_t) );
opt->b_progress = 1;
/* Default i/o modules */
input = yuv_input;
output = raw_output;
/* Presets are applied before all other options. */
for( optind = 0;; )
{
......@@ -773,24 +854,27 @@ static int Parse( int argc, char **argv,
opt->i_seek = atoi( optarg );
break;
case 'o':
if( !strncasecmp(optarg + strlen(optarg) - 4, ".mp4", 4) )
output_filename = optarg;
break;
case OPT_STDOUT_FORMAT:
for( i = 0; stdout_format_names[i] && strcasecmp( stdout_format_names[i], optarg ); )
i++;
if( !stdout_format_names[i] )
{
#ifdef MP4_OUTPUT
output = mp4_output;
#else
fprintf( stderr, "x264 [error]: not compiled with MP4 output support\n" );
fprintf( stderr, "x264 [error]: invalid stdout format `%s'\n", optarg );
return -1;
#endif
}
else if( !strncasecmp(optarg + strlen(optarg) - 4, ".mkv", 4) )
output = mkv_output;
if( !strcmp(optarg, "-") )
opt->hout = stdout;
else if( output.open_file( optarg, &opt->hout ) )
stdout_format = optarg;
break;
case OPT_STDIN_FORMAT:
for( i = 0; stdin_format_names[i] && strcasecmp( stdin_format_names[i], optarg ); )
i++;
if( !stdin_format_names[i] )
{
fprintf( stderr, "x264 [error]: can't open output file `%s'\n", optarg );
fprintf( stderr, "x264 [error]: invalid stdin format `%s'\n", optarg );
return -1;
}
stdin_format = optarg;
break;
case OPT_QPFILE:
opt->qpfile = fopen( optarg, "rb" );
......@@ -799,6 +883,12 @@ static int Parse( int argc, char **argv,
fprintf( stderr, "x264 [error]: can't open `%s'\n", optarg );
return -1;
}
else if( !x264_is_regular_file( opt->qpfile ) )
{
fprintf( stderr, "x264 [error]: qpfile incompatible with non-regular file `%s'\n", optarg );
fclose( opt->qpfile );
return -1;
}
break;
case OPT_THREAD_INPUT:
b_thread_input = 1;
......@@ -918,72 +1008,32 @@ generic_option:
}
/* Get the file name */
if( optind > argc - 1 || !opt->hout )
if( optind > argc - 1 || !output_filename )
{
fprintf( stderr, "x264 [error]: No %s file. Run x264 --help for a list of options.\n",
optind > argc - 1 ? "input" : "output" );
return -1;
}
psz_filename = argv[optind++];
/* check demuxer type */
psz = psz_filename + strlen(psz_filename) - 1;
while( psz > psz_filename && *psz != '.' )
psz--;
if( !strncasecmp( psz, ".avi", 4 ) || !strncasecmp( psz, ".avs", 4 ) )
b_avis = 1;
if( !strncasecmp( psz, ".y4m", 4 ) )
b_y4m = 1;
input_filename = argv[optind++];
if( !(b_avis || b_y4m) ) // raw yuv
if( select_output( output_filename, stdout_format ) )
return -1;
if( output.open_file( output_filename, &opt->hout ) )
{
if( optind > argc - 1 )
{
/* try to parse the file name */
for( psz = psz_filename; *psz; psz++ )
{
if( *psz >= '0' && *psz <= '9'
&& sscanf( psz, "%ux%u", &param->i_width, &param->i_height ) == 2 )
{
if( param->i_log_level >= X264_LOG_INFO )
fprintf( stderr, "x264 [info]: %dx%d (given by file name) @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den);
break;
}
}
}
else
{
sscanf( argv[optind++], "%ux%u", &param->i_width, &param->i_height );
if( param->i_log_level >= X264_LOG_INFO )
fprintf( stderr, "x264 [info]: %dx%d @ %.2f fps\n", param->i_width, param->i_height, (double)param->i_fps_num / (double)param->i_fps_den);
}
fprintf( stderr, "x264 [error]: could not open output file `%s'\n", output_filename );
return -1;
}
if( !(b_avis || b_y4m) && ( !param->i_width || !param->i_height ) )
{
fprintf( stderr, "x264 [error]: Rawyuv input requires a resolution.\n" );
if( select_input( input_filename, optind < argc ? argv[optind++] : NULL, stdin_format, param ) )
return -1;
}
/* open the input */
{
int i_fps_num = param->i_fps_num;
int i_fps_den = param->i_fps_den;
if( b_avis )
{
#ifdef AVIS_INPUT
input = avis_input;
#else
fprintf( stderr, "x264 [error]: not compiled with AVIS input support\n" );
return -1;
#endif
}
if( b_y4m )
input = y4m_input;
if( input.open_file( psz_filename, &opt->hin, param ) )
if( input.open_file( input_filename, &opt->hin, param ) )
{
fprintf( stderr, "x264 [error]: could not open input file '%s'\n", psz_filename );
fprintf( stderr, "x264 [error]: could not open input file `%s'\n", input_filename );
return -1;
}
/* Restore the user's frame rate if fps has been explicitly set on the commandline. */
......@@ -1044,7 +1094,7 @@ static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame )
{
pic->i_type = X264_TYPE_AUTO;
pic->i_qpplus1 = 0;
fseek( opt->qpfile , file_pos , SEEK_SET );
fseek( opt->qpfile, file_pos, SEEK_SET );
break;
}
if( num < i_frame && ret == 3 )
......@@ -1133,7 +1183,7 @@ static int Encode( x264_param_t *param, cli_opt_t *opt )
opt->b_progress &= param->i_log_level < X264_LOG_DEBUG;
i_frame_total = input.get_frame_total( opt->hin );
i_frame_total -= opt->i_seek;
i_frame_total = X264_MAX( i_frame_total - opt->i_seek, 0 );
if( ( i_frame_total == 0 || param->i_frame_total < i_frame_total )
&& param->i_frame_total > 0 )
i_frame_total = param->i_frame_total;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment