eingusteのblog

Windows向けFFmpegバイナリを個人的にビルド(コンパイル)してます。その更新情報など。

カテゴリ: 外部ライブラリ

外部ライブラリlibvpxを更新したところ、vp9のエンコード時にVP8E_SET_NOISE_SENSITIVITYに関するエラーが発生していました。

http://pastebin.com/AVaZmdX5
Failed to set VP8E_SET_NOISE_SENSITIVITY codec control: Unspecified internal error

libvpxのlogを確認したところ、VP9E_SET_NOISE_SENSITIVITYに変更することとなったようです。そこで、vp8エンコードのときにはVP8E_SET_NOISE_SENSITIVITYを有効にし、vp9エンコード時にはVP9E_SET_NOISE_SENSITIVITYを有効にするようにソースに修正を加えました。
そのパッチは以下のとおりです。
http://pastebin.com/mHiR9ZqD
diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c
index 163d12a..0d89c85 100644
--- a/libavcodec/libvpxenc.c
+++ b/libavcodec/libvpxenc.c
@@ -125,6 +125,7 @@ static const char *const ctlidstr[] = {
     [VP9E_SET_TILE_ROWS]               = "VP9E_SET_TILE_ROWS",
     [VP9E_SET_FRAME_PARALLEL_DECODING] = "VP9E_SET_FRAME_PARALLEL_DECODING",
     [VP9E_SET_AQ_MODE]                 = "VP9E_SET_AQ_MODE",
+    [VP9E_SET_NOISE_SENSITIVITY]       = "VP9E_SET_NOISE_SENSITIVITY",
 #endif
 };
 
@@ -440,7 +441,8 @@ static av_cold int vpx_init(AVCodecContext *avctx,
         codecctl_int(avctx, VP8E_SET_ARNR_STRENGTH,    ctx->arnr_strength);
     if (ctx->arnr_type >= 0)
         codecctl_int(avctx, VP8E_SET_ARNR_TYPE,        ctx->arnr_type);
-    codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
+    if (avctx->codec_id == AV_CODEC_ID_VP8)
+        codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
     if (avctx->codec_id == AV_CODEC_ID_VP8)
         codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS,  av_log2(avctx->slices));
     codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD,  avctx->mb_threshold);
@@ -451,6 +453,7 @@ static av_cold int vpx_init(AVCodecContext *avctx,
 
 #if CONFIG_LIBVPX_VP9_ENCODER
     if (avctx->codec_id == AV_CODEC_ID_VP9) {
+        codecctl_int(avctx, VP9E_SET_NOISE_SENSITIVITY, avctx->noise_reduction);
         if (ctx->lossless >= 0)
             codecctl_int(avctx, VP9E_SET_LOSSLESS, ctx->lossless);
         if (ctx->tile_columns >= 0)

configureのlibmodplug関係の修正で、git版のconfigureでエラーがでるようになりました。
こちらで配布しているffmpegではスタティックライブラリを利用していることが要因の1つです。

原因はlibmodplugがデフォルトでDLL使用を前提にしたヘッダになっているためです。
Windows環境ではDLLでの関数名とスタティックライブラリでの関数名が異なります。
そのためDLLでの関数名、_imp__ModPlug_Loadを見つけることができず、エラーとなりました。

回避策はいくつかあります。
コンパイルオプションに-DMODPLUG_STATICを加えること。
これはpkgconfigのCflagsに加える、またはffmpegのビルドオプションに加えることで回避できます。
次にlibmodplug/modplug.hで#define MODPLUG_STATICを宣言する方法があります。ただし、これはlibmodplugをスタティックライブラリ以外では利用しないことを前提にした修正です。

DLLを利用する場合には、不要な修正ですが、現状、git版ソースではlibavformat/libmodplug.cにてMODPLUG_STATICを宣言しています。そのためDLLを利用する場合にはその宣言を削除する必要があります。
どちらにせよ修正が必要なconfigureの変更だったのですが、Windows以外のプラットフォームでの互換性を考えると、有意な修正だったので変更自体には賛成しています。
また変更前のconfigureでは逆にDLLを利用するためにはconfigureに修正を加える必要がありました。
変更後のconfigureではpkgconfigなどを修正することで、スタティックライブラリとして利用するかDLLとして利用するかを選択できるようになったと言えると思います。

以下、参考資料
http://pastebin.com/va9tCWzV
external int ModPlug_Load

http://pastebin.com/Dy3Gu1Fj
#include <libmodplug/modplug.h>
MODPLUG_EXPORT ModPlugFile* ModPlug_Load

2014-09-05時点のgit版バイナリです。ffmpegとffplay、ffprobeを同梱しています。
外部ライブラリlibcdioを追加しました。
ダウンロードは↓

32bit版
FFmpeg version N-66119-g2178abd(x86)(7z) 10.4M

64bit版
FFmpeg version N-66119-g2178abd(x64)(7z) 11.0M

  libavutil      54.  7.100 / 54.  7.100
libavcodec 56. 1.100 / 56. 1.100
libavformat 56. 4.100 / 56. 4.100
libavdevice 56. 0.100 / 56. 0.100
libavfilter 5. 0.103 / 5. 0.103
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 0.100 / 3. 0.100
libswresample 1. 1.100 / 1. 1.100
libpostproc 53. 0.100 / 53. 0.100

2.3系安定版とgit版では現在、mp4形式で-vcodecにlibxvidを指定すると不正なエンコードになってしまっているようです。
2.2系安定版では問題なくエンコードできるので、libxvidを利用したい場合には、そちらをご利用ください。

違いを見ると、2.2系ではMpeg4(Simple Profile)としてエンコードされて、再生でき、2.3系、git版ではMpeg4としてエンコードされて、画像サイズが取得できず、再生できなくなっているようです。
いずれは修正されるとは思いますが、現状は、libxvidを利用したい場合には、2.2系安定版をご利用ください。
2.3系、git版を利用する場合には、コーデック(-vcodec)にmpeg4を指定するのも検討してみてください。

PS
不慣れながらバグ報告しておきました。
再現性があるということで受諾されました。
修正されるのを待ちましょう^^

PS2
2014-09-07 12:20ごろ、修正されました。
ffmpeg: Copy extradata if it has been initialized later from the encoder
Fixes Ticket3909
Fixed in ab84effdeda931a74d8503891488ed538619a5d3
修正したバイナリをアップしました。

2014/02/01 追記
GnuTLS バージョン3.2.10が公開されました。
3.2.9からバグ修正が行われ、ソースに修正加える必要がなくなりました。
随時3.2.10を適用したffmpegバイナリに差し替えていきます。



GnuTLS バージョン3.2.9のインストール手順のメモです。

libnettlegmplibは別途インストール済みの状態です。
ソースそのままだとエラーで止まるので、少し修正が必要でした。
次のGnuTLS-3.2.9用パッチファイルを適用します。

gzip -d gnutls-3.2.9.diff.gz
tar xf gnutls-3.2.9.tar.xz
cd gnutls-3.2.9/
patch -p1 < ../gnutls-3.2.9.diff
./configure --enable-threads=win32 --disable-shared --disable-cxx --without-p11-kit --disable-guile
make
make install


64bit版はconfigureに--build=x86_64-w64-mingw32を追加します。

./configure --enable-threads=win32 --disable-shared --disable-cxx --without-p11-kit --disable-guile --build=x86_64-w64-mingw32

PS
バージョン3.2.7~3.2.8.1への更新を行っていなかったのは、更新するとffmpegTLSでエラーがでてしまい、ダウンロードできなくなってしまったからです。
たしかERROR in the push functionというエラーです
3.2.9でこれが修正されたのか、エラーを起こさなくなっていたので、3.2.6からバージョンアップさせました。多少ソースに修正が必要でしたが、正常に動作しているようなので、安心しています。

PS2
インストール後、pkg-configファイルに修正が必要です。
具体的には-lcrypt32を追記します。

Name: GnuTLS
Description: Transport Security Layer implementation for the GNU system
URL: http://www.gnutls.org/
Version: 3.2.9
Libs: -L${libdir} -lgnutls
Libs.private: -L/usr/local/lib -lz  -lws2_32 -lpthread -L/usr/local/lib -liconv
 -lws2_32  -lgmp -lcrypt32
Requires.private: nettle, hogweed, zlib
Cflags: -I${includedir}

PS
以下、gnutls-3.2.9.diffです。

diff -ur gnutls-3.2.9.orig/src/common.c gnutls-3.2.9/src/common.c
--- gnutls-3.2.9.orig/src/common.c	2013-11-11 02:59:14 +0900
+++ gnutls-3.2.9/src/common.c	2014-01-27 21:28:49 +0900
@@ -1073,3 +1073,40 @@
 }
 
 #endif
+
+#ifdef _WIN32
+static int neterrno()
+{
+int err = WSAGetLastError();
+  
+	if (err == WSAEWOULDBLOCK)
+  		return EAGAIN;
+	else if (err == WSAEINTR)
+  		return EINTR;
+	else if (err == WSAEINPROGRESS)
+		return EINPROGRESS;
+	return 0;
+}
+
+static ssize_t
+system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size)
+{
+	return send((long)ptr, data, data_size, 0);
+}
+
+static ssize_t
+system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size)
+{
+	return recv((long)ptr, data, data_size, 0);
+}
+
+void set_read_funcs(gnutls_session_t session)
+{
+	gnutls_transport_set_push_function(session, system_write);
+	gnutls_transport_set_pull_function(session, system_read);
+	gnutls_transport_set_errno_function(session, neterrno);
+
+}
+#else
+# define set_read_funcs(x)
+#endif
diff -ur gnutls-3.2.9.orig/src/common.h gnutls-3.2.9/src/common.h
--- gnutls-3.2.9.orig/src/common.h	2014-01-02 02:14:59 +0900
+++ gnutls-3.2.9/src/common.h	2014-01-30 14:10:41 +0900
@@ -34,6 +34,7 @@
 #ifdef _WIN32
 #include <io.h>
 #include <winbase.h>
+#include <errno.h>
 #undef OCSP_RESPONSE
 #endif
 
@@ -67,39 +68,3 @@
 
 void pkcs11_common(void);
 
-#ifdef _WIN32
-static int neterrno()
-{
-int err = WSAGetLastError();
-  
-	if (err == WSAEWOULDBLOCK)
-  		return EAGAIN;
-	else if (err == WSAEINTR)
-  		return EINTR;
-	else if (err == WSAEINPROGRESS)
-		return EINPROGRESS;
-	return 0;
-}
-
-static ssize_t
-system_write(gnutls_transport_ptr ptr, const void *data, size_t data_size)
-{
-	return send((long)ptr, data, data_size, 0);
-}
-
-static ssize_t
-system_read(gnutls_transport_ptr_t ptr, void *data, size_t data_size)
-{
-	return recv((long)ptr, data, data_size, 0);
-}
-
-void set_read_funcs(gnutls_session_t session)
-{
-	gnutls_transport_set_push_function(vpninfo->https_sess, system_write);
-	gnutls_transport_set_pull_function(vpninfo->https_sess, system_read);
-	gnutls_transport_set_errno_function(vpninfo->https_sess, neterrno);
-
-}
-#else
-# define set_read_funcs(x)
-#endif
diff -ur gnutls-3.2.9.orig/src/tests.c gnutls-3.2.9/src/tests.c
--- gnutls-3.2.9.orig/src/tests.c	2014-01-02 02:14:59 +0900
+++ gnutls-3.2.9/src/tests.c	2014-01-25 22:17:50 +0900
@@ -27,6 +27,8 @@
 #include <signal.h>
 #else
 #include <errno.h>
+#include <winerror.h>
+#include <winsock2.h>
 #endif
 
 #include <stdio.h>
 

以上

↑このページのトップヘ