libvlc使用起来还是很方便的,但要是自己编译就相当恶心了。最近任务需要,要重新编译Windows-32位版本,并修改MP4和AVI的部分实现加密视频的正常播放。
网上流行的编译版本为vlc-2.2.1和vlc-2.2.4,但真正编译的时候坑很多。为了方便以后要编译的人,现分享编译方法。
一:环境搭建
- Ubuntu18.04LTS-x64 (VMWare虚拟机)
- VLC:vlc-2.2.8,vlc-contrib-i686-w64-mingw32-20160218.tar.bz2
- 目标平台:Windows_Win32(交叉编译)
二:编译
2.1 编译环境
安装VMware虚拟机和Ubuntu18.04_x64。
确保虚拟机联网。
2.2 编译工具链和依赖库
sudo apt-get update
sudo apt-get install gcc-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64-tools
sudo apt-get install lua5.2 libtool automake autoconf autopoint make gettext pkg-config
sudo apt-get install qt4-dev-tools qt5-default git subversion cmake cvs
sudo apt-get install wine64-development-tools libwine-dev zip p7zip nsis bzip2
sudo apt-get install yasm ragel ant default-jdk protobuf-compiler dos2unix
运气好的话应该不会报错。(报错的话断网重连下试试)
2.3 第三方依赖库
VLC依赖第三方依赖库编码,为了方便官方已经将第三方依赖库提前编译好了。但有十分重要的问题需要注意:
- 第三方依赖库放在:http://download.videolan.org/pub/videolan/contrib/i686-w64-mingw32/;
- make prebuilt下载的是最新的第三方依赖库!例如当前VLC开发的最新版本是2.2.6,那么
make prebuilt
下载下来的vlc-contrib-i686-w64-mingw32-latest.tar.bz2
是针对2.2.6版本的第三方依赖库;而假如要编译的是2.2.1,那么make prebuilt下载下来的依赖库很有可能不匹配。而具体哪个版本对应哪个第三方依赖库,目前没有找到说明文档,如果有这方面说明还请告知; - 建议的方式是:从http://download.videolan.org/pub/videolan/contrib/i686-w64-mingw32/下载对应的第三方依赖库,而不是使用
make prebuilt
自动下载。如果版本不匹配那么编译的时候肯定会报...has different size
的错误。 - vlc-2.2.8 对应的第三方依赖库为:
vlc-contrib-i686-w64-mingw32-20160218.tar.bz2
。
依次执行以下步骤:
// 下载 vlc-2.2.8
// 解压到 $HOME/Projects/
cd vlc-2.2.8/contrib/
mkdir win32
// 下载 vlc-contrib-i686-w64-mingw32-20160218.tar.bz2
// 拷贝到 win32并重命名为 "vlc-contrib-i686-w64-mingw32-latest.tar.bz2"
cd win32/
../bootstrap --host=i686-w64-mingw32
make prebuilt
rm -f ../i686-w64-mingw32/bin/moc ../i686-w64-mingw32/bin/uic ../i686-w64-mingw32/bin/rcc
2.4 VLC编译
// 回到vlc主目录,此步执行:
cd ../../
./bootstrap
// 新建编译输出目录
mkdir win32
cd win32/
// 配置环境变量
export PKG_CONFIG_LIBDIR=$HOME/Projects/vlc-2.2.8/contrib/i686-w64-mingw32/lib/pkgconfig
// 配置编译脚本
../extras/package/win32/configure.sh --host=i686-w64-mingw32 --build=x86_64-pc-linux-gnu
配置编译脚本很容易出问题,比如 configure: error: libavcodec versions 55 and later are not supported yet
,这就是因为第三方库太新,下载的第三方库和vlc版本不匹配问题(详见2.3)。
配置编译脚本成功后继续执行:
make
make报错有:
错误1:
`duplicate section xxx has different size`
这个错误还是因为第三方库不匹配,详见2.3。
错误2:
demux/mkv/.libs/libmkv_plugin_la-matroska_segment.o: In function `ZN18matroska_segment_c15ParseSimpleTagsEPN11libmatroska12KaxTagSimpleEi':
/home/nibiru/Projects/vlc-2.2.8/win32/modules/../../extras/package/win32/../../../modules/demux/mkv/matroska_segment.cpp:322: undefined reference to `libebml::EbmlString::operator std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&() const'`
...
...
错误1由于第三方库版本不匹配,详见2.3.
分析错误2: 错误2应该是string类型的强制转换出问题了。打开 modules/demux/mkv/matroska_segment.cpp
,找到错误代码:
...
else if( MKV_IS_ID( el, KaxTagLangue ) )
{
KaxTagLangue &language = *(KaxTagLangue*) el;
language.ReadData( es.I_O(), SCOPE_ALL_DATA );
p_simple->psz_lang = strdup( string( language ).c_str());
}
很显然,KaxTagLangue
强制转换成string时候出错了,即 KaxTagLangue
没有实现string输出,或者实现的有问题。使用SourceInsight分析vlc-2.2.8源码,并没有查找到 KaxTagLangue
的定义。因为 KaxTagLangue
引自第三方库,根据错误提示 libebml::EbmlString
推测它应该由 libebml
第三方库定义。继续分析 vlc-2.2.8/contrib/i686-w64-mingw32/include/
第三方库头文件所在目录,在ebml和matroska文件夹继续查找 KaxTagLangue
:
// matroska/KaxSemantic.h
DECLARE_MKX_STRING(KaxTagLangue)
// matroska/KaxDefines.h
#define DECLARE_MKX_STRING(x) DECLARE_MKX_CONTEXT(x) \
class MATROSKA_DLL_API x : public EbmlString { \
public: x(EBML_EXTRA_PARAM); \
x(const x & ElementToClone) :EbmlString(ElementToClone) {} \
EBML_CONCRETE_CLASS(x)
// ebml/EmblString.h
/*!
\class EbmlString
\brief Handle all operations on a printable string EBML element
*/
class EBML_DLL_API EbmlString : public EbmlElement {
public:
EbmlString();
EbmlString(const std::string & aDefaultValue);
EbmlString(const EbmlString & ElementToClone);
virtual ~EbmlString() {}
virtual bool ValidateSize() const {return IsFiniteSize() && GetSize() < 0x7FFFFFFF;} // any size is possible
filepos_t RenderData(IOCallback & output, bool bForceRender, bool bWithDefault = false);
filepos_t ReadData(IOCallback & input, ScopeMode ReadFully = SCOPE_ALL_DATA);
filepos_t UpdateSize(bool bWithDefault = false, bool bForceRender = false);
EbmlString & operator=(const std::string &);
operator const std::string &() const;
EbmlString &SetValue(std::string const &NewValue);
std::string GetValue() const;
void SetDefaultValue(std::string &);
const std::string & DefaultVal() const;
bool IsDefaultValue() const {
return (DefaultISset() && Value == DefaultValue);
}
#if defined(EBML_STRICT_API)
private:
#else
protected:
#endif
std::string Value; /// The actual value of the element
std::string DefaultValue;
};
可见,KaxXXX类型强制转换string的依据是:operator const std::string &() const;
。但由于此重载不起作用,因此可以考虑在应用的时候使用 std::string GetValue() const;
将string重载替换掉,这样是没有问题的,查询 libebml
源码:
// EbmlString.cpp
EbmlString::operator const std::string &() const {return Value;}
std::string EbmlString::GetValue() const {
return Value;
}
问题2原因找到并且有了解决方法,类似的报错还有几个,将报错的string强制转换全部替换成 GetValue
方式(注意函数调用里的强制转换),继续编译。
make
快完成时报错:
/qt4.cpp:36:
./ui/open.h:14:10: fatal error: QtWidgets/QAction: No such file or directory
#include <QtWidgets/QAction>
显然,这是编译Qt-UI界面时候出现了错误,解决方法有两个:
- 修改编译器脚本
../extras/package/win32/configure.sh
,将--enable-qt
和--enable-skins2
改为--disable-qt
和--disable-skin2
; - 安装qt环境,继续编译。
这里选择方案1。
继续编译:
make
大功告成!
生成库:
make package-win-common
三:库测试
将生成的库拷贝到Windows下,写程序测试是否正常可用。
之后基于源码做一些定制修改,继续编译测试的死循环。。。
参考:
Win32Compile - VideoLAN
http://download.videolan.org/pub/videolan/contrib/i686-w64-mingw32/
http://download.videolan.org/pub/videolan/vlc/