Commit fa3cac51 authored by Henrik Gramner's avatar Henrik Gramner Committed by Fiona Glaser

Windows Unicode support

Windows, unlike most other operating systems, uses UTF-16 for Unicode strings while x264 is designed for UTF-8.

This patch does the following in order to handle things like Unicode filenames:
* Keep strings internally as UTF-8.
* Retrieve the CLI command line as UTF-16 and convert it to UTF-8.
* Always use Unicode versions of Windows API functions and convert strings to UTF-16 when calling them.
* Attempt to use legacy 8.3 short filenames for external libraries without Unicode support.
parent 9b94896b
......@@ -1104,7 +1104,7 @@ static void x264_log_default( void *p_unused, int i_level, const char *psz_fmt,
break;
}
fprintf( stderr, "x264 [%s]: ", psz_prefix );
vfprintf( stderr, psz_fmt, arg );
x264_vfprintf( stderr, psz_fmt, arg );
}
/****************************************************************************
......@@ -1269,7 +1269,7 @@ char *x264_slurp_file( const char *filename )
int b_error = 0;
size_t i_size;
char *buf;
FILE *fh = fopen( filename, "rb" );
FILE *fh = x264_fopen( filename, "rb" );
if( !fh )
return NULL;
b_error |= fseek( fh, 0, SEEK_END ) < 0;
......
......@@ -28,7 +28,7 @@
#ifdef _WIN32
#include <windows.h>
#define ocl_open LoadLibrary( "OpenCL" )
#define ocl_open LoadLibraryW( L"OpenCL" )
#define ocl_close FreeLibrary
#define ocl_address GetProcAddress
#else
......@@ -122,7 +122,7 @@ static int x264_detect_switchable_graphics( void );
static cl_program x264_opencl_cache_load( x264_t *h, const char *dev_name, const char *dev_vendor, const char *driver_version )
{
/* try to load cached program binary */
FILE *fp = fopen( h->param.psz_clbin_file, "rb" );
FILE *fp = x264_fopen( h->param.psz_clbin_file, "rb" );
if( !fp )
return NULL;
......@@ -169,7 +169,7 @@ fail:
* is also saved in the cache file so we do not reuse stale binaries */
static void x264_opencl_cache_save( x264_t *h, cl_program program, const char *dev_name, const char *dev_vendor, const char *driver_version )
{
FILE *fp = fopen( h->param.psz_clbin_file, "wb" );
FILE *fp = x264_fopen( h->param.psz_clbin_file, "wb" );
if( !fp )
{
x264_log( h, X264_LOG_INFO, "OpenCL: unable to open clbin file for write\n" );
......@@ -304,7 +304,7 @@ static cl_program x264_opencl_compile( x264_t *h )
goto fail;
}
FILE *log_file = fopen( "x264_kernel_build_log.txt", "w" );
FILE *log_file = x264_fopen( "x264_kernel_build_log.txt", "w" );
if( !log_file )
{
x264_log( h, X264_LOG_WARNING, "OpenCL: Compilation failed, unable to create file x264_kernel_build_log.txt\n" );
......@@ -672,9 +672,9 @@ static int x264_detect_switchable_graphics( void )
int ret = 0;
#ifdef _WIN32
hDLL = LoadLibrary( "atiadlxx.dll" );
hDLL = LoadLibraryW( L"atiadlxx.dll" );
if( !hDLL )
hDLL = LoadLibrary( "atiadlxy.dll" );
hDLL = LoadLibraryW( L"atiadlxy.dll" );
#else
hDLL = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL );
#endif
......
......@@ -5,6 +5,7 @@
*
* Authors: Steven Walters <kemuri9@gmail.com>
* Laurent Aimar <fenrir@via.ecp.fr>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -26,6 +27,11 @@
#include "common.h"
#ifdef _WIN32
#include <windows.h>
#include <io.h>
#endif
#if SYS_WINDOWS
#include <sys/types.h>
#include <sys/timeb.h>
......@@ -35,8 +41,6 @@
#include <time.h>
#if PTW32_STATIC_LIB
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* this is a global in pthread-win32 to indicate if it has been initialized or not */
extern int ptw32_processInitialized;
#endif
......@@ -134,3 +138,64 @@ void x264_intel_cpu_indicator_init( void )
{}
#endif
#endif
#ifdef _WIN32
/* Functions for dealing with Unicode on Windows. */
FILE *x264_fopen( const char *filename, const char *mode )
{
wchar_t filename_utf16[MAX_PATH];
wchar_t mode_utf16[16];
if( utf8_to_utf16( filename, filename_utf16 ) && utf8_to_utf16( mode, mode_utf16 ) )
return _wfopen( filename_utf16, mode_utf16 );
return NULL;
}
int x264_rename( const char *oldname, const char *newname )
{
wchar_t oldname_utf16[MAX_PATH];
wchar_t newname_utf16[MAX_PATH];
if( utf8_to_utf16( oldname, oldname_utf16 ) && utf8_to_utf16( newname, newname_utf16 ) )
{
/* POSIX says that rename() removes the destination, but Win32 doesn't. */
_wunlink( newname_utf16 );
return _wrename( oldname_utf16, newname_utf16 );
}
return -1;
}
int x264_stat( const char *path, x264_struct_stat *buf )
{
wchar_t path_utf16[MAX_PATH];
if( utf8_to_utf16( path, path_utf16 ) )
return _wstati64( path_utf16, buf );
return -1;
}
int x264_vfprintf( FILE *stream, const char *format, va_list arg )
{
HANDLE console = NULL;
DWORD mode;
if( stream == stdout )
console = GetStdHandle( STD_OUTPUT_HANDLE );
else if( stream == stderr )
console = GetStdHandle( STD_ERROR_HANDLE );
/* Only attempt to convert to UTF-16 when writing to a non-redirected console screen buffer. */
if( GetConsoleMode( console, &mode ) )
{
char buf[4096];
wchar_t buf_utf16[4096];
int length = vsnprintf( buf, sizeof(buf), format, arg );
if( length > 0 && length < sizeof(buf) )
{
/* WriteConsoleW is the most reliable way to output Unicode to a console. */
int length_utf16 = MultiByteToWideChar( CP_UTF8, 0, buf, length, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t) );
WriteConsoleW( console, buf_utf16, length_utf16, NULL, NULL );
return length;
}
}
return vfprintf( stream, format, arg );
}
#endif
......@@ -5,6 +5,7 @@
*
* Authors: Loren Merritt <lorenm@u.washington.edu>
* Laurent Aimar <fenrir@via.ecp.fr>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -32,6 +33,7 @@
#include <stdio.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <stdarg.h>
#include "config.h"
......@@ -40,11 +42,6 @@
#define log2(x) (log(x)/0.693147180559945)
#endif
#ifdef _WIN32
#include <io.h> // _setmode()
#include <fcntl.h> // _O_BINARY
#endif
#ifdef __ICL
#define inline __inline
#define strcasecmp _stricmp
......@@ -67,11 +64,27 @@
#if !defined(isfinite) && (SYS_OPENBSD || SYS_SunOS)
#define isfinite finite
#endif
#ifdef _WIN32
#define rename(src,dst) (unlink(dst), rename(src,dst)) // POSIX says that rename() removes the destination, but win32 doesn't.
#ifndef strtok_r
#define strtok_r(str,delim,save) strtok(str,delim)
#endif
#define utf8_to_utf16( utf8, utf16 )\
MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8, -1, utf16, sizeof(utf16)/sizeof(wchar_t) )
FILE *x264_fopen( const char *filename, const char *mode );
int x264_rename( const char *oldname, const char *newname );
#define x264_struct_stat struct _stati64
#define x264_fstat _fstati64
int x264_stat( const char *path, x264_struct_stat *buf );
int x264_vfprintf( FILE *stream, const char *format, va_list arg );
#else
#define x264_fopen fopen
#define x264_rename rename
#define x264_struct_stat struct stat
#define x264_fstat fstat
#define x264_stat stat
#define x264_vfprintf vfprintf
#endif
#ifdef __ICL
......@@ -366,16 +379,16 @@ static ALWAYS_INLINE void x264_prefetch( void *p )
static inline uint8_t x264_is_regular_file( FILE *filehandle )
{
struct stat file_stat;
if( fstat( fileno( filehandle ), &file_stat ) )
x264_struct_stat file_stat;
if( x264_fstat( fileno( filehandle ), &file_stat ) )
return -1;
return S_ISREG( file_stat.st_mode );
}
static inline uint8_t x264_is_regular_file_path( const char *filename )
{
struct stat file_stat;
if( stat( filename, &file_stat ) )
x264_struct_stat file_stat;
if( x264_stat( filename, &file_stat ) )
return -1;
return S_ISREG( file_stat.st_mode );
}
......
......@@ -261,7 +261,7 @@ int x264_pthread_cond_wait( x264_pthread_cond_t *cond, x264_pthread_mutex_t *mut
int x264_win32_threading_init( void )
{
/* find function pointers to API functions, if they exist */
HANDLE kernel_dll = GetModuleHandle( TEXT( "kernel32.dll" ) );
HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" );
thread_control.cond_init = (void*)GetProcAddress( kernel_dll, "InitializeConditionVariable" );
if( thread_control.cond_init )
{
......@@ -288,7 +288,7 @@ int x264_pthread_num_processors_np( void )
* On platforms that support processor grouping, use GetThreadGroupAffinity to get the current thread's affinity instead. */
#if ARCH_X86_64
/* find function pointers to API functions specific to x86_64 platforms, if they exist */
HANDLE kernel_dll = GetModuleHandle( TEXT( "kernel32.dll" ) );
HANDLE kernel_dll = GetModuleHandleW( L"kernel32.dll" );
BOOL (*get_thread_affinity)( HANDLE thread, x264_group_affinity_t *group_affinity ) = (void*)GetProcAddress( kernel_dll, "GetThreadGroupAffinity" );
if( get_thread_affinity )
{
......
......@@ -26,7 +26,6 @@
#ifndef X264_WIN32THREAD_H
#define X264_WIN32THREAD_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* the following macro is used within x264 */
#undef ERROR
......
......@@ -510,6 +510,7 @@ case $host_os in
else
SYS="WINDOWS"
DEVNULL="NUL"
LDFLAGSCLI="$LDFLAGSCLI -lshell32"
RC="${RC-${cross_prefix}windres}"
fi
;;
......@@ -517,6 +518,7 @@ case $host_os in
SYS="WINDOWS"
EXE=".exe"
DEVNULL="NUL"
LDFLAGSCLI="$LDFLAGSCLI -lshell32"
[ $compiler = ICL ] && RC="${RC-rc}" || RC="${RC-${cross_prefix}windres}"
;;
sunos*|solaris*)
......@@ -945,7 +947,7 @@ fi
if [ "$avs" = "auto" ] ; then
avs="no"
# cygwin can use avisynth if it can use LoadLibrary
if [ $SYS = WINDOWS ] || ([ $SYS = CYGWIN ] && cc_check windows.h "" "LoadLibrary(0);") ; then
if [ $SYS = WINDOWS ] || ([ $SYS = CYGWIN ] && cc_check windows.h "" "LoadLibraryW(0);") ; then
avs="avisynth"
define HAVE_AVS
define USE_AVXSYNTH 0
......@@ -1043,7 +1045,7 @@ if [ "$opencl" = "yes" ]; then
fi
log_ok
# cygwin can use opencl if it can use LoadLibrary
if [ $SYS = WINDOWS ] || ([ $SYS = CYGWIN ] && cc_check windows.h "" "LoadLibrary(0);") ; then
if [ $SYS = WINDOWS ] || ([ $SYS = CYGWIN ] && cc_check windows.h "" "LoadLibraryW(0);") ; then
opencl="yes"
define HAVE_OPENCL
elif [ "$SYS" = "LINUX" -o "$SYS" = "MACOSX" ] ; then
......
......@@ -82,7 +82,7 @@ static int x264_threadpool_wait_all( x264_t *h )
static void x264_frame_dump( x264_t *h )
{
FILE *f = fopen( h->param.psz_dump_yuv, "r+b" );
FILE *f = x264_fopen( h->param.psz_dump_yuv, "r+b" );
if( !f )
return;
......@@ -1623,7 +1623,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
if( h->param.psz_dump_yuv )
{
/* create or truncate the reconstructed video file */
FILE *f = fopen( h->param.psz_dump_yuv, "w" );
FILE *f = x264_fopen( h->param.psz_dump_yuv, "w" );
if( !f )
{
x264_log( h, X264_LOG_ERROR, "dump_yuv: can't write to %s\n", h->param.psz_dump_yuv );
......
......@@ -872,7 +872,7 @@ int x264_ratecontrol_new( x264_t *h )
char *mbtree_stats_in = x264_strcat_filename( h->param.rc.psz_stat_in, ".mbtree" );
if( !mbtree_stats_in )
return -1;
rc->p_mbtree_stat_file_in = fopen( mbtree_stats_in, "rb" );
rc->p_mbtree_stat_file_in = x264_fopen( mbtree_stats_in, "rb" );
x264_free( mbtree_stats_in );
if( !rc->p_mbtree_stat_file_in )
{
......@@ -1140,7 +1140,7 @@ parse_error:
if( !rc->psz_stat_file_tmpname )
return -1;
rc->p_stat_file_out = fopen( rc->psz_stat_file_tmpname, "wb" );
rc->p_stat_file_out = x264_fopen( rc->psz_stat_file_tmpname, "wb" );
if( rc->p_stat_file_out == NULL )
{
x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n" );
......@@ -1158,7 +1158,7 @@ parse_error:
if( !rc->psz_mbtree_stat_file_tmpname || !rc->psz_mbtree_stat_file_name )
return -1;
rc->p_mbtree_stat_file_out = fopen( rc->psz_mbtree_stat_file_tmpname, "wb" );
rc->p_mbtree_stat_file_out = x264_fopen( rc->psz_mbtree_stat_file_tmpname, "wb" );
if( rc->p_mbtree_stat_file_out == NULL )
{
x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open mbtree stats file\n" );
......@@ -1338,7 +1338,7 @@ void x264_ratecontrol_delete( x264_t *h )
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 && b_regular_file )
if( rename( rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out ) != 0 )
if( x264_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",
rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out );
......@@ -1350,7 +1350,7 @@ void x264_ratecontrol_delete( x264_t *h )
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 && b_regular_file )
if( rename( rc->psz_mbtree_stat_file_tmpname, rc->psz_mbtree_stat_file_name ) != 0 )
if( x264_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",
rc->psz_mbtree_stat_file_tmpname, rc->psz_mbtree_stat_file_name );
......
......@@ -35,7 +35,7 @@
#define avs_address dlsym
#else
#include <windows.h>
#define avs_open LoadLibrary( "avisynth" )
#define avs_open LoadLibraryW( L"avisynth" )
#define avs_close FreeLibrary
#define avs_address GetProcAddress
#endif
......@@ -172,7 +172,7 @@ static float get_avs_version( avs_hnd_t *h )
static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
{
FILE *fh = fopen( psz_filename, "r" );
FILE *fh = x264_fopen( psz_filename, "r" );
if( !fh )
return -1;
FAIL_IF_ERROR( !x264_is_regular_file( fh ), "AVS input is incompatible with non-regular file `%s'\n", psz_filename );
......@@ -192,7 +192,16 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
if( avs_version <= 0 )
return -1;
x264_cli_log( "avs", X264_LOG_DEBUG, "using avisynth version %.2f\n", avs_version );
#ifdef _WIN32
/* Avisynth doesn't support Unicode filenames. */
char ansi_filename[MAX_PATH];
FAIL_IF_ERROR( !x264_ansi_filename( psz_filename, ansi_filename, MAX_PATH, 0 ), "invalid ansi filename\n" );
AVS_Value arg = avs_new_value_string( ansi_filename );
#else
AVS_Value arg = avs_new_value_string( psz_filename );
#endif
AVS_Value res;
char *filename_ext = get_filename_extension( psz_filename );
......
......@@ -5,6 +5,7 @@
*
* Authors: Mike Gurlitz <mike.gurlitz@gmail.com>
* Steven Walters <kemuri9@gmail.com>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -34,8 +35,6 @@
#ifdef _WIN32
#include <windows.h>
#else
#define SetConsoleTitle(t)
#endif
typedef struct
......@@ -60,7 +59,7 @@ static int FFMS_CC update_progress( int64_t current, int64_t total, void *privat
char buf[200];
sprintf( buf, "ffms [info]: indexing input file [%.1f%%]", 100.0 * current / total );
fprintf( stderr, "%s \r", buf+5 );
SetConsoleTitle( buf );
x264_cli_set_console_title( buf );
fflush( stderr );
return 0;
}
......@@ -82,7 +81,21 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
ffms_hnd_t *h = calloc( 1, sizeof(ffms_hnd_t) );
if( !h )
return -1;
#ifdef __MINGW32__
/* FFMS supports UTF-8 filenames, but it uses std::fstream internally which is broken with Unicode in MinGW. */
FFMS_Init( 0, 0 );
char src_filename[MAX_PATH];
char idx_filename[MAX_PATH];
FAIL_IF_ERROR( !x264_ansi_filename( psz_filename, src_filename, MAX_PATH, 0 ), "invalid ansi filename\n" );
if( opt->index_file )
FAIL_IF_ERROR( !x264_ansi_filename( opt->index_file, idx_filename, MAX_PATH, 1 ), "invalid ansi filename\n" );
#else
FFMS_Init( 0, 1 );
char *src_filename = psz_filename;
char *idx_filename = opt->index_file;
#endif
FFMS_ErrorInfo e;
e.BufferSize = 0;
int seekmode = opt->seek ? FFMS_SEEK_NORMAL : FFMS_SEEK_LINEAR_NO_RW;
......@@ -90,29 +103,29 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
FFMS_Index *idx = NULL;
if( opt->index_file )
{
struct stat index_s, input_s;
if( !stat( opt->index_file, &index_s ) && !stat( psz_filename, &input_s ) &&
x264_struct_stat index_s, input_s;
if( !x264_stat( opt->index_file, &index_s ) && !x264_stat( psz_filename, &input_s ) &&
input_s.st_mtime < index_s.st_mtime )
idx = FFMS_ReadIndex( opt->index_file, &e );
idx = FFMS_ReadIndex( idx_filename, &e );
}
if( !idx )
{
if( opt->progress )
{
idx = FFMS_MakeIndex( psz_filename, 0, 0, NULL, NULL, 0, update_progress, &h->time, &e );
idx = FFMS_MakeIndex( src_filename, 0, 0, NULL, NULL, 0, update_progress, &h->time, &e );
fprintf( stderr, " \r" );
}
else
idx = FFMS_MakeIndex( psz_filename, 0, 0, NULL, NULL, 0, NULL, NULL, &e );
idx = FFMS_MakeIndex( src_filename, 0, 0, NULL, NULL, 0, NULL, NULL, &e );
FAIL_IF_ERROR( !idx, "could not create index\n" )
if( opt->index_file && FFMS_WriteIndex( opt->index_file, idx, &e ) )
if( opt->index_file && FFMS_WriteIndex( idx_filename, idx, &e ) )
x264_cli_log( "ffms", X264_LOG_WARNING, "could not write index file\n" );
}
int trackno = FFMS_GetFirstTrackOfType( idx, FFMS_TYPE_VIDEO, &e );
FAIL_IF_ERROR( trackno < 0, "could not find video track\n" )
h->video_source = FFMS_CreateVideoSource( psz_filename, trackno, idx, 1, seekmode, &e );
h->video_source = FFMS_CreateVideoSource( src_filename, trackno, idx, 1, seekmode, &e );
FAIL_IF_ERROR( !h->video_source, "could not create video source\n" )
h->track = FFMS_GetTrackFromVideo( h->video_source );
......
......@@ -70,7 +70,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
if( !strcmp( psz_filename, "-" ) )
h->fh = stdin;
else
h->fh = fopen( psz_filename, "rb" );
h->fh = x264_fopen( psz_filename, "rb" );
if( h->fh == NULL )
return -1;
......
......@@ -368,7 +368,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
timecode_input.picture_alloc = h->input.picture_alloc;
timecode_input.picture_clean = h->input.picture_clean;
tcfile_in = fopen( psz_filename, "rb" );
tcfile_in = x264_fopen( psz_filename, "rb" );
FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename )
else if( !x264_is_regular_file( tcfile_in ) )
{
......
......@@ -81,7 +81,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
if( !strcmp( psz_filename, "-" ) )
h->fh = stdin;
else
h->fh = fopen(psz_filename, "rb");
h->fh = x264_fopen(psz_filename, "rb");
if( h->fh == NULL )
return -1;
......
......@@ -96,7 +96,7 @@ flv_buffer *flv_create_writer( const char *filename )
if( !strcmp( filename, "-" ) )
c->fp = stdout;
else
c->fp = fopen( filename, "wb" );
c->fp = x264_fopen( filename, "wb" );
if( !c->fp )
{
free( c );
......
......@@ -307,7 +307,7 @@ mk_writer *mk_create_writer( const char *filename )
if( !strcmp( filename, "-" ) )
w->fp = stdout;
else
w->fp = fopen( filename, "wb" );
w->fp = x264_fopen( filename, "wb" );
if( !w->fp )
{
mk_destroy_contexts( w );
......
......@@ -173,7 +173,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt
mp4_hnd_t *p_mp4;
*p_handle = NULL;
FILE *fh = fopen( psz_filename, "w" );
FILE *fh = x264_fopen( psz_filename, "w" );
if( !fh )
return -1;
FAIL_IF_ERR( !x264_is_regular_file( fh ), "mp4", "MP4 output is incompatible with non-regular file `%s'\n", psz_filename )
......@@ -183,7 +183,15 @@ static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt
return -1;
memset( p_mp4, 0, sizeof(mp4_hnd_t) );
#ifdef _WIN32
/* GPAC doesn't support Unicode filenames. */
char ansi_filename[MAX_PATH];
FAIL_IF_ERR( !x264_ansi_filename( psz_filename, ansi_filename, MAX_PATH, 1 ), "mp4", "invalid ansi filename\n" )
p_mp4->p_file = gf_isom_open( ansi_filename, GF_ISOM_OPEN_WRITE, NULL );
#else
p_mp4->p_file = gf_isom_open( psz_filename, GF_ISOM_OPEN_WRITE, NULL );
#endif
p_mp4->b_dts_compress = opt->use_dts_compress;
......
......@@ -30,7 +30,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt
{
if( !strcmp( psz_filename, "-" ) )
*p_handle = stdout;
else if( !(*p_handle = fopen( psz_filename, "w+b" )) )
else if( !(*p_handle = x264_fopen( psz_filename, "w+b" )) )
return -1;
return 0;
......
......@@ -8,6 +8,7 @@
* Steven Walters <kemuri9@gmail.com>
* Fiona Glaser <fiona@x264.com>
* Kieran Kunhya <kieran@kunhya.com>
* Henrik Gramner <henrik@gramner.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -27,6 +28,15 @@
* For more information, contact us at licensing@x264.com.
*****************************************************************************/
#ifdef _WIN32
/* The following two defines must be located before the inclusion of any system header files. */
#define WINVER 0x0500
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <io.h> /* _setmode() */
#include <fcntl.h> /* _O_BINARY */
#endif
#include <signal.h>
#define _GNU_SOURCE
#include <getopt.h>
......@@ -38,13 +48,6 @@
#define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "x264", __VA_ARGS__ )
#ifdef _WIN32
#include <windows.h>
#else
#define GetConsoleTitle(t,n)
#define SetConsoleTitle(t)
#endif
#if HAVE_LAVF
#undef DECLARE_ALIGNED
#include <libavformat/avformat.h>
......@@ -61,18 +64,97 @@
#include <ffms.h>
#endif
#ifdef _WIN32
#define CONSOLE_TITLE_SIZE 200
static wchar_t org_console_title[CONSOLE_TITLE_SIZE] = L"";
void x264_cli_set_console_title( const char *title )
{
wchar_t title_utf16[CONSOLE_TITLE_SIZE];
if( utf8_to_utf16( title, title_utf16 ) )
SetConsoleTitleW( title_utf16 );
}
static int utf16_to_ansi( const wchar_t *utf16, char *ansi, int size )
{
int invalid;
return WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, utf16, -1, ansi, size, NULL, &invalid ) && !invalid;
}
/* Some external libraries doesn't support Unicode in filenames,
* as a workaround we can try to get an ANSI filename instead. */
int x264_ansi_filename( const char *filename, char *ansi_filename, int size, int create_file )
{
wchar_t filename_utf16[MAX_PATH];
if( utf8_to_utf16( filename, filename_utf16 ) )
{
if( create_file )
{
/* Create the file using the Unicode filename if it doesn't already exist. */
FILE *fh = _wfopen( filename_utf16, L"ab" );
if( fh )
fclose( fh );
}
/* Check if the filename already is valid ANSI. */
if( utf16_to_ansi( filename_utf16, ansi_filename, size ) )
return 1;
/* Check for a legacy 8.3 short filename. */
int short_length = GetShortPathNameW( filename_utf16, filename_utf16, MAX_PATH );
if( short_length > 0 && short_length < MAX_PATH )
if( utf16_to_ansi( filename_utf16, ansi_filename, size ) )
return 1;
}
return 0;
}
/* Retrieve command line arguments as UTF-8. */
static int get_argv_utf8( int *argc_ptr, char ***argv_ptr )
{
int ret = 0;
wchar_t **argv_utf16 = CommandLineToArgvW( GetCommandLineW(), argc_ptr );
if( argv_utf16 )
{
int argc = *argc_ptr;
int offset = (argc+1) * sizeof(char*);
int size = offset;
for( int i = 0; i < argc; i++ )
size += WideCharToMultiByte( CP_UTF8, 0, argv_utf16[i], -1, NULL, 0, NULL, NULL );
char **argv = *argv_ptr = malloc( size );
if( argv )
{
for( int i = 0; i < argc; i++ )
{
argv[i] = (char*)argv + offset;
offset += WideCharToMultiByte( CP_UTF8, 0, argv_utf16[i], -1, argv[i], size-offset, NULL, NULL );
}
argv[argc] = NULL;
ret = 1;
}
LocalFree( argv_utf16 );
}
return ret;
}
#endif
/* Ctrl-C handler */
static volatile int b_ctrl_c = 0;
static int b_exit_on_ctrl_c = 0;
static void sigint_handler( int a )
{
if( b_exit_on_ctrl_c )
exit(0);
{
#ifdef _WIN32
SetConsoleTitleW( org_console_title );
#endif
exit( 0 );
}
b_ctrl_c = 1;
}
static char UNUSED originalCTitle[200] = "";
typedef struct {
int b_progress;
int i_seek;
......@@ -211,7 +293,7 @@ void x264_cli_log( const char *name, int i_level, const char *fmt, ... )
fprintf( stderr, "%s [%s]: ", name, s_level );
va_list arg;
va_start( arg, fmt );
vfprintf( stderr, fmt, arg );
x264_vfprintf( stderr, fmt, arg );
va_end( arg );
}
......@@ -221,7 +303,7 @@ void x264_cli_printf( int i_level, const char *fmt, ... )
return;
va_list arg;
va_start( arg, fmt );
vfprintf( stderr, fmt, arg );
x264_vfprintf( stderr, fmt, arg );
va_end( arg );
}
......@@ -275,18 +357,22 @@ int main( int argc, char **argv )
FAIL_IF_ERROR( x264_threading_init(), "unable to initialize threading\n" )
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
#endif
FAIL_IF_ERROR( !get_argv_utf8( &argc, &argv ), "unable to convert command line to UTF-8\n" )
GetConsoleTitle( originalCTitle, sizeof(originalCTitle) );
GetConsoleTitleW( org_console_title, CONSOLE_TITLE_SIZE );
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
_setmode( _fileno( stderr ), _O_BINARY );
#endif
/* Parse command line */
if( parse( argc, argv, &param, &opt ) < 0 )
ret = -1;
#ifdef _WIN32
/* Restore title; it can be changed by input modules */
SetConsoleTitle( originalCTitle );
SetConsoleTitleW( org_console_title );
#endif
/* Control-C handler */
signal( SIGINT, sigint_handler );
......@@ -306,7 +392,10 @@ int main( int argc, char **argv )
if( opt.qpfile )
fclose( opt.qpfile );
SetConsoleTitle( originalCTitle );</