静止画+音声=動画(Twitter 投稿可能 MP4)作成方法
画像ファイル+音声ファイルで、静止画音声動画(Twitter に投稿可能な MP4)をつくる方法を記す。
必要なもの
- 使用するソフト: FFmpeg
- 画像ファイル:
src.png
- 音声ファイル:
src.m4a
方法
src.png
と src.m4a
を同じディレクトリに置き、そこで以下のコマンドを実行する。
ffmpeg -y -loop 1 -i src.png -i src.m4a -shortest -tune stillimage src.mpg ffmpeg -y -i src.mpg -an src2.mpg ffmpeg -y -i src2.mpg -i src.m4a -acodec copy out.mp4
上記の通り、3 つのコマンドを上から順に実行していくと、どれかが失敗しない限り、目的の out.mp4
が生成される。
解説
3 つのコマンドを日本語で表現すると、
- 画像と音声から mpg を作成し、
- その mpg から音声を抜いた新 mpg を作成し、
- 新 mpg と音声から mp4 を作成せよ。
となる。
どうして、このような回りくどい方法なのだろうか。1 の段階でいきなり mp4 をつくればいいのではないか。これには理由がある。いきなり mp4 をつくってしまうと、VLC メディアプレイヤーでは一応再生できるものの、シークバーが効かなかったり、Twitter に投稿できなかったりと、不完全な mp4 が出来上がってしまうからだ。FFmpeg やファイルフォーマットの知識には疎い。原因不明である。
さて、以下に、コマンドの内容を一つ一つ解説する。
コマンド 1
ffmpeg -y -loop 1 -i src.png -i src.m4a -shortest -tune stillimage src.mpg
このコマンドにより、src.png
と src.m4a
から src.mpg
を作成する。src.mpg
は静止画+音声=動画である。
-y
: 出力ファイル強制上書き(必ずしも必要ではないオプション)-loop
: 静止画を動画にする際に必要らしい?-i src.png
: 画像を入力-i src.m4a
: 音声を入力-shortest
: 音声の尺と同じ尺の動画を作成?-tune stillimage
: 静止画を動画にする際に必要らしい?src.mpg
: 動画を出力
コマンド 2
ffmpeg -y -i src.mpg -an src2.mpg
このコマンドにより、src.mpg
から src2.mpg
を作成する。src2.mpg
は静止画だけの動画であり、音声はない。
-an
: 音声を無効にする
コマンド 3
ffmpeg -y -i src2.mpg -i src.m4a -acodec copy out.mp4
このコマンドにより、src2.mpg
と src.m4a
から out.mp4
を作成する。完成だ。
-acodec copy
: 音声をエンコードせず、そのまま動画の音声として使用する。(音質が劣化してもいいなら不要なオプション)
Visual Studio 2013 で msvcrt.dll にリンクする
Visual Studio Community 2013 の cl.exe によるビルドにおいて、生成される実行ファイルが msvcr120.dll ではなく msvcrt.dll をリンクするようにする方法・更にはどちらにもリンクさせない方法をメモしておく。
Visual Studio Community 2013 ダウンロードサイト
Microsoft が個人開発者や小規模組織等向けに公開している Visual Studio 無償版の名称は、Visual Studio Community である。
- Visual Studio Community 2013 with Update 5 (ISO)
- go.microsoft.com/fwlink/?LinkId=532496
- Visual Studio 2013 Language Pack (日本語)
- go.microsoft.com/fwlink/?LinkID=320680
情報源を元にやってみる
タイトルの方法については以下のサイトに全て書かれている。
すなわち、Windows Driver Kit の中に、良い msvcrt.lib がある。
- Download Windows Driver Kit Version 7.1.0 from Official Microsoft Download Center
- download.microsoft.com/download/4/A/2/4A25C7D5-EFBE-4182-B6A9-AE6850409A78/GRMWDK_EN_7600_1.ISO
なんとかして msvcrt.lib を取り出す
F(ISO):\WDK
から以下のファイルを例えば C:\wdk\
に置く。
libs_x86fre.msi
libs_x86fre_cab001.cab
C:\wdk\
にてコマンドプロンプトで以下を実行する。
msiexec /a libs_x86fre.msi /qb targetdir=C:\wdk\temp\
これで CAB 圧縮ファイルがうまい具合に展開されて、目当ての msvcrt.lib が以下のパスに出現している。
C:\wdk\temp\WinDDK\7600.16385.win7_wdk.100208-1538\lib\Crt\i386\msvcrt.lib
この msvcrt.lib を C:\wdk\lib\
にでも入れておく。
使用例
以下のコードは、cl.exe でうまくビルドできるよう環境変数を整えるためのバッチファイルである。
@echo off setlocal set path=%path%;"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin" set include="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src";"C:\Program Files (x86)\Windows Kits\8.1\Include\shared";"C:\Program Files (x86)\Windows Kits\8.1\Include\um"; set lib="C:\wdk\lib";"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib";"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86" if "%*" GTR "" (cmd /c %*) else (cmd /k prompt[VS]$P$G) endlocal
このように、環境変数 lib に C:\wdk\lib
をなるべく先頭に入れておく。
これで、ビルドする際には良い msvcrt.lib が使用され、msvcrt.dll にリンクされるようになる。
あるいは、C言語ソースコード中に標準ライブラリの関数等を使っておらず、リンカオプションで独自にエントリポイントを指定 /ENTRY:__start__
した場合は、msvcrt.dll へのリンクもされなくなる。
【GCC】implicit declaration of function '_wtoi' 解決方法
- 問題 : GCC で C コンパイル時の警告文「warning: implicit declaration of function '
_wtoi
' [-Wimplicit-function-declaration] int n = _wtoi(argv[1]);」を解消したい - 答え :
#undef __STRICT_ANSI__
コンパイルする
#include <windows.h> int main() { // コマンドライン引数(1番目)を数値変換して出力 int length; LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length); int n = _wtoi(argv[1]); TCHAR s[99]; wsprintf(s, TEXT("%d"), n); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
警告が出る
コンパイル gcc src.c -std=c11
すると、以下の警告文が表示される。
src.c: In function 'main': src.c:6:3: warning: implicit declaration of function '_wtoi' [-Wimplicit-funct ion-declaration] int n = _wtoi(argv[1]);
この意味は、「暗黙に宣言された関数 _wtoi
を使っています」だ。
インクルードし忘れか?
きっと _wtoi
が宣言されたヘッダファイルをインクルードしていないから、こんな警告をされるのだ。ならば、インクルードしよう。C:\MinGw\include\
内を検索する。
結果はこれだ。
stdlib.h
tchar.h
なので、#include <stdlib.h>
と #include <tchar.h>
を src.c
に追加して再コンパイルするも、同じ警告をされてしまった。(それどころか別のエラーまで発生する始末)
よくよく調べてみると、windows.h
にて、遠回しにこれらのヘッダファイルがインクルードされるようになっていたので、全く意味がなかった。
原因は stdlib.h のソースだった
明示的に宣言しているはずなのに、どうして暗黙の宣言だと警告されてしまうのか。その原因は、stdlib.h
内にある _wtoi
の宣言方法にあった。以下に、当該箇所を示す。
#if !defined (__STRICT_ANSI__) _CRTIMP double __cdecl __MINGW_NOTHROW _wtof (const wchar_t *); _CRTIMP int __cdecl __MINGW_NOTHROW _wtoi (const wchar_t *); _CRTIMP long __cdecl __MINGW_NOTHROW _wtol (const wchar_t *); #endif
#if !defined (__STRICT_ANSI__)
というブロックに囲われて宣言されている。「もし __STRICT_ANSI__
が定義されていないならば、_wtoi
という関数を宣言しますよ」という意味だ。ゆえに、_wtoi
が宣言されたヘッダファイルを正しくインクルードしていても、__STRICT_ANSI__
が定義されていれば、暗黙の宣言になってしまい、警告が出る。
そもそも「暗黙の宣言」とは何か。よくわからないが、#include <stdio.h>
しなくとも printf
が使えるのと同じで、自動的に宣言してくれる機能があるらしい。
GCC コマンドオプションによって結果が変わる
つまり、警告を出さないためには __STRICT_ANSI__
を定義しないようにすればいいことがわかる。どうすれば定義されないようにできるかというと、コンパイル時のオプションで -std=c11
や -std=c99
を指定せず、例えば -std=gnu1x
を指定しておけば定義されなくなる。その証明は、以下のソースコードのコンパイルで行うことができる。
#include <windows.h> int main() { TCHAR s[99]; wsprintf(s, TEXT("%d"), __STRICT_ANSI__); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
コンパイル gcc nazo.c -std=c11
して、実行すると、メッセージボックスが現れ、「1」と表示される。
一方で、gcc nazo.c -std=gnu1x
すると、以下のエラーが出てコンパイル失敗する。
nazo.c: In function 'main': nazo.c:4:27: error: '__STRICT_ANSI__' undeclared (first use in this function) wsprintf(s, TEXT("%d"), __STRICT_ANSI__); ^ nazo.c:4:27: note: each undeclared identifier is reported only once for each function it appears in
このことにより、__STRICT_ANSI__
の定義は、-std=c11
なら「有」となり、-std=gnu1x
だと「無」になることがわかる。
強引だが解決できなくはない
ならば、-std=c11
時に行われる __STRICT_ANSI__
の定義を取り消せば、_wtoi
が明示的に宣言されるようになるのであり、その方法として、「ソースコードの最初のほうに #undef __STRICT_ANSI__
を書いておく」というものがある。
#undef __STRICT_ANSI__ #include <windows.h> int main() { // コマンドライン引数(1番目)を数値変換して出力 int length; LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length); int n = _wtoi(argv[1]); TCHAR s[99]; wsprintf(s, TEXT("%d"), n); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
これで警告は出なくなる。
たかが警告だ放っておこう
しかしながら、ヘッダファイルが -std=c11
といった規格指示によって、何らかの意図があって _wtoi
の宣言の有無を自動決定していくれているものを「警告をなくしたいから」という理由だけで影響範囲も考えず __STRICT_ANSI__
の定義を取り消すことはまずいことのきっかけになりそうなにおいを孕んでいる。
たかが警告だ。放っておこう。