当前位置: 首页 > wzjs >正文

iss里面的默认网站开启不了提示服务器无响应.怎么开启重庆建设公司

iss里面的默认网站开启不了提示服务器无响应.怎么开启,重庆建设公司,关键词网络推广企业,公司网站招聘模板Android-RTC系列软重启,改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性,方便形成肌肉记忆。同时不分种类、不分难易程度,在线征集问题切入点。 问题:webrtc是如何创建视频编码器选用软编码or硬编码的&#xff1…

Android-RTC系列软重启,改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性,方便形成肌肉记忆。同时不分种类、不分难易程度,在线征集问题切入点。

问题:webrtc是如何创建视频编码器选用软编码or硬编码的?如何扩展支持OpenH264,OpenH265?

其实这个问题,是上篇文章的一个补充。在上篇文章【WebRTC-13】我们确认创建编码器是如何创建的,找到了编码器的实体类,并大致的勾画出其调用链路,如下所示:

SdpOfferAnswerHandler:: ApplyLocalDescription / ApplyRemoteDescription(sdp信息)
SdpOfferAnswerHandler::UpdateTransceiversAndDataChannels -> UpdateTransceiverChannel(创建RtpTransceiver->Video/VoiceChannel)
SdpOfferAnswerHandler::UpdateSessionState
SdpOfferAnswerHandler::PushdownMediaDescription
BaseChannel::SetLocalContent(const MediaContentDescription* content, ..)
VoiceChannel/VideoChannel::SetLocalContent_w
BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams, ..)WebRtcVideoSendChannel::AddSendStream
WebRtcVideoSendChannel::WebRtcVideoSendStream::WebRtcVideoSendStream(Constructor)
WebRtcVideoSendChannel::WebRtcVideoSendStream::SetCodec|::RecreateWebRtcStream|::SetSenderParameters|::ReconfigureEncoder
Call::CreateVideoSendStream
VideoSendStreamImpl() -> VideoStreamEncoder(Interface)

我们可以在VideoStreamEncoder实体类中快速定位成员变量std::unique_ptr<VideoEncoder> encoder_ 代码创建的地方。

VideoStreamEncoderSettings   settings_;
VideoEncoderConfig     encoder_config_;void VideoStreamEncoder::ReconfigureEncoder() {std::unique_ptr<VideoEncoder> encoder_;encoder_ = MaybeCreateFrameDumpingEncoderWrapper(settings_.encoder_factory->CreateVideoEncoder(encoder_config_.video_format),field_trials_);
}

随着调用链路的回溯,我们定位到WebRtcVideoSendChannel::WebRtcVideoSendStream的构造函数初始化了VideoSendStreamParameters,VideoStreamEncoder需要使用以下的三个输入参数,都是WebRtcVideoSendStream构造函数前在上层传入并创建好了。

webrtc::VideoSendStream::Config   parameters_.config
webrtc::VideoEncoderConfig            parameters_.encoder_config
VideoCodecSettings                         parameters_.codec_settings;

也就是在WebRtcVideoSendStream创建的地方,WebRtcVideoSendChannel::AddSendStream。

// cpp\media\engine\webrtc_video_engine.cc
bool WebRtcVideoSendChannel::AddSendStream(const StreamParams& sp) {webrtc::VideoSendStream::Config config(transport());config.encoder_settings.encoder_factory = encoder_factory_;config.encoder_settings.bitrate_allocator_factory = bitrate_allocator_factory_;...WebRtcVideoSendStream* stream = new WebRtcVideoSendStream(call_, sp, std::move(config), default_send_options_,video_config_.enable_cpu_adaptation, bitrate_config_.max_bitrate_bps,send_codec(), send_rtp_extensions_, send_params_);
}

记住上面出现的transport() 以后会重点讲】显然encoder_factory也是从WebRtcVideoSendChannel外部持有者,webrtc_media_engine传进来的。经过了前面几篇文章的分析,这里直接跳过无聊的跟踪代码,直接给出encoder_factory的根持有者调用链——由PeerConnectionFactory持有的,实际对象位于Java层的DefaultVideoEncoderFactory。

|CreatePeerConnectionFactoryForJava
|---CreateModularPeerConnectionFactory( PeerConnectionFactoryDependencies )
|------ConnectionContext( dep )::EnableMeida = dep->media_factory->CreateMediaEngine
|		auto audio_engine = std::make_unique<WebRtcVoiceEngine>(
|			&env.task_queue_factory(), deps.adm.get(), env.field_trials(),
|			std::move(deps.audio_encoder_factory),
|			std::move(deps.audio_decoder_factory), std::move(deps.audio_mixer),
|			std::move(deps.audio_processing), std::move(deps.audio_frame_processor) );
|		auto video_engine = std::make_unique<WebRtcVideoEngine>(
|			std::move(deps.video_encoder_factory),
|			std::move(deps.video_decoder_factory), env.field_trials());
|---------CreateMediaEngine( deps ) with audio_engine / video_engine


现在我们找到问题答案的入口了,由于C++和Java之间存在一层JNI接口,所以我们先顺着调用接口,看看JNI层的接口对象类。

//文件位置 \sdk\android\src\jni\pc\peer_connection_factory.cc
ScopedJavaLocalRef<jobject> CreatePeerConnectionFactoryForJava(...) {PeerConnectionFactoryDependencies dependencies;...dependencies.adm = std::move(audio_device_module);dependencies.audio_encoder_factory = std::move(audio_encoder_factory);dependencies.audio_decoder_factory = std::move(audio_decoder_factory);dependencies.audio_processing = std::move(audio_processor);dependencies.video_encoder_factory =absl::WrapUnique(CreateVideoEncoderFactory(jni, jencoder_factory));dependencies.video_decoder_factory =absl::WrapUnique(CreateVideoDecoderFactory(jni, jdecoder_factory));EnableMedia(dependencies);rtc::scoped_refptr<PeerConnectionFactoryInterface> factory =CreateModularPeerConnectionFactory(std::move(dependencies));
}//文件位置 \sdk\android\src\jni\pc\video.cc
VideoEncoderFactory* CreateVideoEncoderFactory(JNIEnv* jni,const JavaRef<jobject>& j_encoder_factory) {return IsNull(jni, j_encoder_factory)? nullptr: new VideoEncoderFactoryWrapper(jni, j_encoder_factory);
}

明显这个VideoEncoderFactoryWrapper就是Jni层的接口类,并且看到了它是继承了C++的VideoEncoderFactory 纯虚类。

// 文件位置 sdk\android\src\jni\video_encoder_factory_wrapper.h .cc
// Wrapper for Java VideoEncoderFactory class. Delegates method calls through
// JNI and wraps the encoder inside VideoEncoderWrapper.
class VideoEncoderFactoryWrapper : public VideoEncoderFactory {public:VideoEncoderFactoryWrapper(JNIEnv* jni,const JavaRef<jobject>& encoder_factory);~VideoEncoderFactoryWrapper() override;std::unique_ptr<VideoEncoder> CreateVideoEncoder(const SdpVideoFormat& format) override;// Returns a list of supported codecs in order of preference.std::vector<SdpVideoFormat> GetSupportedFormats() const override;std::vector<SdpVideoFormat> GetImplementations() const override;std::unique_ptr<EncoderSelectorInterface> GetEncoderSelector() const override;private:const ScopedJavaGlobalRef<jobject> encoder_factory_;std::vector<SdpVideoFormat> supported_formats_;std::vector<SdpVideoFormat> implementations_;
};std::unique_ptr<VideoEncoder> VideoEncoderFactoryWrapper::CreateVideoEncoder(const SdpVideoFormat& format) {JNIEnv* jni = AttachCurrentThreadIfNeeded();ScopedJavaLocalRef<jobject> j_codec_info =SdpVideoFormatToVideoCodecInfo(jni, format);ScopedJavaLocalRef<jobject> encoder = Java_VideoEncoderFactory_createEncoder(jni, encoder_factory_, j_codec_info);if (!encoder.obj())return nullptr;return JavaToNativeVideoEncoder(jni, encoder);
}

我们也看到了VideoEncoderFactoryWrapper::CreateVideoEncoder的实现,就是调用Java层的DefaultVideoEncoderFactory.createEncoder。现在到Java层看看实现。

/** Helper class that combines HW and SW encoders. */
public class DefaultVideoEncoderFactory implements VideoEncoderFactory {private final VideoEncoderFactory hardwareVideoEncoderFactory;private final VideoEncoderFactory softwareVideoEncoderFactory = new SoftwareVideoEncoderFactory();/** Create encoder factory using default hardware encoder factory. */public DefaultVideoEncoderFactory(EglBase.Context eglContext, boolean enableIntelVp8Encoder, boolean enableH264HighProfile) {this.hardwareVideoEncoderFactory =new HardwareVideoEncoderFactory(eglContext, enableIntelVp8Encoder, enableH264HighProfile);}@Nullable@Overridepublic VideoEncoder createEncoder(VideoCodecInfo info) {final VideoEncoder softwareEncoder = softwareVideoEncoderFactory.createEncoder(info);final VideoEncoder hardwareEncoder = hardwareVideoEncoderFactory.createEncoder(info);if (hardwareEncoder != null && softwareEncoder != null) {// Both hardware and software supported, wrap it in a software fallbackreturn new VideoEncoderFallback(/* fallback= */ softwareEncoder, /* primary= */ hardwareEncoder);}return hardwareEncoder != null ? hardwareEncoder : softwareEncoder;}}// A combined video encoder that falls back on a secondary encoder if the primary encoder fails.
public class VideoEncoderFallback extends WrappedNativeVideoEncoder {private final VideoEncoder fallback;private final VideoEncoder primary;public VideoEncoderFallback(VideoEncoder fallback, VideoEncoder primary) {this.fallback = fallback;this.primary = primary;}@Overridepublic long createNativeVideoEncoder() {return nativeCreateEncoder(fallback, primary);}@Overridepublic boolean isHardwareEncoder() {return primary.isHardwareEncoder();}
}

Java层的DefaultVideoEncoderFactory是同时创建硬编码器和软编码器,并以Fallback备份的形式,打包成一个WrapperNativeVideoEncoder。上述流程各种类关系如下:

搞清楚各种对象类的上下文之后,我们就得继续深入探究软编码是怎么产生,要如何扩展。也就是上图加粗的SoftwareVideoEncoderFactory -> WrappedNativeVideoEncoder


节省篇幅,以下是 Java.SoftwareVideoEncoderFactory到Cxx.internal_encoder_factory具体实现的依赖链路。

|-org/webrtc/SoftwareVideoEncoderFactory.java
|--sdk/android/src/jni/software_video_encoder_factory.cc
|---api/video_codecs/builtin_video_encoder_factory.cc
|----media/engine/internal_encoder_factory.cc

接下来就是本次问题的答案了,在Cxx.internal_encoder_factory我们可以看到一个动态模板的Factory。这里的VideoEncoderFactoryTemplate是VideoEncoderFactory多模板实现类,

//  media/engine/internal_encoder_factory.cc
namespace {using Factory =VideoEncoderFactoryTemplate<webrtc::LibvpxVp8EncoderTemplateAdapter,
#if defined(WEBRTC_USE_H264)webrtc::OpenH264EncoderTemplateAdapter,
#endif
#if defined(RTC_USE_LIBAOM_AV1_ENCODER)webrtc::LibaomAv1EncoderTemplateAdapter,
#endifwebrtc::LibvpxVp9EncoderTemplateAdapter>;
}std::unique_ptr<VideoEncoder> InternalEncoderFactory::CreateVideoEncoder(const SdpVideoFormat& format) {auto original_format =FuzzyMatchSdpVideoFormat(Factory().GetSupportedFormats(), format);return original_format ? Factory().CreateVideoEncoder(*original_format): nullptr;
}
//  api/video_codecs/video_encoder_factory_template.h
//  api/video_codecs/video_encoder_factory_template_open_h264_adapter.h
//  api/video_codecs/video_encoder_factory_template_libvpx_vp8_adapter.h
//  api/video_codecs/video_encoder_factory_template_libaom_av1_adapter.htemplate <typename V, typename... Vs>std::unique_ptr<VideoEncoder> CreateVideoEncoderInternal(const SdpVideoFormat& format) {if (IsFormatInList(format, V::SupportedFormats())) {return V::CreateEncoder(format);}if constexpr (sizeof...(Vs) > 0) {return CreateVideoEncoderInternal<Vs...>(format);}return nullptr;}

仔细看创建编码器对象的方法实现,逻辑上很好理解,其实就是递归检查模板列表的编码器工厂类(适配器),命中格式就直接调用模板类的方法实现;不命中则继续往后递归,直至最后一个候选。

比起用STL容器去实现适配器列表,用元模板的实现方式能从编译器层面上去优化实现的代码,提高性能。

而且到这里我们也找到了如何扩展软编码器的入口:仿照OpenH264EncoderTemplateAdapter实现模板静态结构体(VideoEncoderFactory)接口方法;仿照H264Encoder继承VideoEncoder实现功能方法。但其实这里只是找到了 扩展软编解码器的入口,要真正实现扩展软编解码,还需要做大量的调查&分析工作,了解webrtc内部大量的调度算法才能得以实现。


文章转载自:

http://SZTPeSuS.prkdL.cn
http://e4hSq0iC.prkdL.cn
http://6RJ3q4kf.prkdL.cn
http://7eCvWhuc.prkdL.cn
http://XGcTkzNj.prkdL.cn
http://4bqS4rxY.prkdL.cn
http://tRP8PN2H.prkdL.cn
http://T8J6ZMgq.prkdL.cn
http://38rzq9hr.prkdL.cn
http://WHFLXMrh.prkdL.cn
http://DoaelfOT.prkdL.cn
http://HghotOZr.prkdL.cn
http://NjXlCcn0.prkdL.cn
http://IyD4bqsz.prkdL.cn
http://Mxnlszxp.prkdL.cn
http://yZ9fSVIh.prkdL.cn
http://vpsANu7S.prkdL.cn
http://zvmAHdw0.prkdL.cn
http://R9Myv2NE.prkdL.cn
http://MkfdkZoS.prkdL.cn
http://7Uc4hg96.prkdL.cn
http://cn6386F2.prkdL.cn
http://26795sjp.prkdL.cn
http://VDpW05jB.prkdL.cn
http://d2hD2hWt.prkdL.cn
http://l3ieasz7.prkdL.cn
http://Jej8rPJy.prkdL.cn
http://jdCrh4Bv.prkdL.cn
http://MxQfcCYW.prkdL.cn
http://5gvo3X7O.prkdL.cn
http://www.dtcms.com/wzjs/688751.html

相关文章:

  • 安徽省建设总站网站怎么开发一款小程序
  • 怎么才能把网站优化做好wordpress 定制表单
  • 体育 网站建设询价函格式电脑上安装wordpress
  • PHP+Ajax网站开发典型实例企业做网站属于广告宣传费吗
  • 广东深圳网站如何推销网站
  • 网站开发 脚本之家店铺小程序如何开通
  • python 做网站合适吗微信小程序排行榜前十名
  • 电商网站建设与运营实训做详情页上什么网站找素材
  • 二级网站和自建网站有什么区别东莞网站建设相关技术
  • 注销主体备案与网站备案表抽奖网站建设
  • 标准论坛网站建设德宏做网站
  • 青岛网站关键字优化神木网站建设
  • 做网站有必要注册商标吗wordpress购买资源插件
  • 北京网站排名制作做h5页面的网站有哪些
  • 展示型网站 带后台大都会app用不了
  • 带动画引导的网站网站建设与管理考查方案
  • 网站建设与管理 十四五国规教材网站网页设计的公司
  • 做网站二级页面的wordpress 简单企业主题下载
  • 网站建站目标wordpress破解登录密码破解
  • 南通做网站优化哪家好网络营销推广8种方法
  • 旅游网站开发注意点wordpress 页面下载
  • 电商网站设计线路图公司介绍ppt模板免费
  • 建设一个网站的基本步骤做网站外链需要多少钱
  • 怎么做网站推太原的网站搭建公司
  • 重庆做网站推广一个完整的策划案范文
  • 网站定制那个好公司网站建设建设
  • 响应式网站模板免费下载wordpress播放器安装
  • 做游戏网站年入百万山东济南seo整站优化费用
  • 山东泰安特产seo是做什么工作的
  • 网站的转化率泉州市住房和城乡建设部网站