2013年7月8日月曜日

MultiByteToWideCharToMultiByte その2

承前

2.FFmpegとAvisynth

前回に書いたような経緯でffmpeg.exeやavconv.exeでも日本語ファイル名のavsを読めるようになったのだが、今年の3月に今度はFFmpegのほうだけでこれが再発した。
原因はこのコミット
Avxsynthの開発者がAvxsynth入力を導入するべくFFmpegのほうだけavformat/avisynth.cを全部書きなおしてしまったことにより発生したのだった。
そして、自分がバグの再発を知ったのは先月(6月)の半ば頃のことである(2ちゃんねるのffmpegスレで見かけた)。

さて、問題のコードは次のとおりだった。
arg = avs_new_value_string(s->filename);
val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
このコード、x264のavs.cを参考にしているわけだが、大事なことを忘れている。
前回も書いたように、s->filenameの中身はUTF-8でエンコードされた文字列である。
一方、Avisynthはマルチバイト文字アプリケーションで、文字列はACPエンコードが前提になっている。
だから非ASCIIな文字を含んだ文字列をそのままでAvisynthに渡したら、Avisynthはファイルを見つけられないのである。

書きなおすのは構わないんだけど、できればもうちょっと既存のコードを注意して読んでおいて欲しかった……。
ちょっと腹がたったから言っちゃうけど、Avxsynthユーザーなんて、非英語圏のAvisynthユーザーの千分の一もいないよ。

さて、原因は前回と同じなので対策も前回とまったく同じである。
再びパッチを書いて今度はFFmpegのMLに送った(Avxsynthの中の人はFFmpegだけに送ったのでLibavは昔のまま)。
かくしてコードは次のように変わった。
#ifdef _WIN32
    char filename_ansi[MAX_PATH * 4];
    wchar_t filename_wc[MAX_PATH * 4];
    MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
    WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi, MAX_PATH * 4, NULL, NULL);
    arg = avs_new_value_string(filename_ansi);
#else
    arg = avs_new_value_string(s->filename);
#endif
    val = avs_library->avs_invoke(avs->env, "Import", arg, 0);
変数名が変わったのと MAX_PATH * 4 は、そのほうがいいんじゃね?とレビューしてもらったDaemon404(Derek Builtenhuis)氏に言われたから。

さすがにもう再発することはないと思うけど、もし再発しても次は知らない。気づいた人が直して下さい。
(そもそも筆者はエンコード素材のファイル名は半角英数以外使わないので、自分で気づくことはまずありません)

それともうひとつ。
このFFmpegの新Avisynth入力は、Avisynth2.5.8では不具合が出るそうです(参考:avisynth scripts fail to load in ffmpeg)。
まだ2.5.8を使ってる人は、とっとと2.6alphaに更新しましょう。

0 件のコメント:

コメントを投稿