在Windows下使用shell编译自己的FFmpeg库

前言

之前在Windows下编译过FFmpeg库,但是编译出来的DLL库不仅个数多达7个,而且库总大小高达几十兆。现经过研究,使用shell脚本根据自己的需要编译自己的FFmpeg库,不仅可以编译出来一个自己命名的DLL,而且大小可以减小到10MB以下。

1、下载

1.1、下载ffmpeg

在https://github.com/FFmpeg/FFmpeg/tree/master下载zip压缩包即可,我下载的是n6.1.1版本

1.2、下载Visual Studio

在Microsoft官网下载VS,我下载的是Visual Studio Professional 2022

1.3、下载msys2

在https://www.msys2.org/下载msys2工具,我下载的是msys2-x86_64-20240113版本

2、安装

2.1、安装ffmpeg

将zip解压至D:\workspace\build\FFmpeg-n6.1.1

2.2、安装VS2022

自行选择安装,我不习惯到C盘,选择安装到D盘

2.3、安装msys2

安装到C:\msys64;
将msys2_shell.cmd中rem set MSYS2_PATH_TYPE=inherit改为set MSYS2_PATH_TYPE=inherit,这样可以从中环境%PATH%读取变量;
再把usr\bin中link.exe改为link.exe.bak,这样可以使用VS自带link.exe进行链接。
使用x86 Native Tools Command Prompt for VS 2022输入C:\msys64\msys2_shell.cmd,打开msys2之后输入下面命令更新并安装工具:
pacman -Syu
pacman -Su
pacman -S make
pacman -S diffutils
pacman -S yasm
pacman -S nasm

3、编译

3.1、设置全局环境,包括cl.exe以及ffmpeg头文件

/* 在Path中添加cl.exe所在文件夹路径。若未找到,可以在VS的安装目录下搜索cl.exe */
D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\bin\Hostx86\x86;

/* 在系统变量中新建变量INCLUDE,添加ffmpeg、cl.exe包含头文件目录 */
D:\workspace\build\FFmpeg-n6.1.1;
D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\include;
D:\Windows Kits\10\Include\10.0.22000.0\shared;
D:\Windows Kits\10\Include\10.0.22000.0\ucrt;
D:\Windows Kits\10\Include\10.0.22000.0\um;
D:\Windows Kits\10\Include\10.0.22000.0\winrt;

/* 在系统变量中新建变量LIB,添加cl.exe库文件目录 */
D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.32215\lib\x86;
D:\Windows Kits\10\Lib\10.0.22000.0\ucrt\x86;
D:\Windows Kits\10\Lib\10.0.22000.0\um\x86;

3.2、编写source桥接文件.h和.c

编写桥接头文件myffmpeg.h

#ifndef __MY_FFMPEG_H__
#define __MY_FFMPEG_H__

#include "libavutil/mem.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/mathematics.h"
#include "libavutil/time.h"

#include "libavcodec/avcodec.h"
#include "libavcodec/packet.h"

#include "libavformat/avformat.h"

#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"

#include "libswscale/swscale.h"

#include "libswresample/swresample.h"

#include "libavdevice/avdevice.h"

#ifdef _WIN32
#define MYFFMPEG_EXPORT __declspec(dllexport)
#else
#define MYFFMPEG_EXPORT __attribute__((visibility("default")))
#endif // _WIN32

/* 自定义ffmpeg结构体 */
typedef struct MyFfmpeg {
	const AVCodec* (*avcodec_find_encoder)(enum AVCodecID id);
	AVCodecContext* (*avcodec_alloc_context3)(const AVCodec* codec);
	int (*avcodec_open2)(AVCodecContext* avctx, const AVCodec* codec, AVDictionary** options);
	/***省略***/
	
	int (*avformat_network_init)(void);
	AVFormatContext* (*avformat_alloc_context)(void);
	AVStream* (*avformat_new_stream)(AVFormatContext* s, const struct AVCodec* c);
	/***省略***/

	int (*avio_open)(AVIOContext** s, const char* url, int flags);
	int (*avio_open2)(AVIOContext** s, const char* url, int flags,
		const AVIOInterruptCB* int_cb, AVDictionary** options);
	int (*avio_closep)(AVIOContext** s);
	/***省略***/

	AVFilterInOut* (*avfilter_inout_alloc)(void);
	AVFilterGraph* (*avfilter_graph_alloc)(void);
	int (*avfilter_graph_create_filter)(AVFilterContext** filt_ctx, const AVFilter* filt,
		const char* name, const char* args, void* opaque,
		AVFilterGraph* graph_ctx);
	/***省略***/

	struct SwsContext* (*sws_getContext)(int srcW, int srcH, enum AVPixelFormat srcFormat,
		int dstW, int dstH, enum AVPixelFormat dstFormat,
		int flags, SwsFilter* srcFilter,
		SwsFilter* dstFilter, const double* param);
	int (*sws_scale)(struct SwsContext* c, const uint8_t* const srcSlice[],
		const int srcStride[], int srcSliceY, int srcSliceH,
		uint8_t* const dst[], const int dstStride[]);
	void (*sws_freeContext)(struct SwsContext* swsContext);
	/***省略***/

	int64_t (*av_get_default_channel_layout)(int nb_channels);
	AVFrame* (*av_frame_alloc)(void);
	void (*av_frame_free)(AVFrame** frame);
	/***省略***/
} MyFfmpeg;

MYFFMPEG_EXPORT MyFfmpeg* GetMyFfmpeg();

#endif

编写桥接实现myffmpeg.c

#include "myffmpeg.h"

/* 全局ffmpeg对象 */
static MyFfmpeg g_myffmpeg = {
	.avcodec_find_encoder = avcodec_find_encoder,
	.avcodec_alloc_context3 = avcodec_alloc_context3,
	.avcodec_open2 = avcodec_open2,
	/***省略***/

	.avformat_network_init = avformat_network_init,
	.avformat_alloc_context = avformat_alloc_context,
	.avformat_new_stream = avformat_new_stream,
	/***省略***/

	.avio_open = avio_open,
	.avio_open2 = avio_open2,
	.avio_closep = avio_closep,
	/***省略***/

	.avfilter_inout_alloc = avfilter_inout_alloc,
	.avfilter_graph_alloc = avfilter_graph_alloc,
	.avfilter_graph_create_filter = avfilter_graph_create_filter,
	/***省略***/

	.sws_getContext = sws_getContext,
	.sws_scale = sws_scale,
	.sws_freeContext = sws_freeContext,
	/***省略***/

	.av_get_default_channel_layout = av_get_default_channel_layout,
	.av_frame_alloc = av_frame_alloc,
	.av_frame_free = av_frame_free,
	/***省略***/
};

MyFfmpeg* GetMyFfmpeg()
{
	return &g_myffmpeg;
}

3.3、编写shell脚本

编写脚本build_myffmpeg.sh

cur_path=$(cd `dirname $0`;pwd)
echo ${cur_path}

rm -f -r ffmpeg_build_win32
mkdir ffmpeg_build_win32

make clean
make distclean

./configure --prefix=./ffmpeg_build_win32 --target-os=win32 --arch=i386 --toolchain=msvc --enable-small --enable-static --disable-gpl --disable-ffmpeg --disable-ffprobe --disable-ffplay --disable-programs --disable-doc --disable-encoders --disable-decoders --disable-muxers --disable-demuxers --disable-parsers --disable-protocols --enable-filters --enable-bsfs --enable-encoder=aac,bmp,flv,gif,h264,h264_mf,hevc,hevc_mf,mjpeg,mp3_mf,mpeg4,opus,png,tiff --enable-decoder=aac,bmp,flv,gif,h264,hevc,mjpeg,mp3,mpeg4,opus,png,tiff --enable-muxer=avi,flv,gif,h264,hevc,hls,m4v,mjpeg,mov,mp3,mp4,ogg,opus,wav --enable-demuxer=aac,avi,flv,gif,h264,hevc,hls,m4v,mjpeg,mov,mp3,mp4,ogg,wav --enable-parser=aac,bmp,flac,gif,h264,hevc,mjpeg,opus,png --enable-protocol=data,fd,file,ftp,hls,http,https,pipe,rtmp,rtp,srtp,tcp,udp

make -j10
make install

cl.exe -c -GS -nologo -Fo:ffmpeg_build_win32/myffmpeg.obj source/myffmpeg.c -Iffmpeg_build_win32/include

link.exe -DLL -DEBUG -nologo -opt:ref -opt:icf -out:ffmpeg_build_win32/myffmpeg.dll ffmpeg_build_win32/myffmpeg.obj -LIBPATH:ffmpeg_build_win32/lib libavutil.a libavcodec.a libavformat.a  libavfilter.a libswscale.a libswresample.a libavdevice.a kernel32.lib user32.lib ole32.lib shell32.lib Bcrypt.lib ws2_32.lib Secur32.lib Strmiids.lib Mfuuid.lib Mfplat.lib

3.4、用msys2编译

拷贝.h和.c到D:\workspace\build\FFmpeg-n6.1.1\source中,再拷贝.sh到D:\workspace\build\FFmpeg-n6.1.1中。
在x86 Native Tools Command Prompt for VS 2022输入C:\msys64\msys2_shell.cmd,打开msys2之后输入D:\workspace\build\FFmpeg-n6.1.1,再输入sh build_myffmpeg.sh运行脚本开始编译……

最终生成了对应的include、lib文件夹以及myffmpeg.dll、myffmpeg.lib文件,即编译成功
在这里插入图片描述

4、使用

写个简单的test工程使用下新编译出来的myffmpeg库:

4.1、拷贝库文件

将编译出来的myffmpeg头文件、lib、dll库文件拷贝到工程对应的inc、lib、bin目录下
在这里插入图片描述
需要注意的是除了拷贝myffmpeg.h外,需要将编译产生的ffmpeg头文件include目录拷贝过来
在这里插入图片描述

4.2、配置工程属性

在工程中添加头文件目录,找到C/C++,然后按图所示
在这里插入图片描述
在工程中添加LIB库目录和文件信息,找到链接器,接着按图所示
在这里插入图片描述
在这里插入图片描述

4.3、编译TEST工程

简单写了几句,加载myffmpeg成功并成功运行(需要将myffmpeg.dll拷贝到test.exe目录下),说明编译出来的库可用,大功告成!

#include <iostream>

extern "C" {
#include "myffmpeg.h"
}

using namespace std;

#define MY_FFMPEG() (*GetMyFfmpeg())

int main()
{
    int result = MY_FFMPEG().avformat_network_init();
    cout << "init network ret=" << result << endl;

    return 0;
}
  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值