当前位置:网站首页>重新配置chrome中ffmpeg插件
重新配置chrome中ffmpeg插件
2022-08-04 22:04:00 【HUI的技術筆記】
FFmpegDemuxer
我们从demux开始说起,Chrome中非MSE源都是走的ffmpeg_demuxer,具体实现是在src/media/filters/ffmpeg_demuxer.cc里面进行的。
ffmpeg_demuxer先借助buffer数据初始化一个format_context,记录视频格式信息,然后调avformat_find_stream_info得到所有的streams,一个stream包含一个track,循环streams,根据codec_id区分audio、video、text三种track,记录每种track的数量,设置播放时长duration,用fist_pts初始化播放开始时间start_time。
同时实例化一个DemuxerStream对象,这个对象会记录视频宽高、是否有旋转角度等,初始化audio_config和video_config,给解码的时候使用。
这里面的每一步几乎都是通过PostTask进行的,即把函数当作一个任务抛给media线程处理,同时传递一个处理完成的回调函数。如果其中有一步挂了就不会进行下一步,例如遇到不支持的容器格式,在第一步初始化就会失败,就不会调回调函数往下走了。
FFmpegVideoDecoder
FFmpegVideoDecoder在编译的时候配置了下面几个参数后,编译出来的chrome就支持ffmpeg解码,默认是软解。

如图,FFmpegVideoDecoder的结构很简单,在Chrome的框架下,实现了Decode和onNewFrame函数,Decode是将DecodeBuffer类型的数据送给FFmpegDecodingLoop解码,FFmpegDecodingLoop中会创建AVPacket,获取解码后的AVFrame并且完成AVFrame到chrome的VideoFrame的数据转移,最后通过frame_ready_cb(onnewFrame)回调,将解码的数据送给render。
下面是编译ffmpeg的参数:
is_component_ffmpeg = true
media_use_ffmpeg = true
ffmpeg_branding = "Chrome"
ffmpeg v4l2m2m
开始这个探索的背景是,在我们的平台上ffmpeg v4l2m2m是可以直接使用的,所以就想在Chrome中也能用v4l2m2m插件走硬解码,这里先忽略硬显示问题以及render和GPU线程在使用hardware decoder的限制,单纯从技术角度探讨下可行性。
add configure
通过阅读代码,发现ffmpeg中V4l2m2m默认是没有启用的,在Chrome中ffmpeg的源码是在third_party/ffmpeg/目录下,但是ffmpeg的编译是由third_party/ffmpeg/BUILD.gn组织的,在这个文件的开头,首先import了一个ffmpeg_generated.gni,这个文件也才是ffmpeg编译真正的代码组织文件。
在third_party/ffmpeg/ffmpeg_generated.gni中,首先会看到NOTE: this file is autogenerated by ffmpeg/chromium/scripts/generate_gn.py这一行注释,看来这个文件是自动生成的。从生成的代码中发现不同平台编译引用的文件是不完全相同的。
这个以codec_list.c文件来看就可以很清楚。
在third_party/ffmpeg/libavcodec/allcodecs.c中codec_list.c是被include进来的,同时在代码树中可以看到多个codec_list.c文件:
#if CONFIG_OSSFUZZ
const FFCodec * codec_list[] = {
NULL,
NULL,
NULL
};
#else
#include "libavcodec/codec_list.c"
#endif
static AVOnce av_codec_static_init = AV_ONCE_INIT;
static void av_codec_init_static(void)
{
for (int i = 0; codec_list[i]; i++) {
if (codec_list[i]->init_static_data)
codec_list[i]->init_static_data((FFCodec*)codec_list[i]);
}
}
这里列出来linux平台不同ABI对应的文件:
third_party/ffmpeg/chromium/config/Chrome/linux/x64/libavcodec/codec_list.c
third_party/ffmpeg/chromium/config/Chrome/linux/arm/libavcodec/codec_list.c
third_party/ffmpeg/chromium/config/Chrome/linux/ia32/libavcodec/codec_list.c
third_party/ffmpeg/chromium/config/Chrome/linux/arm64/libavcodec/codec_list.c
实际上还有很多,如下,以arm/libavcodec/codec_list.c为例,默认只有这么几个codec列表:
static const FFCodec * const codec_list[] = {
&ff_h264_decoder,
&ff_theora_decoder,
&ff_vp3_decoder,
&ff_vp8_decoder,
&ff_aac_decoder,
&ff_flac_decoder,
&ff_mp3_decoder,
&ff_vorbis_decoder,
&ff_pcm_alaw_decoder,
&ff_pcm_f32le_decoder,
&ff_pcm_mulaw_decoder,
&ff_pcm_s16be_decoder,
&ff_pcm_s16le_decoder,
&ff_pcm_s24be_decoder,
&ff_pcm_s24le_decoder,
&ff_pcm_s32le_decoder,
&ff_pcm_u8_decoder,
&ff_libopus_decoder,
NULL };
如果只是单纯的调试,只要找对了平台和ABI对应的文件,直接修改这个也是可以的,但是如果是整体编译,这样改肯定不行,交叉编译需要arm和ia32对应的代码一致才可以,这就是后面要说的怎么自动生成这个文件。
代码生成
回到third_party/ffmpeg/chromium/scripts/build_ffmpeg.py,如果要重新配置ffmpeg的组件,直接修改build_ffmpeg.py是可以的,当然可以不该,直接传递参数给build_ffmpeg.py是可以的。
先把需要传递的参数写出来:
--enable-v4l2-m2m --enable-swscale \
--enable-decoder=h263_v4l2m2m,h264_v4l2m2m,hevc_v4l2m2m,mpeg1_v4l2m2m,mpeg2_v4l2m2m,vp8_v4l2m2m,vp9_v4l2m2m \
--enable-filter=h264_mp4toannexb,hevc_mp4toannexb \
--enable-demuxer=mpegts,flv,matroska
下面是使用build_ffmpeg.py脚本的过程:
调用ffmpeg的代码如果使用到没有启用的部分,就需要重新生成ffmpeg_generated.gni文件,才能完成编译,最后要生产arm和
86的libffmpeg.so
更新、生成arm-neon的相关的文件
export PATH=`pwd`/third_party/llvm-build/Release+Asserts/bin:$PATH
./build/linux/sysroot_scripts/install-sysroot.py --arch=arm
cd ./third_party/ffmpeg/
./chromium/scripts/build_ffmpeg.py linux arm-neon --branding Chrome \
-- --enable-v4l2-m2m --enable-swscale \
--enable-decoder=h263_v4l2m2m,h264_v4l2m2m,hevc_v4l2m2m,mpeg1_v4l2m2m,mpeg2_v4l2m2m,vp8_v4l2m2m,vp9_v4l2m2m \
--enable-filter=h264_mp4toannexb,hevc_mp4toannexb \
--enable-demuxer=mpegts,flv,matroska
./chromium/scripts/copy_config.sh
./chromium/scripts/generate_gn.py
cd ../../
更新、生成x86的相关的文件
export PATH=`pwd`/third_party/llvm-build/Release+Asserts/bin:$PATH
./build/linux/sysroot_scripts/install-sysroot.py --arch=i386
cd ./third_party/ffmpeg/
./chromium/scripts/build_ffmpeg.py linux ia32 --branding Chrome \
-- --enable-v4l2-m2m --enable-swscale \
--enable-decoder=h263_v4l2m2m,h264_v4l2m2m,hevc_v4l2m2m,mpeg1_v4l2m2m,mpeg2_v4l2m2m,vp8_v4l2m2m,vp9_v4l2m2m \
--enable-filter=h264_mp4toannexb,hevc_mp4toannexb \
--enable-demuxer=mpegts,flv,matroska
./chromium/scripts/copy_config.sh
./chromium/scripts/generate_gn.py
cd ../../
编译
export PATH="$PATH:/home/hui/chrome/depot_tools"
gn gen out/default/
autoninja -C out/default/ chrome -v
编译错误记录
lld: error: undefined symbol问题处理
ld.lld: error: undefined symbol: avcodec_free_context
>>> referenced by ffmpeg_audio_decoder.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-49CB027A656D6EFA991374D541CC87AA4FC1D312:(media::FFmpegAudioDecoder::~FFmpegAudioDecoder())
>>> referenced by ffmpeg_audio_decoder.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-49CB027A656D6EFA991374D541CC87AA4FC1D312:(media::FFmpegAudioDecoder::~FFmpegAudioDecoder())
>>> referenced by ffmpeg_audio_decoder.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-49CB027A656D6EFA991374D541CC87AA4FC1D312:(media::FFmpegAudioDecoder::ConfigureDecoder(media::AudioDecoderConfig const&))
>>> referenced 11 more times
先检查ffmpeg.sigs文件中是否有定义,如果有,删除out/default/clang_x86_v8_arm/obj/third_party/ffmpeg/ffmpeg_internal/目录下文件,重新编译(autoninja -C out/default/ chrome -v)。
rm out/default/clang_x86_v8_arm/obj/third_party/ffmpeg/ffmpeg_internal/*
比如添加了swscale库之后:
ld.lld: error: undefined symbol: sws_getContext
>>> referenced by ffmpeg_decoding_loop.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-601B86BFA7603203EE89754C3E35196FBCC0AE0E:(media::FFmpegDecodingLoop::ConvertToI420(AVFrame*, AVFrame*))
ld.lld: error: undefined symbol: sws_scale
>>> referenced by ffmpeg_decoding_loop.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-601B86BFA7603203EE89754C3E35196FBCC0AE0E:(media::FFmpegDecodingLoop::ConvertToI420(AVFrame*, AVFrame*))
ld.lld: error: undefined symbol: sws_freeContext
>>> referenced by ffmpeg_decoding_loop.cc
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-601B86BFA7603203EE89754C3E35196FBCC0AE0E:(media::FFmpegDecodingLoop::ConvertToI420(AVFrame*, AVFrame*))
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
需要更新./third_party/ffmpeg/chromium/ffmpeg.sigs文件,添加:
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 attribute_align_arg 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(SwsContext *c);
recompile with -fPIC
ld.lld: error: relocation R_386_32 cannot be used against local symbol; recompile with -fPIC
>>> defined in clang_x86_v8_arm/thinlto-cache/llvmcache-FE528CDEC76E847EC1A72B262C147253194FC80C
>>> referenced by hscale_fast_bilinear_simd.c
>>> clang_x86_v8_arm/thinlto-cache/llvmcache-FE528CDEC76E847EC1A72B262C147253194FC80C:(ff_init_hscaler_mmxext)
增加–enable-pic重新生成ffmpeg_generated.gni:
# --enable-pic
./build/linux/sysroot_scripts/install-sysroot.py --arch=i386
cd ./third_party/ffmpeg/
##--disable-x86asm
./chromium/scripts/build_ffmpeg.py linux ia32 --branding Chrome \
-- --enable-v4l2-m2m --enable-swscale --disable-x86asm --enable-pic \
--enable-decoder=h263_v4l2m2m,h264_v4l2m2m,hevc_v4l2m2m,mpeg1_v4l2m2m,mpeg2_v4l2m2m,vp8_v4l2m2m,vp9_v4l2m2m \
--enable-filter=h264_mp4toannexb,hevc_mp4toannexb \
--enable-demuxer=mpegts,flv,matroska
./chromium/scripts/copy_config.sh
./chromium/scripts/generate_gn.py
再次编译,验证还是解决不了这个错误。
在./chromium/scripts/build_ffmpeg.py中增加参数--disable-x86asm解决不了output.asm找不到的问题,看了下output.asm里面直接是一句include,所以拷贝third_party/ffmpeg/libswscale/x86/autorename_libswscale_x86_output.asm到output.asm编译通过。
# ../../third_party/ffmpeg/libswscale/x86/autorename_libswscale_x86_output.asm:2: \
error: unable to open include file `output.asm': No such file or directory
看了下output.asm文件存在,autorename_libswscale_x86_output.asm直接include了output.asm,不知道为什么会报错,但是直接复制为autorename_libswscale_x86_output.asm,这个文件就解决了:
cp third_party/ffmpeg/libswscale/x86/output.asm \
third_party/ffmpeg/libswscale/x86/autorename_libswscale_x86_output.asm
–disable-x86asm是不行的,前面的fpic可能就是这个引起的,最后总结下,前面这部分是试过无数次之后才得以编译通过,就是要保证这个build_ffmpeg.py后面的参数在不同arch一定要一样,不然碰到的问题是没完没了的。
参考链接
边栏推荐
猜你喜欢
随机推荐
CPU、内存、显卡等硬件因素也影响着你的深度学习模型性能
Webmine Webpage Mining Trojan Analysis and Disposal
The upgrade and transformation plan of the fortress machine for medium and large commercial banks!Must see!
如何为Web3.0世界启动完美的DAO
numpy关于两个array叠加操作
Develop your own text recognition application with Tesseract
Altium Designer 19.1.18 - 画多边形铜皮挖空时,针对光标胡乱捕获的解决方法
VSCode - common shortcut keys (continuous recording
立即升级!WPS Office 出现 0day 高危安全漏洞:可完全接管系统,官方推出紧急更新
LayaBox---TypeScript---structure
torch单机多卡和多机多卡训练
MySQL查询为啥慢了?
ES6高级-async的用法
Go----Go 语言基础之标识符、关键字、命名规范、变量、常量
开源一夏 | 云服务器ECS安装Mysql、JDK、RocketMQ
input事件中文触发多次问题研究php DEBUG
论文解读(PPNP)《Predict then Propagate: Graph Neural Networks meet Personalized PageRank》
【组成原理 六 存储器类型】
[Linear Algebra 02] 2 interpretations of AX=b and 5 perspectives of matrix multiplication
字节跳动秋招提前批高频面试问题汇总!(内附答案!)



![[QT] Implementation of callback function](/img/df/500ae0625eccf83f39d9a8ddfd3533.png)




