window下用mingw编译 x264

最近尝试在windows系统下,交叉编译了x264源码。参考了一些网友们的经验。由于工具一直在变,网上的教程大部分比较老了,所以把我踩过的坑写下来,回馈网友们的帮助。

1.  为什么要交叉编译

x264用的c语言是c99版本的,然而VS对C99语法的支持并不好,所以没有办法直接用VS编译。x264官方代码从2009年开始放弃了支持VS。 

但是可以用交叉编译工具,生成windows系统能用的exe,和VS能用的动态库。

步骤如下:

2.1  下载交叉编译工具 mingw+msys

https://sourceforge.net/projects/mingw/files/latest/download?source=files

下载后安装。

安装后会有一个 MinGW Installation Manager程序,用这个程序安装Basic Setup下的mingw-developer-toolkit、mingw32-base、mingw32-gcc-g++、msys-base工具集。


2.2 安装nasm 

 X264 自从2015年以后,默认的汇编器从 yasm 改成了nasm, 下一步需要下载nasm.exe

https://www.nasm.us/

找到MinGW的安装目录,把下载后的nasm.exe 放在MinGW\bin 目录下

 

2.3 下载最新的x264

https://www.videolan.org/developers/x264.html

下载源代码放在 msys 的目录里面: 

for example: MinGW\msys\1.0\home\yourname\


2.4 打开msys 

进入MinGW\msys\1.0,执行msys.bat, 会有一个类似bash的命令行界面:

 

一些教程说需要编辑 msys.bat,实测并不需要。

2.5 编译源码

进入 x264源码目录,执行

./configure  --enable-shared

--enable-shared 可以配置生成dll文件。

然后执行 make

在源码目录下会产生4个文件:

    x264.exe:命令行程序,可以运行测试一下:

    Windows 下打开一个cmd窗口, cd 到这个目录, 运行 x264.exe --version

    libx264-155.dll:动态库dll文件,其中155是版本。

    libx264.dll.a:将文件名字修改为libx264-155.lib,它是dll文件的引导lib。修改完名字之后在VC工程中就可以作为“附加依赖项”了。

    libx264.a:这个是linux的静态库。

在VC工程使用 .lib 和 .dll ,会提示缺少 libgcc_s_dw2-1.dll,从mingw搜索拷贝过去就行了。

 2.6 附简单的测试代码

#include <iostream>
#include <string>
#include "stdint.h"

extern "C"{
#include "x264.h"
#include "x264_config.h"

};
using namespace std;
int main()
{
    x264_param_t param;
    x264_param_default(&param);
    getchar();
    return 0;

}

 2.7 库api用法例子

源码中也有一个 example.c , 演示了libx264 api的用法。

在VS新建工程,添加上述步骤生成的 .dll, .lib文件和必要的.h 文件,

然后将example.c 复制到visual studio中试运行。

由于这个文件也用了VS不支持的C99语法,需要把所有goto去掉,把所有变量声明放在代码块开始的地方。

这是我改后的一小段代码:

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#ifdef _WIN32
#include <io.h>       /* _setmode() */
#include <fcntl.h>    /* _O_BINARY */
#endif

#include <stdint.h>
#include <stdio.h>
extern "C" {
	#include <x264.h>
}

#include <chrono>
#include <iostream>

#define FAIL_IF_ERROR( cond, ... )\
do\
{\
    if( cond )\
    {\
        fprintf( stderr, __VA_ARGS__ );\
        return -1;\
    }\
} while( 0 )


int main(int argc, char **argv)
{
	int width, height;
	x264_param_t param;
	x264_picture_t pic;
	x264_picture_t pic_out;
	x264_t *h;
	int i_frame = 0;
	int i_frame_size;
	x264_nal_t *nal;
	int i_nal;

	FILE * i_file;
	FILE * o_file;

	int luma_size;
	int chroma_size;
	decltype(std::chrono::high_resolution_clock::now()) t_start, t_end;


	FAIL_IF_ERROR(!(argc > 3), "Example usage: example 352x288 input.yuv output.h264\n");
	FAIL_IF_ERROR(2 != sscanf(argv[1], "%dx%d", &width, &height), "resolution not specified or incorrect\n");

	char * in_file_name = argv[2];
	char * out_file_name = argv[3];


	i_file = fopen(in_file_name, "rb");
	FAIL_IF_ERROR(!i_file, "can't open input file");
	o_file = fopen(out_file_name, "wb");
	FAIL_IF_ERROR(!o_file, "can't open output file");

	/* Get default params for preset/tuning */
	if (x264_param_default_preset(¶m, "medium", NULL) < 0)
		return -1;

	/* Configure non-default params */
	param.i_bitdepth = 8;
	param.i_csp = X264_CSP_I420;
	param.i_width = width;
	param.i_height = height;
	param.b_vfr_input = 0;
	param.b_repeat_headers = 1;
	param.b_annexb = 1;


	/* Apply profile restrictions. */
	if (x264_param_apply_profile(¶m, "high") < 0)
		return -1;

	if (x264_picture_alloc(&pic, param.i_csp, param.i_width, param.i_height) < 0)
		return -1;

	h = x264_encoder_open(¶m);
	if (!h) {
		x264_picture_clean(&pic);
		return -1;
	}
	luma_size = width * height;
	chroma_size = luma_size / 4;
	t_start = std::chrono::high_resolution_clock::now();

	/* Encode frames */
	for (;; i_frame++)
	{
		/* Read input frame */
		if (fread(pic.img.plane[0], 1, luma_size, i_file) != luma_size)
			break;
		if (fread(pic.img.plane[1], 1, chroma_size, i_file) != chroma_size)
			break;
		if (fread(pic.img.plane[2], 1, chroma_size, i_file) != chroma_size)
			break;

		pic.i_pts = i_frame;
		i_frame_size = x264_encoder_encode(h, &nal, &i_nal, &pic, &pic_out);
		if (i_frame_size < 0) {
			x264_encoder_close(h);
			x264_picture_clean(&pic);
			return -1;
		}
		else if (i_frame_size)
		{
			if (!fwrite(nal->p_payload, i_frame_size, 1, o_file)) {
				x264_encoder_close(h);
				x264_picture_clean(&pic);
				return -1;
			}
		}
	}
	/* Flush delayed frames */
	while (x264_encoder_delayed_frames(h))
	{
		i_frame_size = x264_encoder_encode(h, &nal, &i_nal, NULL, &pic_out);
		if (i_frame_size < 0) {
			x264_encoder_close(h);
			x264_picture_clean(&pic);
			return -1;
		}
		else if (i_frame_size)
		{
			if (!fwrite(nal->p_payload, i_frame_size, 1, o_file)) {
				x264_encoder_close(h);
				x264_picture_clean(&pic);
				return -1;
			}
		}
	}
	t_end = std::chrono::high_resolution_clock::now();
	auto int_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t_end - t_start);

	x264_encoder_close(h);
	x264_picture_clean(&pic);
	std::cout << std::endl;
	std::cout << "time in ms: " << int_ms.count() << "; frames: " << i_frame << std::endl;
	std::cout << "frame per seconde " << i_frame * 1000 / int_ms.count() << std::endl;
	return 0;

}


Reference:

 https://blog.csdn.net/aflyeaglenku/article/details/47146863

 https://blog.csdn.net/chinabinlang/article/details/26452011

 https://www.jianshu.com/p/fa42abce1ea7

 https://my.oschina.net/u/1866382/blog/406068


 3. 64位x264

    默认编译出来是32位的,下一步尝试交叉编译64位的x264。


 4. Visual Studio原生编译x264

   有网友把x264改成兼容VS的 c语言规则,并制作了完整的VS工程。

   https://github.com/ShiftMediaProject/x264

   可以在VS下原生编译。

   改c语言版本的过程没有想象中那么麻烦,见作者博客:

    http://siliconandlithium.blogspot.ca/2014/03/building-x264-on-windows-with-visual.html


5. 性能对比

    无论是交叉编译的版本(32位),还是VS编译的版本(64位),性能都比x264官方编译对应版本略逊。

    哪位大神如果知道原因的话,欢迎交流。


猜你喜欢

转载自blog.csdn.net/soulmate_scut/article/details/80180092