安卓mediasoup webrtc h264 软编解码相关源码分析
Posted 清霜之辰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓mediasoup webrtc h264 软编解码相关源码分析相关的知识,希望对你有一定的参考价值。
文章目录
安卓mediasoup webrtc h264 软编解码相关源码分析
本文首发地址 https://blog.csdn.net/CSqingchen/article/details/120218923
最新更新地址 https://gitee.com/chenjim/chenjimblog
本文基于libmediasoupclient 3.2.0 和 webrtc branch-heads/4147(m84)
本文得熟悉相关基础,参考 文1 和 文2
mediasoup H264 支持
-
打开
rtc_use_h264
在webrtc.gni
中可以看到如下,也就是安卓默认不支持 h264
rtc_use_h264 = proprietary_codecs && !is_android && !is_ios && !(is_win && !is_clang)
可以将此处改为true
,也可以带上编译参数'rtc_use_h264=true
,如下:
./tools_webrtc/android/build_aar.py --extra-gn-args 'rtc_use_h264=true'
-
mediasoup-demo-android 的 forceH264
通过代码我们看到,这个参数只在UrlFactory.java
中拼接地址使用
正常情况 如果 url 中 有forceH264=true
, 就应该采用H264编码
如浏览器输入https://v3demo.mediasoup.org/?forceH264=true&roomId=123456
输出的视频就是H264
(安卓默认显示黑屏,缺少H264解码器,后文解决)
但是mediasoup-demo-android
菜单勾选forceH264
了还是VP8
编码,算是个BUG …
安卓 webrtc 视频采集流程源码分析
webrtc针对视频采集对外主要提供的是VideoCapturer接口,实现类有ScreenCapturerAndroid、FileVideoCapturer和CameraCapturer,分别表示屏幕、文件、摄像头三种不同的视频来源,因为android系统先后提供了camera1.0和camera2.0接口,因此CameraCapturer又用Camera1Capturer和Camera2Capturer两个子类分别表示。
主要类图
视频采集和分发流程如下图
更多细节可以参考原文 webrtc源码分析之视频采集之一, 感谢 Jimmy2012
安卓 mediasoup 为啥没有使用H264硬编解码
- 安卓 mediasoup Java层 CreateMediaEngine 如下
mediasoup-demo-android\\app\\src\\main\\java\\org\\mediasoup\\droid\\lib\\PeerConnectionUtils.java
中
VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory( mEglBase.getEglBaseContext(), true /* enableIntelVp8Encoder */, true);
VideoDecoderFactory decoderFactory = new DefaultVideoDecoderFactory(mEglBase.getEglBaseContext());
mPeerConnectionFactory = builder.setAudioDeviceModule(adm)
.setVideoEncoderFactory(encoderFactory)
.setVideoDecoderFactory(decoderFactory)
.createPeerConnectionFactory();
大致跟原生的 webrtc (AppRTCDemo\\app\\src\\main\\java\\org\\appspot\\apprtc\\PeerConnectionClient.java
)相同,原生的支持硬编解码,
其中 .createPeerConnectionFactory();
相关流程如下
–> createPeerConnectionFactory()
–> JNI_PeerConnectionFactory_CreatePeerConnectionFactory(…) (webrtc/src/sdk/android/src/jni/pc/peer_connection_factory.cc)
–> CreatePeerConnectionFactoryForJava(…) (webrtc/src/sdk/android/src/jni/pc/peer_connection_factory.cc) 部分代码如下
media_dependencies.task_queue_factory = dependencies.task_queue_factory.get();
media_dependencies.adm = std::move(audio_device_module);
media_dependencies.audio_encoder_factory = std::move(audio_encoder_factory);
media_dependencies.audio_decoder_factory = std::move(audio_decoder_factory);
media_dependencies.audio_processing = std::move(audio_processor);
media_dependencies.video_encoder_factory = absl::WrapUnique(CreateVideoEncoderFactory(jni, jencoder_factory));
media_dependencies.video_decoder_factory = absl::WrapUnique(CreateVideoDecoderFactory(jni, jdecoder_factory));
dependencies.media_engine = cricket::CreateMediaEngine(std::move(media_dependencies));
- 安装 mediasoup Native 层 CreateMediaEngine 如下
Handler::GetNativeRtpCapabilities (libmediasoupclient/src/Device.cpp)
–> std::unique_ptr pc(new PeerConnection(privateListener.get(), peerConnectionOptions))
(libmediasoupclient/src/Handler.cpp)
–> webrtc::CreateBuiltinVideoEncoderFactory (deps/libmediasoupclient/src/PeerConnection.cpp)
–> webrtc::CreatePeerConnectionFactory
–> cricket::CreateMediaEngine(std::move(media_dependencies)) (webrtc/src/api/create_peerconnection_factory.cc)
–> CreateMediaEngine (webrtc/src/media/engine/webrtc_media_engine.cc)
–> WebRtcVideoEngine::WebRtcVideoEngine (webrtc/src/media/engine/webrtc_media_engine.cc)
从 libmediasoupclient/src/PeerConnection.cpp
中 PeerConnection
构造函数部分代码如下,我们可以看到音视频编解码器的创建工厂
this->peerConnectionFactory = webrtc::CreatePeerConnectionFactory(
this->networkThread.get(),
this->workerThread.get(),
this->signalingThread.get(),
nullptr /*default_adm*/,
webrtc::CreateBuiltinAudioEncoderFactory(),
webrtc::CreateBuiltinAudioDecoderFactory(),
webrtc::CreateBuiltinVideoEncoderFactory(),
webrtc::CreateBuiltinVideoDecoderFactory(),
nullptr /*audio_mixer*/,
nullptr /*audio_processing*/);
从上面1
2
可以看到 CreateMediaEngine 传入了不同的Factory,实际编码使用的是后者,
因此 mediasoup 默认无法支持安卓h264的硬编解码…
webrtc openh264 软编码源码分析
-
VideoStreamEncoder 创建流程如下
SetRemoteContent_w (webrtc/src/pc/channel.cc)
–> media_channel()->SetSendParameters(send_params)
–> WebRtcVideoChannel::SetSendParameters (webrtc/src/media/engine/webrtc_video_engine.cc)
–> ApplyChangedParams(changed_params)
–> kv.second->SetSendParameters(changed_params)
–> SetCodec(params.send_codec)
–> RecreateWebRtcStream(…)
–> stream_ = call_->CreateVideoSendStream
–> CreateVideoSendStream (webrtc/src/call/call.cc)
–> VideoSendStream send_stream = new VideoSendStream(…) (webrtc/src/call/call.cc)
–> video_stream_encoder_ = CreateVideoStreamEncoder(…) (webrtc/src/video/video_send_stream.cc)
–> VideoStreamEncoder::VideoStreamEncoder(…) (webrtc/src/video/video_stream_encoder.cc) -
H264Encoder 创建
视频帧分发到 VideoStreamEncoder::OnFrame (webrtc/src/video/video_stream_encoder.cc)
–> ReconfigureEncoder()
–> encoder_ = settings_.encoder_factory->CreateVideoEncoder(encoder_config_.video_format)
(webrtc/src/video/video_stream_encoder.cc)
–> internal_encoder = std::make_unique(internal_encoder_factory_.get(), format) (webrtc\\src\\api\\video_codecs\\builtin_video_encoder_factory.cc)
–> EncoderSimulcastProxy::EncoderSimulcastProxy (webrtc\\src\\media\\engine\\encoder_simulcast_proxy.cc)
–> InternalEncoderFactory::CreateVideoEncoder (webrtc/src/media/engine/internal_encoder_factory.cc)
–> H264Encoder::Create() (webrtc/src/modules/video_coding/codecs/h264/h264.cc)
–> H264EncoderImpl::H264EncoderImpl (webrtc/src/modules/video_coding/codecs/h264/h264_encoder_impl.cc)
在 internal_encoder_factory.cc
中我们可以看到有 V8 V9 H264 AV1 Encoder 的创建,如下:
std::unique_ptr<VideoEncoder> InternalEncoderFactory::CreateVideoEncoder(const SdpVideoFormat& format) {
if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName))
return VP8Encoder::Create();
if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName))
return VP9Encoder::Create(cricket::VideoCodec(format));
if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName))
return H264Encoder::Create(cricket::VideoCodec(format));
if (kIsLibaomAv1EncoderSupported &&absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName))
return CreateLibaomAv1Encoder();
return nullptr;
}
-
H264Encoder 初始化
视频帧分发到 VideoStreamEncoder::OnFrame (webrtc/src/video/video_stream_encoder.cc)
ReconfigureEncoder()
–> encoder_->InitEncode(…)
–> EncoderSimulcastProxy::InitEncode(…) (webrtc/src/media/engine/encoder_simulcast_proxy.cc)
–> H264EncoderImpl::InitEncode(…) (webrtc/src/modules/video_coding/codecs/h264/h264_encoder_impl.cc)
其中还会调用H264EncoderImpl::SetRates
、H264EncoderImpl::CreateEncoderParams
等 -
H264Encoder 编码
视频帧分发到 VideoStreamEncoder::OnFrame (webrtc/src/video/video_stream_encoder.cc)
–> MaybeEncodeVideoFrame
–> VideoStreamEncoder::EncodeVideoFrame
–> encoder_->Encode(…)
–> H264EncoderImpl::Encode (webrtc/src/modules/video_coding/codecs/h264/h264_encoder_impl.cc)
–> encoded_image_callback_->OnEncodedImage 编码完成回调
H264Decoder初始化流程
VideoReceiver2::Decode (modules/video_coding/video_receiver2.cc)
–>
VCMDecoderDataBase::GetDecoder (modules/video_coding/decoder_database.cc)
–>
H264DecoderImpl::InitDecode (modules/video_coding/codecs/h264/h264_decoder_impl.cc)
–>
avcodec_find_decoder (third_party/ffmpeg/libavcodec/allcodecs.c)
其中 av_codec_iterate
会用到 codec_list
(在 libavcodec/codec_list.c
)
也就是为啥 开启h264软编解码 需要修改此处
openh264 提供编解码相关函数
WelsCreateDecoder;
WelsCreateSVCEncoder;
WelsDestroyDecoder;
WelsDestroySVCEncoder;
WelsGetCodecVersion;
WelsGetCodecVersionEx;
使用 openh264 编解码示例
https://blog.csdn.net/NB_vol_1/article/details/103376649
webrtc 视频 H264 硬编码
安卓设备由于碎片化,早期的版本并不支持硬编码,又存在不同的芯片厂商如高通、MTK、海思、三星等
最终并不是所有安卓设备都支持硬编解码
-
修改
MediaCodecUtils.java
中SOFTWARE_IMPLEMENTATION_PREFIXES
建议把"OMX.SEC."
去掉
因为在HardwareVideoDecoderFactory.java
和PlatformSoftwareVideoDecoderFactory
中,
MediaCodecUtils.SOFTWARE_IMPLEMENTATION_PREFIXES
包含芯片厂家被加不支持硬编码黑名单了。。。 -
支持的 H264 的芯片代码前缀如下,参考自 一朵桃花压海棠 博文
private static final String[] supportedH264HwCodecPrefixes = {
"OMX.qcom.", "OMX.Intel.", "OMX.Exynos."
,"OMX.Nvidia.H264." /*Nexus 7(2012), Nexus 9, Tegra 3, Tegra K1*/
,"OMX.ittiam.video." /*Xiaomi Mi 1s*/
,"OMX.SEC.avc." /*Exynos 3110, Nexus S*/
,"OMX.IMG.MSVDX." /*Huawei Honor 6, Kirin 920*/
,"OMX.k3.video." /*Huawei Honor 3C, Kirin 910*/
,"OMX.hisi." /*Huawei Premium Phones, Kirin 950*/
,"OMX.TI.DUCATI1." /*Galaxy Nexus, Ti OMAP4460*/
,"OMX.MTK.VIDEO." /*no sense*/
,"OMX.LG.decoder." /*no sense*/
,"OMX.rk.video_decoder."/*Youku TVBox. our service doesn't need this */
,"OMX.amlogic.avc" /*MiBox1, 1s, 2. our service doesn't need this */
};
- 修改
HardwareVideoEncoderFactory.java
和HardwareVideoDecoderFactory
相关代码以支持更多芯片
如需暴力修改可以参考 https://www.pianshen.com/article/63171561802/
其它相关文档
-
安卓webrtc在ubuntu 2004下编译使用
https://blog.csdn.net/CSqingchen/article/details/120016697 -
Android 断点调试 webrtc、 medieasoup
https://blog.csdn.net/CSqingchen/article/details/120156900 -
安卓增加 mediasoup webrtc 日志输出
https://blog.csdn.net/CSqingchen/article/details/120156669 -
安卓 Mediasoup V3 基于webrtc 分支m84 的编译
https://blog.csdn.net/CSqingchen/article/details/120163087 -
安卓 webrtc 开启h264 软编解码
https://blog.csdn.net/CSqingchen/article/details/120199702 -
安卓mediasoup输出H264流(支持H264编码)
https://blog.csdn.net/CSqingchen/article/details/120218832 -
安卓mediasoup webrtc h264 软编解码相关源码分析
https://blog.csdn.net/CSqingchen/article/details/120218923
以上是关于安卓mediasoup webrtc h264 软编解码相关源码分析的主要内容,如果未能解决你的问题,请参考以下文章
安卓mediasoup webrtc h264 编解码相关源码分析