]> git.sesse.net Git - x264/commitdiff
Windows Unicode support
authorHenrik Gramner <henrik@gramner.com>
Sun, 11 Aug 2013 17:50:42 +0000 (19:50 +0200)
committerFiona Glaser <fiona@x264.com>
Fri, 23 Aug 2013 21:04:14 +0000 (14:04 -0700)
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.

22 files changed:
common/common.c
common/opencl.c
common/osdep.c
common/osdep.h
common/win32thread.c
common/win32thread.h
configure
encoder/encoder.c
encoder/ratecontrol.c
input/avs.c
input/ffms.c
input/raw.c
input/timecode.c
input/y4m.c
output/flv_bytestream.c
output/matroska_ebml.c
output/mp4.c
output/raw.c
x264.c
x264.h
x264cli.h
x264res.rc

index ba9f5d1c9f3c1e5a64589fc1fc25d060319fcef2..c736c95393a091fefc7be37f53cb9eb9e3f1dc42 100644 (file)
@@ -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;
index 974aff36fb2899f3ecb5866a84cdb2e925cf487f..5d0dce509d690c68a37dbf9313f2ac5fa9aab362 100644 (file)
@@ -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
index a1084d0fc5ce7c5a3a6bdf55d52195c6696e9c68..6952dd0a6e30e494b89d33bdf4f9cf07ac546659 100644 (file)
@@ -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
 
 #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
index cdc0f61be640c6b02dfc1f04d387d344cc698366..dba1eb071a5f62dcaf22ff5ecf9ffd0b0dcf9044 100644 (file)
@@ -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"
 
 #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
 #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 );
 }
index 4be914f19b7593c229c3ecadf468169e22157ef0..b446b76c1466bb1133c82a0ca4226cd8b9351d97 100644 (file)
@@ -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 )
     {
index 844b18abcbdfd4843c8c05d8c4be3b94f1afeecd..48494d510ea083e0f81e3de048bc95c4289b736e 100644 (file)
@@ -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
index 6f3ac025c63aea70fe3590c8394d7a0b97082da3..07796b1f661d7bc1f4348945a4a3640d00b970bc 100755 (executable)
--- a/configure
+++ b/configure
@@ -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
index 3b3bc638bebcf222da8713b882403f1adee5f198..52392269f4a3f946366df023df0678d7ada6b2ed 100644 (file)
@@ -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 );
index 00121847b22f8bdb45b0cb5f2862ca74abece71f..030d2ab81e676ec788d95bec2a7ca2f166b53826 100644 (file)
@@ -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 );
index d237a446fd81c2d9ec333ecad5587290b13e0a0d..6e8801c25a4fe6f532210ea2f6b8609e87a1eb0e 100644 (file)
@@ -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 );
 
index 1a0677805e108203873e4e6fe5aab092775310ea..054728b258026fc0bdf6ef0f92964b3e8ad7ef52 100644 (file)
@@ -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 );
index e853dd0a211c3e8254600995274fd5f44d383128..32134358c7eac00e0656225be8fd93220f3f255b 100644 (file)
@@ -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;
 
index a476e5d4622bd8d2eca48b5b54246a9e5c759f77..7653f837fb8a5606b5481cc3b8ce29d49135b558 100644 (file)
@@ -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 ) )
     {
index 014450cba1130aafa99817e38672676b8c63173e..da8f980384d87ace2fe689b4dfaa80e6623de21c 100644 (file)
@@ -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;
 
index 44c19238d55002644c9cbbf1cfbfb10b9fbda7dc..38a4ca9e967857c1ff45e3ccacb6fd538a16cb13 100644 (file)
@@ -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 );
index 2f41a2d15f43fef08f65c7241bbf5bf7bc45cf16..12c43d55fff22033bfd6053c0412382d1725032a 100644 (file)
@@ -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 );
index ee54e66f939e226b9686e8deeec20e2457487856..c6192a897511da5f839f684a718cbde3a32c6641 100644 (file)
@@ -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;
 
index d8ed3a98a821bf491e290637b635015b5faee1bc..4bfb7895919a5bc3953c3ba93170fe82e5b43546 100644 (file)
@@ -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;
diff --git a/x264.c b/x264.c
index e229604857d95a6a3510f0d54cc75127982e27d8..3415cd65b0d51e26040ee7a67daab966602e4171 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -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
  * 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>
 
 #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>
 #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 );
+#ifdef _WIN32
+    SetConsoleTitleW( org_console_title );
+    free( argv );
+#endif
 
     return ret;
 }
@@ -1096,7 +1185,7 @@ static int select_input( const char *demuxer, char *used_demuxer, char *filename
     b_regular = b_regular && x264_is_regular_file_path( filename );
     if( b_regular )
     {
-        FILE *f = fopen( filename, "r" );
+        FILE *f = x264_fopen( filename, "r" );
         if( f )
         {
             b_regular = x264_is_regular_file( f );
@@ -1340,7 +1429,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
                 input_opt.index_file = optarg;
                 break;
             case OPT_QPFILE:
-                opt->qpfile = fopen( optarg, "rb" );
+                opt->qpfile = x264_fopen( optarg, "rb" );
                 FAIL_IF_ERROR( !opt->qpfile, "can't open qpfile `%s'\n", optarg )
                 if( !x264_is_regular_file( opt->qpfile ) )
                 {
@@ -1399,7 +1488,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
                 tcfile_name = optarg;
                 break;
             case OPT_TCFILE_OUT:
-                opt->tcfile_out = fopen( optarg, "wb" );
+                opt->tcfile_out = x264_fopen( optarg, "wb" );
                 FAIL_IF_ERROR( !opt->tcfile_out, "can't open `%s'\n", optarg )
                 break;
             case OPT_TIMEBASE:
@@ -1723,11 +1812,9 @@ static int64_t print_status( int64_t i_start, int64_t i_previous, int i_frame, i
                  eta/3600, (eta/60)%60, eta%60 );
     }
     else
-    {
         sprintf( buf, "x264 %d frames: %.2f fps, %.2f kb/s", i_frame, fps, bitrate );
-    }
     fprintf( stderr, "%s  \r", buf+5 );
-    SetConsoleTitle( buf );
+    x264_cli_set_console_title( buf );
     fflush( stderr ); // needed in windows
     return i_time;
 }
diff --git a/x264.h b/x264.h
index f6611385976d49111d4a7fabe618508876eb3388..c3e2dba81e5f52689cd3319c7dcba9b03500f2f0 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -41,7 +41,7 @@
 
 #include "x264_config.h"
 
-#define X264_BUILD 137
+#define X264_BUILD 138
 
 /* Application developers planning to link against a shared library version of
  * libx264 from a Microsoft Visual Studio or similar development environment
@@ -334,7 +334,7 @@ typedef struct x264_param_t
     int         b_constrained_intra;
 
     int         i_cqm_preset;
-    char        *psz_cqm_file;      /* JM format */
+    char        *psz_cqm_file;      /* filename (in UTF-8) of CQM file, JM format */
     uint8_t     cqm_4iy[16];        /* used only if i_cqm_preset == X264_CQM_CUSTOM */
     uint8_t     cqm_4py[16];
     uint8_t     cqm_4ic[16];
@@ -350,7 +350,7 @@ typedef struct x264_param_t
     int         i_log_level;
     int         b_visualize;
     int         b_full_recon;   /* fully reconstruct frames, even when not necessary for encoding.  Implied by psz_dump_yuv */
-    char        *psz_dump_yuv;  /* filename for reconstructed frames */
+    char        *psz_dump_yuv;  /* filename (in UTF-8) for reconstructed frames */
 
     /* Encoder analyser parameters */
     struct
@@ -416,9 +416,9 @@ typedef struct x264_param_t
 
         /* 2pass */
         int         b_stat_write;   /* Enable stat writing in psz_stat_out */
-        char        *psz_stat_out;
+        char        *psz_stat_out;  /* output filename (in UTF-8) of the 2pass stats file */
         int         b_stat_read;    /* Read stat from psz_stat_in and use it */
-        char        *psz_stat_in;
+        char        *psz_stat_in;   /* input filename (in UTF-8) of the 2pass stats file */
 
         /* 2pass params (same as ffmpeg ones) */
         float       f_qcompress;    /* 0.0 => cbr, 1.0 => constant qp */
@@ -486,7 +486,7 @@ typedef struct x264_param_t
     int b_opencl;            /* use OpenCL when available */
     int i_opencl_device;     /* specify count of GPU devices to skip, for CLI users */
     void *opencl_device_id;  /* pass explicit cl_device_id as void*, for API users */
-    char *psz_clbin_file;    /* compiled OpenCL kernel cache file */
+    char *psz_clbin_file;    /* filename (in UTF-8) of the compiled OpenCL kernel cache file */
 
     /* Slicing parameters */
     int i_slice_max_size;    /* Max size per slice in bytes; includes estimated NAL overhead. */
index 7437602519ca6093208ec29a21983b863d29574c..1794992a7271e4bfcaa430638ea6d5cf409e4187 100644 (file)
--- a/x264cli.h
+++ b/x264cli.h
@@ -63,6 +63,13 @@ static inline char *get_filename_extension( char *filename )
 void x264_cli_log( const char *name, int i_level, const char *fmt, ... );
 void x264_cli_printf( int i_level, const char *fmt, ... );
 
+#ifdef _WIN32
+void x264_cli_set_console_title( const char *title );
+int x264_ansi_filename( const char *filename, char *ansi_filename, int size, int create_file );
+#else
+#define x264_cli_set_console_title( title )
+#endif
+
 #define RETURN_IF_ERR( cond, name, ret, ... )\
 if( cond )\
 {\
index 73c82ef94e4ca5de14f99adb306100b1f34dd77d..d25c810897caa8ec3d5e650719b2c6b0a7367b40 100644 (file)
@@ -3,7 +3,7 @@
  *****************************************************************************
  * Copyright (C) 2012-2013 x264 project
  *
- * Authors: Henrik Gramner <hengar-6@student.ltu.se>
+ * Authors: 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
@@ -50,7 +50,7 @@ FILESUBTYPE     VFT2_UNKNOWN
 BEGIN
     BLOCK "StringFileInfo"
     BEGIN
-        BLOCK "040904E4"
+        BLOCK "040904B0"
         BEGIN
             VALUE "CompanyName",      "x264 project"
 #ifdef DLL
@@ -73,6 +73,6 @@ BEGIN
 
     BLOCK "VarFileInfo"
     BEGIN
-        VALUE "Translation", 0x0409, 0x04E4
+        VALUE "Translation", 0x0409, 0x04B0 /* U.S. English (Unicode) */
     END
 END