SDL中文论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz

让webrtc解码rtsp流

查看数: 4026 | 评论数: 2 | 收藏 0
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2018-10-15 20:36

正文摘要:

本帖最后由 ancientcc 于 2020-10-12 14:16 编辑 webrtc如何解码rtsp,有种方案是在服务器把rtsp转成webrtc要求的格式,然后通过网络传给客户端,这里描述的方案是不通过服务器,客户端按收rtsp流,然后用通过web ...

回复

ancientcc 发表于 2019-4-13 09:51:08

MediaCodec编码h264流

1、设置编码码率
  1. <webrtc>/media/engine/webrtcvideoengine.cc
  2. std::vector<webrtc::VideoStream> EncoderStreamFactory::CreateEncoderStreams(
  3.     int width,
  4.     int height,
  5.     const webrtc::VideoEncoderConfig& encoder_config)
  6. {
  7.   ...
  8.   int max_bitrate_bps =
  9.       (encoder_config.max_bitrate_bps > 0)
  10.           ? encoder_config.max_bitrate_bps
  11.           : GetMaxDefaultVideoBitrateKbps(width, height) * 1000;
  12.   ...
  13. }
复制代码
如果encoder_config.max_bitrate_bps <= 0,会用webrtc内置函数GetMaxDefaultVideoBitrateKbps计算码率。对于想自定义场合,方法是让encoder_config.max_bitrate_bps > 0,单位bps,像4000000表示4Mbps。encoder_config哪来的?app调用webrtc::VideoStreamEncoder::ConfigureEncoder(..)传入的第一个参数。
ancientcc 发表于 2018-10-21 11:43:21

MediaCodec解码h264流

本帖最后由 ancientcc 于 2018-10-21 11:48 编辑

1、让webrtc能搜出这个MediaCodec解码器
MediaCodecVideoDecoder.java的findDecoder负责搜索系统内MediaCodec支持的解码器。对匹配条件,除了MIME,还有解码器名称,具体是名称必须满足要求的前缀。对MIME="video/avc",supportedH264HwCodecPrefixes列出了内置支持的前缀。
  1. String[] supportedH264HwCodecPrefixes = {"OMX.qcom.", "OMX.Intel.", "OMX.Exynos."};
复制代码

一些android开发板解码器的名称前缀可能不在这里头,会使得webrtc枚举不到这解码器。举个例子,firefly的AIO-rk3288就不在这里,它的名称前缀是“OMX.rk.”,就须要修改supportedH264HwCodecPrefixes。
  1. String[] supportedH264HwCodecPrefixes = {"OMX.qcom.", "OMX.Intel.", "OMX.Exynos.", "OMX.rk."};
复制代码

即使app只希望解码,但最初找cricket::VideoCodec时是用编码器找的。MediaCodecVideoEncoder.java的findHwEncoder执行搜索编码器,它在匹配上也有名称前缀问题,也须按findHwEncoder要求的去改。。

2、增大kMaxPendingFramesH264值
kMaxPendingFramesH264用于指示允许“悬”着未解码帧的最大帧数,一旦超过这帧数,androidmediadecoder.cc会复位MediaCodec模块。要理解这个,先说下MediaCodec解码机制。

webrtc调用MediaCodec解码使用同步方式,在DecodingThread内,解码具体一帧没为MediaCodec开新的线程,那它怎么“估算”调用queueInputBuffer、dequeueOutputBuffer之间间隔?把编码数据放入inputbuffer后,调用queueInputBuffer告知MediaCodec,这inputbuffer可用于解码了。MediaCodec解这一帧须要时间,webrtc不可能严格预知这时间。——它采用的方法是调用dequeueOutputBuffer时设置“最优”溢出时间,即参数timeoutUs。运气好时,解码花费时间恰好“等于”timeoutUs,不花费额外开销。运气不好时,timeoutUs小于解码须要时间,没解出该帧,dequeueOutputBuffer返回INFO_TRY_AGAIN_LATER。那是不是app永远拿不到这帧了,不是的。下一次调用dequeueOutputBuffer时,它首先会取到该帧!也就是说,此次queueInputBuffer了B帧,但有可能dequeueOutputBuffer到上次的A帧。

webtc这逻辑会不会有bug?一次queueInputBuffer对应一个dequeueOutputBuffer,即一次queueInputBuffer只会得到一解码帧,如果outputBuffers因意外累积了多帧……AIO-rk3288上,outputBuffers长度是6。

回到kMaxPendingFramesH264。webrtc统计queueInputBuffer次数和dequeueOutputBuffer成功解出帧的次数,它们之间差值就是“悬”着未解码帧的帧数,而这数目一旦超过门限,就认为得复位MediaCodec了。kMaxPendingFramesH264存储着这个门限值,官方设的是4,即“悬”着未解码帧的帧数超过4帧,就要复位MediaCodec。为什么要增大kMaxPendingFramesH264?实际使用时遇到了些码流,它初始时有一段不能解,像2秒,但后面能正常解码。为支持这种码流,就要适当增大kMaxPendingFramesH264。我改到200,对fps=30来说,已容许6秒没解出有效帧。

3、VCMDecodedFrameCallback:ecoded
解码器成功解码一帧后,它会调用VCMDecodedFrameCallback:ecoded,参数decodedImage就是解出的图像。为什么要改这函数?——它要基于多个时间戳进行计算,一旦算出认为这帧“来得不是时候”,就会丢掉该帧,导致app层的OnFrame收不到这帧。实际使用时,一些rtsp设备可能码流不平稳,提供时间戳严重错乱,修改VCMDecodedFrameCallback:ecoded,使得让会算出“来得不是时候”帧也上传到OnFrame。以下是一种修改法,一进入就调用FrameToRender。
  1. void VCMDecodedFrameCallback::Decoded(VideoFrame& decodedImage, ...)
  2. {
  3.         _receiveCallback->FrameToRender(decodedImage, qp, webrtc::VideoContentType::UNSPECIFIED);
  4.         return;
  5. }
复制代码

Archiver|手机版|小黑屋|丽谷软件|libsdl.cn

GMT+8, 2025-5-1 23:40 , Processed in 0.070897 second(s), 25 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表