[x265] Allows for Unicode filenames in Windows (output and stat files).

Mateusz mateuszb at poczta.onet.pl
Thu Apr 28 10:15:35 CEST 2016


Due to problem with breaking lines I sent this patch as attachment.
-------------- next part --------------
# HG changeset patch
# User Ma0 <mateuszb at poczta.onet.pl>
# Date 1461830370 -7200
#      Thu Apr 28 09:59:30 2016 +0200
# Node ID 705b7ba5bad5da71f09292a4ee23544e89dac5b5
# Parent  19cced21060f71e8efe5f2544ccb14f9273fd93c
Allows for Unicode filenames in Windows (output and stat files).

Copy of x264 code for processing Unicode filenames in Windows.
Output file and stat file(s) are very important for GUI makers.

diff -r 19cced21060f -r 705b7ba5bad5 source/common/common.cpp
--- a/source/common/common.cpp	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/common/common.cpp	Thu Apr 28 09:59:30 2016 +0200
@@ -29,6 +29,8 @@
 #if _WIN32
 #include <sys/types.h>
 #include <sys/timeb.h>
+#include <io.h>
+#include <fcntl.h>
 #else
 #include <sys/time.h>
 #endif
@@ -139,6 +141,90 @@
     fputs(buffer, stderr);
 }
 
+#if _WIN32
+/* For Unicode filenames in Windows we convert UTF-8 strings to UTF-16 and we use _w functions.
+ * For other OS we do not make any changes. */
+void general_log_file(const x265_param* param, const char* caller, int level, const char* fmt, ...)
+{
+    if (param && level > param->logLevel)
+        return;
+    const int bufferSize = 4096;
+    char buffer[bufferSize];
+    int p = 0;
+    const char* log_level;
+    switch (level)
+    {
+    case X265_LOG_ERROR:
+        log_level = "error";
+        break;
+    case X265_LOG_WARNING:
+        log_level = "warning";
+        break;
+    case X265_LOG_INFO:
+        log_level = "info";
+        break;
+    case X265_LOG_DEBUG:
+        log_level = "debug";
+        break;
+    case X265_LOG_FULL:
+        log_level = "full";
+        break;
+    default:
+        log_level = "unknown";
+        break;
+    }
+
+    if (caller)
+        p += sprintf(buffer, "%-4s [%s]: ", caller, log_level);
+    va_list arg;
+    va_start(arg, fmt);
+    vsnprintf(buffer + p, bufferSize - p, fmt, arg);
+    va_end(arg);
+
+    wchar_t buf_utf16[bufferSize];
+    MultiByteToWideChar(CP_UTF8, 0, buffer, -1, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t));
+    fflush(stderr);
+    int oldmode = _setmode(_fileno(stderr), _O_U8TEXT);
+    fwprintf(stderr, L"%ls", buf_utf16);               // WARNING: due to bug in msvcrt.dll fputws doesn't work in mingw/gcc 
+    fflush(stderr);
+    _setmode(_fileno(stderr), oldmode);
+}
+
+FILE* x265_fopen(const char* fileName, const char* mode)
+{
+    wchar_t buf_utf16[MAX_PATH * 2], mode_utf16[16];
+
+    if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t)) &&
+        MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, mode_utf16, sizeof(mode_utf16)/sizeof(wchar_t)))
+    {
+        return _wfopen(buf_utf16, mode_utf16);
+    }
+    return NULL;
+}
+
+int x265_unlink(const char* fileName)
+{
+    wchar_t buf_utf16[MAX_PATH * 2];
+
+    if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, buf_utf16, sizeof(buf_utf16)/sizeof(wchar_t)))
+        return _wunlink(buf_utf16);
+
+    return -1;
+}
+
+int x265_rename(const char* oldName, const char* newName)
+{
+    wchar_t old_utf16[MAX_PATH * 2], new_utf16[MAX_PATH * 2];
+
+    if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, oldName, -1, old_utf16, sizeof(old_utf16)/sizeof(wchar_t)) &&
+        MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, newName, -1, new_utf16, sizeof(new_utf16)/sizeof(wchar_t)))
+    {
+        return _wrename(old_utf16, new_utf16);
+    }
+    return -1;
+}
+#endif
+
 double x265_ssim2dB(double ssim)
 {
     double inv_ssim = 1 - ssim;
@@ -177,10 +263,10 @@
     size_t fSize;
     char *buf = NULL;
 
-    FILE *fh = fopen(filename, "rb");
+    FILE *fh = x265_fopen(filename, "rb");
     if (!fh)
     {
-        x265_log(NULL, X265_LOG_ERROR, "unable to open file %s\n", filename);
+        x265_log_file(NULL, X265_LOG_ERROR, "unable to open file %s\n", filename);
         return NULL;
     }
 
diff -r 19cced21060f -r 705b7ba5bad5 source/common/common.h
--- a/source/common/common.h	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/common/common.h	Thu Apr 28 09:59:30 2016 +0200
@@ -404,7 +404,19 @@
 /* located in common.cpp */
 int64_t  x265_mdate(void);
 #define  x265_log(param, ...) general_log(param, "x265", __VA_ARGS__)
+#define  x265_log_file(param, ...) general_log_file(param, "x265", __VA_ARGS__)
 void     general_log(const x265_param* param, const char* caller, int level, const char* fmt, ...);
+#if _WIN32
+void     general_log_file(const x265_param* param, const char* caller, int level, const char* fmt, ...);
+FILE*    x265_fopen(const char* fileName, const char* mode);
+int      x265_unlink(const char* fileName);
+int      x265_rename(const char* oldName, const char* newName);
+#else
+#define  general_log_file(param, caller, level, fmt, ...) general_log(param, caller, level, fmt, __VA_ARGS__)
+#define  x265_fopen(fileName, mode) fopen(fileName, mode)
+#define  x265_unlink(fileName) unlink(fileName)
+#define  x265_rename(oldName, newName) rename(oldName, newName)
+#endif
 int      x265_exp2fix8(double x);
 
 double   x265_ssim2dB(double ssim);
diff -r 19cced21060f -r 705b7ba5bad5 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/encoder/ratecontrol.cpp	Thu Apr 28 09:59:30 2016 +0200
@@ -417,11 +417,11 @@
                 char *tmpFile = strcatFilename(fileName, ".cutree");
                 if (!tmpFile)
                     return false;
-                m_cutreeStatFileIn = fopen(tmpFile, "rb");
+                m_cutreeStatFileIn = x265_fopen(tmpFile, "rb");
                 X265_FREE(tmpFile);
                 if (!m_cutreeStatFileIn)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "can't open stats file %s\n", tmpFile);
+                    x265_log_file(m_param, X265_LOG_ERROR, "can't open stats file %s.cutree\n", fileName);
                     return false;
                 }
             }
@@ -602,11 +602,11 @@
             statFileTmpname = strcatFilename(fileName, ".temp");
             if (!statFileTmpname)
                 return false;
-            m_statFileOut = fopen(statFileTmpname, "wb");
+            m_statFileOut = x265_fopen(statFileTmpname, "wb");
             X265_FREE(statFileTmpname);
             if (!m_statFileOut)
             {
-                x265_log(m_param, X265_LOG_ERROR, "can't open stats file %s\n", statFileTmpname);
+                x265_log_file(m_param, X265_LOG_ERROR, "can't open stats file %s.temp\n", fileName);
                 return false;
             }
             p = x265_param2string(m_param);
@@ -618,11 +618,11 @@
                 statFileTmpname = strcatFilename(fileName, ".cutree.temp");
                 if (!statFileTmpname)
                     return false;
-                m_cutreeStatFileOut = fopen(statFileTmpname, "wb");
+                m_cutreeStatFileOut = x265_fopen(statFileTmpname, "wb");
                 X265_FREE(statFileTmpname);
                 if (!m_cutreeStatFileOut)
                 {
-                    x265_log(m_param, X265_LOG_ERROR, "can't open mbtree stats file %s\n", statFileTmpname);
+                    x265_log_file(m_param, X265_LOG_ERROR, "can't open mbtree stats file %s.cutree.temp\n", fileName);
                     return false;
                 }
             }
@@ -2656,13 +2656,12 @@
         int bError = 1;
         if (tmpFileName)
         {
-           unlink(fileName);
-           bError = rename(tmpFileName, fileName);
+            x265_unlink(fileName);
+            bError = x265_rename(tmpFileName, fileName);
         }
         if (bError)
         {
-            x265_log(m_param, X265_LOG_ERROR, "failed to rename output stats file to \"%s\"\n",
-                     fileName);
+            x265_log_file(m_param, X265_LOG_ERROR, "failed to rename output stats file to \"%s\"\n", fileName);
         }
         X265_FREE(tmpFileName);
     }
@@ -2675,13 +2674,12 @@
         int bError = 1;
         if (tmpFileName && newFileName)
         {
-           unlink(newFileName);
-           bError = rename(tmpFileName, newFileName);
+            x265_unlink(newFileName);
+            bError = x265_rename(tmpFileName, newFileName);
         }
         if (bError)
         {
-            x265_log(m_param, X265_LOG_ERROR, "failed to rename cutree output stats file to \"%s\"\n",
-                     newFileName);
+            x265_log_file(m_param, X265_LOG_ERROR, "failed to rename cutree output stats file to \"%s\"\n", newFileName);
         }
         X265_FREE(tmpFileName);
         X265_FREE(newFileName);
diff -r 19cced21060f -r 705b7ba5bad5 source/output/raw.cpp
--- a/source/output/raw.cpp	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/output/raw.cpp	Thu Apr 28 09:59:30 2016 +0200
@@ -32,11 +32,11 @@
     b_fail = false;
     if (!strcmp(fname, "-"))
     {
-        ofs = &cout;
+        ofs = stdout;
         return;
     }
-    ofs = new ofstream(fname, ios::binary | ios::out);
-    if (ofs->fail())
+    ofs = x265_fopen(fname, "wb");
+    if (!ofs || ferror(ofs))
         b_fail = true;
 }
 
@@ -51,7 +51,7 @@
 
     for (uint32_t i = 0; i < nalcount; i++)
     {
-        ofs->write((const char*)nal->payload, nal->sizeBytes);
+        fwrite((const void*)nal->payload, 1, nal->sizeBytes, ofs);
         bytes += nal->sizeBytes;
         nal++;
     }
@@ -65,7 +65,7 @@
 
     for (uint32_t i = 0; i < nalcount; i++)
     {
-        ofs->write((const char*)nal->payload, nal->sizeBytes);
+        fwrite((const void*)nal->payload, 1, nal->sizeBytes, ofs);
         bytes += nal->sizeBytes;
         nal++;
     }
@@ -75,6 +75,6 @@
 
 void RAWOutput::closeFile(int64_t, int64_t)
 {
-    if (ofs != &cout)
-        delete ofs;
+    if (ofs != stdout)
+        fclose(ofs);
 }
diff -r 19cced21060f -r 705b7ba5bad5 source/output/raw.h
--- a/source/output/raw.h	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/output/raw.h	Thu Apr 28 09:59:30 2016 +0200
@@ -35,7 +35,7 @@
 {
 protected:
 
-    std::ostream* ofs;
+    FILE* ofs;
 
     bool b_fail;
 
diff -r 19cced21060f -r 705b7ba5bad5 source/x265.cpp
--- a/source/x265.cpp	Tue Apr 26 15:06:55 2016 -0700
+++ b/source/x265.cpp	Thu Apr 28 09:59:30 2016 +0200
@@ -451,10 +451,10 @@
     this->output = OutputFile::open(outputfn, info);
     if (this->output->isFail())
     {
-        x265_log(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
+        x265_log_file(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
         return true;
     }
-    general_log(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
+    general_log_file(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
     return false;
 }
 
@@ -493,6 +493,39 @@
     return 1;
 }
 
+#ifdef _WIN32
+/* Copy of x264 code, which allows for Unicode characters in the command line.
+ * 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 = (char**)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
+
 /* CLI return codes:
  *
  * 0 - encode successful
@@ -513,6 +546,9 @@
 
     GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
     SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
+#if _WIN32
+    get_argv_utf8(&argc, &argv);
+#endif
 
     ReconPlay* reconPlay = NULL;
     CLIOptions cliopt;


More information about the x265-devel mailing list