序
ffmpeg编译后执行可执行文件会提示各组件库的版本信息,这些版本信息从何而来是本文关注的重点
1、ffmpeg版本信息一探
1.1 windows下示例
(1)假设你在windows下编译了ffmpeg,执行ffmpeg.exe便会出现下图所示的信息,图中列出了ffmpeg各组件的版本信息;
(2)版本信息从何而来?
打开ffmpeg.c文件,main函数调用了 ‘show_banner(argc, argv, options);
’ 此函数原理很简单,调用了一些现有的宏,这些宏在一些头文件中,例如’libavcodec/version.h
’ 中,就含有某个宏表示libavcodec的版本信息;
(3)windows下编译的动态库命名带有版本信息(如’avdevice-57.dll,57为版本
)又从何而来?
1>、在ffmpeg的早期版本中,如ffmpeg2.5,在./configure之后会产生config,mak文件,ffmpeg各组件的版本信息就在此文件中,如’libavcodec_VERSION_MAJOR=56
,脚本编译动态库的时候,动态库的名字会加上此宏。
2>、在ffmpeg比较新的版本中,如ffmpeg3.4,在./configure之后也会产生一些mak文件,譬如 ffbuild/ 目录下的library.mak文件,其中的’-include $(SUBDIR)lib$(NAME).version
其实是将各组件目录下含版本信息的文件例如’libavcodec/libavcodec.version
包含进来,接着使用’LIBMAJOR := $(lib$(NAME)_VERSION_MAJOR)
读取版本信息;然后在链接的时候(’$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver
)生成类似’avdevice-57.dll
的命名;
2、通过动态库加载的方式获取版本号
2.1 新建名为symbol.c的文件,内容为:
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
//#include <wtypes.h>
//#include <winbase.h>
#else
#include <dlfcn.h>
#endif
//将版本信息转换成具体的数字
//#define AV_VERSION_INT(a,b,c) ((a)<<16 | (b)<<8 | (c))
void transport_version(unsigned int version_num, char *pname)
{
int version_major, version_minor, version_micro;
version_major = (version_num >> 16) & 0xff;
version_minor = (version_num >> 8) & 0xff;
version_micro = (version_num) & 0xff;
printf("%s: %d, %d, %d\n", pname, version_major, version_minor, version_micro);
}
//需要从so或dll文件中导出的函数声明
typedef unsigned (*avcodec_version_fuc)(void);
//动态库名字加路径
char *psoavutil = "libavutil.so";
char *psoavcodec = "libavcodec.so";
char *psoavformat = "libavformat.so";
char *psoavdevice = "libavdevice.so";
char *psoavfilter = "libavfilter.so";
char *psoavscale = "libswscale.so";
char *pdllavutil = "libavutil.dll";
char *pdllavcodec = "libavcodec.dll";
char *pdllavformat = "libavformat.dll";
char *pdllavdevice = "libavdevice.dll";
char *pdllavfilter = "libavfilter.dll";
char *pdllavscale = "libswscale.dll";
#ifdef WIN32
void get_lib_version(char *pdllname, char *function)
{
HINSTANCE pdllHandle;
avcodec_version_fuc avcodec_version = NULL;//函数指针
pdllHandle = LoadLibrary(pdllname);
if (pdllHandle == NULL){
printf("Cant open %s\n", pdllHandle);
return;
}
avcodec_version = (avcodec_version_fuc)GetProcAddress(pdllHandle, function);
if(avcodec_version == NULL){
printf("Cant load symbol %s\n", function);
FreeLibrary(pdllHandle);
return;
}
transport_version(avcodec_version(),function);
//关闭so文件
FreeLibrary(pdllHandle);
}
void get_ffmpeg_version(char *psoname, char *function)
{
HINSTANCE pdllHandle;
char *avcodec_version = NULL;//函数指针
pdllHandle = LoadLibrary(pdllname);
if (pdllHandle == NULL){
printf("Cant open %s\n", pdllHandle);
return;
}
avcodec_version = (avcodec_version_fuc)GetProcAddress(pdllHandle, function);
if(avcodec_version == NULL){
printf("Cant load symbol %s\n", function);
FreeLibrary(pdllHandle);
return;
}
printf("%s\n", avcodec_version);
//关闭so文件
FreeLibrary(pdllHandle);
}
//windows动态加载方法
void main(int argc, char *argv[])
{
get_lib_version(pdllavutil, "avutil_version");
get_lib_version(pdllavcodec, "avcodec_version");
get_lib_version(pdllavformat, "avformat_version");
get_lib_version(pdllavdevice, "avdevice_version");
get_lib_version(pdllavfilter, "avfilter_version");
get_lib_version(pdllavscale, "swscale_version");
get_ffmpeg_version(pdllavcodec, "av_codec_ffversion");
}
#else
void get_lib_version(char *psoname, char *function)
{
void *psoHandle;
avcodec_version_fuc avcodec_version = NULL;//函数指针
psoHandle = dlopen(psoname, RTLD_NOW | RTLD_GLOBAL);
if (psoHandle == NULL){
printf("Cant open %s\n", psoHandle);
return;
}
avcodec_version = dlsym(psoHandle, function);
if(avcodec_version == NULL){
printf("Cant load symbol %s\n", function);
dlclose(psoHandle);
return;
}
transport_version(avcodec_version(),function);
//关闭so文件
dlclose(psoHandle);
}
void get_ffmpeg_version(char *psoname, char *function)
{
void *psoHandle;
char *avcodec_version = NULL;//函数指针
psoHandle = dlopen(psoname, RTLD_NOW | RTLD_GLOBAL);
if (psoHandle == NULL){
printf("Cant open %s\n", psoHandle);
return;
}
avcodec_version = dlsym(psoHandle, function);
if(avcodec_version == NULL){
printf("Cant load symbol %s\n", function);
dlclose(psoHandle);
return;
}
printf("%s\n", avcodec_version);
//关闭so文件
dlclose(psoHandle);
}
//linux动态加载方法
void main(int argc, char *argv[])
{
get_lib_version(psoavutil, "avutil_version");
get_lib_version(psoavcodec, "avcodec_version");
get_lib_version(psoavformat, "avformat_version");
get_lib_version(psoavdevice, "avdevice_version");
get_lib_version(psoavfilter, "avfilter_version");
get_lib_version(psoavscale, "swscale_version");
get_ffmpeg_version(psoavcodec, "av_codec_ffversion");
}
#endif
2.2 新建Linux下的makefile脚本(Makefile)
src = $(wildcard *.c)
obj = $(src:.c:.o)
CC = gcc
LDFALGS = -lm -ldl
demo:$(obj)
$(CC) -o $@ $^ $(LDFALGS)
.PHONY:clean
clean:
rm -f $(obj) demo
编译方法,将.c代码跟makefile放在同一路径下,之后make就行
2.3 新建windows的makefile脚本(Makefile.vc)
src = $(wildcard *.c)
obj = $(src:.c:.o)
CC = cl
LD = link
LDFALGS = -debug
CFLAGS = -DWIN32
.PHONY: all
all:clean demo.exe
demo.exe:$(obj)
$(LD) -libpath:./ $(LDFALGS) -PDB:./demo.pdb $(obj) -debug -out:./$@
%.o:%.c
$(CC) $(CFLAGS) -Fo$@ -c $<
.PHONY:clean
clean:
rm -f $(obj) demo.exe
编译方法,将.c代码跟Makefile.vc放在同一路径下,之后make -f Makefile.vc就行
动态库加载的代码参考1:https://blog.csdn.net/eydwyz/article/details/74932628
动态库加载的代码参考2:https://www.cnblogs.com/marblemm/p/7804056.html