今回はなんとなくffmpegAPIを導入します。いや、音楽再生で真っ先に思い浮かんだのがffmpegだったもんで。え?DirectX?DxLib?知らない子ですね(ぉい)。この記事ではFFmpegをビルドするなんてことはしません。
@yumetodo zeranoeのビルドがいっぱいExternal libが入っているから、それをLSWにlinkすると、変なことが起こるかも
例:どかのMultiple entry point, unresolved/redifined symbols
— 芳乃さくら(三次元) (@MaverickTse) 2015, 2月 12
「いや、とりあえず、仮設置だから、ね --by じゃりみち」
って言っとけば逃げられる・・・のかな?
ffmpegAPIとは?
動画編集をしたり、音声編集をしたことのある人なら一度は聞いたことがあるはず、あのffmpegです。数多くのコーデックに対応しているソフトウェアです。
AviUtlの入力プラグインとして不動の地位を築きつつあるL-SMASH Worksもffmpegの力なしにはなかったかもしれません。
で、そのFFmpegを共有ライブラリ付きでコンパイルすると、プログラムから直接FFmpegのAPIを利用することが可能になります。
「じゃあ、今回の目標はそこはかとなくffmpegAPIに触れるように導入するのか」だって?いいえ。
そこはかとなく
なんとなく、どことなく。特にどこがどうと言うわけではないが、雰囲気として感じられる様子などを表す表現。
--実用日本語表現辞典
さりげなく
何事もないように振る舞うさま。それらしいようすを感じさせない。
--デジタル大辞泉
「そこはかとなく」導入してはいけません、「さりげなく」導入しようと思います。大丈夫、ビルド済みのライブラリーを取ってきてコピーするだけの簡単なお仕事です(サンプルコード書くのに25時間もかかったなんて言えない)。
目標(再掲)
- ffmpegAPIをVisual Studio 2013 Community から使えるように、Win32、x64両対応できるように導入する
環境
項目 | 内容 |
---|---|
FFmpegバージョン | FFmpeg git-078be09(2015/02/10) |
Visual Studio | Visual Studio 2013 Community for Desktop Update4 |
ビルド構成 | Win32 or x64 | Debug or Release |
OS | Windows 7 Homr Premium(64bit) |
inttypes.hとstdint.h
少なくともVisual Studio 2010の頃はinttypes.hはVisual Studioになく、さらに昔はstdint.hもなかったらしいです。その頃のVisual Studioをお使いの場合は下記のリンクをどうぞ。
Visual Studio 2013 communityではいずれも必要ありません
手順抜粋
ざっというと・・・というより、これだけでいい気もするけど、こんな感じ。
- 導入
- SharedとDevの32bit,64bit両方落とす
- inttypes.hとstdint.hをDL、配置(古いバージョンのVCのみ)
- Devを配置
- Sharedを配置
- Visual Studio の設定
手順詳細
注意
.7zファイルの解凍(展開)方法については解説しません。各自CubeICEや7-Zipなどを導入して解凍(展開)できるようにしておいてください。
DL
-
SharedとDevの32bit,64bit両方落とす
http://ffmpeg.zeranoe.com/builds/
にアクセスし、- Download FFmpeg git-[最新バージョン] 32-bit Shared
- Download FFmpeg git-[最新バージョン] 64-bit Shared
- Download FFmpeg git-[最新バージョン] 32-bit Dev
- Download FFmpeg git-[最新バージョン] 64-bit Dev
をクリックして4つともDLする。編集時点git-078be09。
配置
注意
以下ライブラリーは「C:\lib\ffmpeg20150210」に入れていくものとする。適当にパスは読み替えてね。
- 「C:\lib\ffmpeg20150210」フォルダー(ディレクトリ)を作る。
- 「C:\lib\ffmpeg20150210\win32」フォルダー(ディレクトリ)を作る。
- 「C:\lib\ffmpeg20150210\win64」フォルダー(ディレクトリ)を作る。
- 「C:\lib\ffmpeg20150210\include」フォルダー(ディレクトリ)を作る。
-
先ほどDLした
を2つとも解凍(展開)する。
- 32-bit Devの中身を「include」フォルダー以外すべて「C:\lib\ffmpeg20150210\win32」に入れる
- 64-bit Devの中身を「include」フォルダー以外すべて「C:\lib\ffmpeg20150210\win64」に入れる
- 64-bit Devの中の「include」の中身を「C:\lib\ffmpeg20150210\include」に入れる。いや、32bitも64bitも中身同じだけど。
-
先ほどDLした
を2つとも解凍(展開)する。
- 「ffmpeg-[最新日付]-git-[最新バージョン]-win32-shared\bin」の中身のうち.dllを「C:\Windows\SysWOW64」に入れる。
- 「ffmpeg-[最新日付]-git-[最新バージョン]-win64-shared\bin」の中身のうち.dllを「C:\Windows\System32」に入れる。
- 「C:\Program Files (x86)\Microsoft Visual Studio [VCのバージョン]\VC\include」にinttypes.h、stdint.hを入れる(古いバージョンのみ)
x64構成を作る(ない人のみ)
注意
以下フツーにVisual Studioで「Win32 プロジェクト」ないし、「Win32 コンソールアプリケーション」を空のプロジェクトとして作ってあるものとします。
詳細は
http://www.buildinsider.net/small/opencv/03
の「2.1 新規プロジェクト作成」の項目に投げます。ソースファイルはまだいらない。
説明しようと思ったんだけど、ちゃんと書いてるサイトがあるのでそちらに投げます。
http://www.buildinsider.net/small/opencv/03
の「2.2 新規プロジェクト作成(64bitアプリケーションの場合)」の項目です。
Visual Studio Project設定
-
構成:すべての構成
プラットフォーム:すべてのプラットフォーム
の状態で
構成プロパティ→C/C++→全般→追加のインクルードディレクトリに
C:\lib\ffmpeg20150210\include
を追加、適用を押す -
構成:すべての構成
プラットフォーム:x64
の状態で
構成プロパティ→リンカー→全般→追加のライブラリーディレクトリで
C:\lib\ffmpeg20150210\win64\lib
を追加、適用を押す -
構成:すべての構成
プラットフォーム:Win32
の状態で
構成プロパティ→リンカー→全般→追加のライブラリーディレクトリで
C:\lib\ffmpeg20150210\win32\lib
を追加、適用を押す
テンプレート化(必要なら)
ファイル→テンプレートのエクスポートで
プロジェクトテンプレート→
テンプレート名「FFmpeg-API_win32_x64_Console」
テンプレートの説明「http://freesofutotravel.blog94.fc2.com/blog-entry-16.html」
アイコンのイメージ:適当に↓とか
https://lh4.googleusercontent.com/-C8ZOe8nUlr0/AAAAAAAAAAI/AAAAAAAAAAg/Vc9qrl88PEI/photo.jpg
*適当でいいです
で完了を押す。
実験
下記のコードを実行して見てください。一応、C++でなくCでもコンパイルできるようにはなっているはず。
[実行ファイル名] [動画or音声ファイルのフルパス]
のように指定します。
サンプルコード
#ifdef _MSC_VER #if _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES != 1 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 #endif #if _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT != 1 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 #endif #endif /*_MSC_VER */ #include <stdio.h> #include <stdint.h> #ifdef __cplusplus extern "C" { #else #include <stdbool.h> #define nullptr NULL #endif /* __cplusplus */ #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #ifdef __cplusplus } #endif /* __cplusplus */ #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "swscale.lib") bool my_libav_file_open(AVFormatContext **p_format_ctx, char const* file_name){ /* ほぼL-SMASH Worksのlibavsmash.cのlibavsmash_open_file関数。 */ char error_string[96] = { 0 }; av_register_all(); avcodec_register_all(); if (avformat_open_input(p_format_ctx, file_name, NULL, NULL)) { strcpy(error_string, "Failed to avformat_open_input.\n"); goto open_fail; } if (avformat_find_stream_info(*p_format_ctx, NULL) < 0) { strcpy(error_string, "Failed to avformat_find_stream_info.\n"); goto open_fail; } return true; open_fail: if (*p_format_ctx) avformat_close_input(p_format_ctx); fprintf(stderr, "%s", error_string); return false; } char* codec_type_string(enum AVMediaType type) { switch (type) { case AVMEDIA_TYPE_UNKNOWN: return "Unknown"; case AVMEDIA_TYPE_VIDEO: return "Video"; case AVMEDIA_TYPE_AUDIO: return "Audio"; case AVMEDIA_TYPE_DATA: return "Data"; case AVMEDIA_TYPE_SUBTITLE: return "Subtitle"; case AVMEDIA_TYPE_ATTACHMENT: return "Attachment"; case AVMEDIA_TYPE_NB: return "NB"; default: return "Undefined"; } } int main(int argc, char *argv[]) { char* file_name; if (2 != argc){ fprintf(stderr, "%s", "Invalid input"); return -1; } else{ file_name = argv[1]; } AVFormatContext *format_ctx = nullptr;//必ずNULLで初期化、じゃないとメモリーリークが起こる if (false == my_libav_file_open(&format_ctx, file_name)) return -1; unsigned int i; for (i = 0; i < format_ctx->nb_streams; i++){ printf("stream #%d\n", i); printf("\tcodec type: %s\n", codec_type_string(format_ctx->streams[i]->codec->codec_type)); enum AVCodecID codec_id = format_ctx->streams[i]->codec->codec_id; AVCodec *codec = avcodec_find_decoder(codec_id); if (codec) { printf("\tcodec name: %s\n", codec->name); } else { printf("\tcodec id %d is not found\n", codec_id); } } if (nullptr != format_ctx) avformat_close_input(&format_ctx); return 0; }
なんでjsいじってもSyntaxHighlighterがうまく色分けしてくれないんや・・・。あと、2 != argcの時に標準入力から動的確保した領域に文字列を受けるように書こうとしたら、「確保範囲外に書き込むな」ってデバッガーに怒られるし。どーなってんだってばよ。
サンプルコードの実行例
ファイル名:C:\Users\yumetodo\Videos\『魔法科高校の劣等生 LOST ZERO』プロモーションムービー.mp4 stream #0 codec type: Video codec name: h264 stream #1 codec type: Audio codec name: aac
参考サイト
なぜか知らん、FFmpegAPIの導入も使い方も解説サイトが少ない。どーなってんだってばよ。結局一番役に立ったのは、AviUtlのプラグインでお馴染み、L-SMASH Worksのソースコードでした
@yumetodo @Paranoialmaniac と契約して、LSW developer になろうw
— Innovator (@MaverickTse) 2015, 2月 12
だから、どうしてそ~なった。
@yumetodo @MaverickTse 俺のコードがわかりやすい?そんなばかな。
わざと空行が全然無いというのに。
— muken, Phyrexian MP4 (@Paranoialmaniac) 2015, 2月 12
リファレンスの初見殺し度は異常だと私はおもうんです。
参考サイトを見る上での注意点として、libavformat 53.2.0以降ではav_open_input_file関数を始めとして多くの関数が廃止、変更されています。十分注意してください。
- VFR-maniac/L-SMASH-Works | GitHub
https://github.com/VFR-maniac/L-SMASH-Works - VFR-maniac/L-SMASH-Works - Compare | GitHub
https://github.com/VFR-maniac/L-SMASH-Works/compare/2242b107cf2c41b0ca6d118b66442262e7f2f3ee...47ad4b9edd3a5f4d6274f272f2b600a1b243f7b3 - l-smash/l-smash | GitHub
https://github.com/l-smash/l-smash - 目指せCREATIVE ART!! FFmpegのライブラリをMicrosoft Visual C++で使う
http://creativeart.blog.shinobi.jp/c-c--/FFmpegのライブラリをMicrosoft Visual C++で使う - こたつつきみかん » libavcodec / libavformat を使ってみる 1
http://www.lifeaether.com/overtaker/blog/?p=1276 - Zeranoe FFmpeg builds
http://ffmpeg.zeranoe.com/builds/ - 猫科研究所 - x264-changelog-jp r2000-r2099
http://up-cat.net/x264%252Dchangelog%252Djp%2Br2000%252Dr2099.html