iOS开发-WebRTC本地直播高分辨率不显示画面问题
iOS开发-WebRTC本地直播高分辨率不显示画面问题
在之前使用WebRTC结合ossrs进行推流时候,ossrs的播放端无法看到高分辨率画面问题。根据这个问题,找到了解决方案。
一、WebRTC是什么
WebRTC是什么呢?
WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和(或)音频流或者其他任意数据的传输。
二、ossrs是什么?
ossrs是什么呢?
SRS(Simple Realtime Server)是一个简单高效的实时视频服务器,支持RTMP、WebRTC、HLS、HTTP-FLV、SRT等多种实时流媒体协议。
官网地址:https://ossrs.net/lts/zh-cn/
这里暂时不写iOS Google WebRTC与ossrs实现RTC直播了。暂时值记录一下本地WebRTC直播高分辨率不显示画面问题。
三、高分辨率不显示画面问题解决方案
本地WebRTC直播高分辨率不显示画面问题,这个问题和SDP中的profile-level-id有关。
profile-level-id正好是SPS中的第二至四个字节的base16编码。这三个字节的具体含义是
sps[1] AVCProfileIndication
sps[2] profile_compatibility
sps[3] AVCLevlIndication
http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Levels
实际设置时,就是level值乘以10,例如level 1.0,设置值就是0x0A。level 3.0,设置值就是0x1E。比较例外的是level 1b,设置值是0x09
图片来源网络(抱歉忘记地址了,如果引用了您的博客图片,请留言)

第三个代表level,比如1f值为31,从图中可以看出3.1,分辨率在720480 720576 1280*720
如果需要高分辨率 19201080 25601920 3840*2160 ,需要设置的level 5.1 16进制值为33,这里设置的值是42e033。
下面是一个SDP示例
“code”: 0,
“server”: “vid-415v5lz”,
“sdp”: “v=0\r\no=SRS/4.0.268(Leo) 94003279212192 2 IN IP4 0.0.0.0\r\ns=SRSPublishSession\r\nt=0 0\r\na=ice-lite\r\na=group:BUNDLE 0 1\r\na=msid-semantic: WMS live/livestream\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:q01184s8\r\na=ice-pwd:o25158210twbb093o342910094v0wo5k\r\na=fingerprint:sha-256 6A:66:81:7C:68:91:79:18:05:2C:EE:5F:BF:1B:4B:F4:78:C4:01:06:CC:CC:9E:F0:32:5B:72:21:4A:C2:A1:AA\r\na=setup:passive\r\na=mid:0\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=candidate:0 1 udp 2130706431 10.0.80.128 8000 typ host generation 0\r\na=candidate:1 1 udp 2130706431 112.124.157.141 8000 typ host generation 0\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 127\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:q01184s8\r\na=ice-pwd:o25158210twbb093o342910094v0wo5k\r\na=fingerprint:sha-256 6A:66:81:7C:68:91:79:18:05:2C:EE:5F:BF:1B:4B:F4:78:C4:01:06:CC:CC:9E:F0:32:5B:72:21:4A:C2:A1:AA\r\na=setup:passive\r\na=mid:1\r\na=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=recvonly\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 H264/90000\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=fmtp:96 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:127 red/90000\r\na=candidate:0 1 udp 2130706431 10.0.80.128 8000 typ host generation 0\r\na=candidate:1 1 udp 2130706431 112.124.157.141 8000 typ host generation 0\r\n”,
“sessionid”: “q01184s8:oPvh”
}
可以看到这里的profile-level-id=42e01f
如果在WebRTC中将本地的SDP的profile-level-id替换成42e033
[weakSelf.webRTCClient offer:^(RTCSessionDescription *sdp) {DebugLog(@"changeSDP2Server offer sdp:%@", sdp);NSString *offerSDPString = [SDWebRTCSDPUtil setMediaBitrate:sdp.sdp media:@"video" bitrate:(6*1024*1024)];DebugLog(@"changeSDP2Server offerSDPString:%@", offerSDPString);[weakSelf changeSDP2Server:offerSDPString];}];
将调用rtc/v1/publish/接口获得的remoteSDPString中的profile-level-id更改42e033之后再调用
- (void)setRemoteDescription:(RTC_OBJC_TYPE(RTCSessionDescription) *)sdpcompletionHandler:(nullable void (^)(NSError *_Nullable error))completionHandler;
经过测试,切换高分辨率画面可以正常显示。
NSString *resultRemoteSDPString = [SDWebRTCSDPUtil setMediaBitrate:remoteSDPString media:@"video" bitrate:(6*1024*1024)];DebugLog(@"changeSDP2Server resultRemoteSDPString:%@", resultRemoteSDPString);RTCSessionDescription *remoteSDP = [[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer sdp:resultRemoteSDPString];[weakSelf.webRTCClient setRemoteSdp:remoteSDP completion:^(NSError * error) {DebugLog(@"changeSDP2Server setRemoteDescription error:%@", error);}];
四、通过RTCVideoEncoderFactory解决高分辨率不显示画面问题解决方案
通过将SDP中的profile-level-id进行更改并不是我的最终解决方法,我最后使用的是通过指定RTCVideoEncoder的RTCVideoCodecInfo中constrainedHighParams的profile-level-id值为42e033
设置codecs的constrainedHighInfo和constrainedBaselineInfo元素。
NSDictionary<NSString *, NSString *> *constrainedHighParams = @{@"profile-level-id" : kLevelHighConstrainedHigh,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedHighInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Name parameters:constrainedHighParams];[codecs addObject:constrainedHighInfo];NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{@"profile-level-id" : kLevelHighConstrainedBaseline,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedBaselineInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Name parameters:constrainedBaselineParams];[codecs addObject:constrainedBaselineInfo];
完整代码如下
SDRTCVideoEncoderFactory.h
#import <Foundation/Foundation.h>
#import <WebRTC/WebRTC.h>/**+ (NSArray<RTCVideoCodecInfo *> *)supportedCodecs {NSDictionary<NSString *, NSString *> *constrainedHighParams = @{@"profile-level-id" : kRTCMaxSupportedH264ProfileLevelConstrainedHigh,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedHighInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Nameparameters:constrainedHighParams];NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{@"profile-level-id" : kRTCMaxSupportedH264ProfileLevelConstrainedBaseline,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedBaselineInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Nameparameters:constrainedBaselineParams];RTCVideoCodecInfo *vp8Info = [[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecVp8Name];#if defined(RTC_ENABLE_VP9)RTCVideoCodecInfo *vp9Info = [[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecVp9Name];#endifreturn @[constrainedHighInfo,constrainedBaselineInfo,vp8Info,#if defined(RTC_ENABLE_VP9)vp9Info,#endif];}*/@interface SDRTCVideoEncoderFactory : NSObject<RTCVideoEncoderFactory>@end
SDRTCVideoEncoderFactory.m
#import "SDRTCVideoEncoderFactory.h"static NSString *kLevelHighConstrainedHigh = @"640c33";
static NSString *kLevelHighConstrainedBaseline = @"42e033";@implementation SDRTCVideoEncoderFactory- (id<RTCVideoEncoder>)createEncoder:(RTCVideoCodecInfo *)info {if ([info.name isEqualToString:kRTCVideoCodecH264Name]) {return [[RTCVideoEncoderH264 alloc] initWithCodecInfo:info];} else if ([info.name isEqualToString:kRTCVideoCodecVp8Name]) {return [RTCVideoEncoderVP8 vp8Encoder];} else if ([info.name isEqualToString:kRTCVideoCodecVp9Name]) {return [RTCVideoEncoderVP9 vp9Encoder];}return nil;
}- (NSArray<RTCVideoCodecInfo *> *)supportedCodecs {NSMutableArray<RTCVideoCodecInfo *> *codecs = [NSMutableArray array];NSDictionary<NSString *, NSString *> *constrainedHighParams = @{@"profile-level-id" : kLevelHighConstrainedHigh,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedHighInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Name parameters:constrainedHighParams];[codecs addObject:constrainedHighInfo];NSDictionary<NSString *, NSString *> *constrainedBaselineParams = @{@"profile-level-id" : kLevelHighConstrainedBaseline,@"level-asymmetry-allowed" : @"1",@"packetization-mode" : @"1",};RTCVideoCodecInfo *constrainedBaselineInfo =[[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecH264Name parameters:constrainedBaselineParams];[codecs addObject:constrainedBaselineInfo];RTCVideoCodecInfo *vp8Info = [[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecVp8Name parameters:nil];[codecs addObject:vp8Info];#if defined(RTC_ENABLE_VP9)RTCVideoCodecInfo *vp9Info = [[RTCVideoCodecInfo alloc] initWithName:kRTCVideoCodecVp9Name];[codecs addObject:vp9Info];
#endifreturn [codecs copy];
}@end
最后在RTCPeerConnectionFactory初始化的时候做一下设置
#pragma mark - Lazy
- (RTCPeerConnectionFactory *)factory {if (!_factory) {RTCInitializeSSL();SDRTCVideoDecoderFactory *decoderFactory = [[SDRTCVideoDecoderFactory alloc] init];SDRTCVideoEncoderFactory *encoderFactory = [[SDRTCVideoEncoderFactory alloc] init];// for (RTCVideoCodecInfo *codec in encoderFactory.supportedCodecs) {
// DebugLog(@"RTCVideoCodecInfo codec.parameters:%@", codec.parameters);
// }_factory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory decoderFactory:decoderFactory];}return _factory;
}
经过测试,解决了高分辨率不显示画面的问题
五、小结
iOS开发-WebRTC本地直播高分辨率不显示画面问题,使用WebRTC结合ossrs进行推流时候,ossrs的播放端无法看到高分辨率画面问题。通过设置RTCPeerConnectionFactory的initWithEncoderFactory最后解决了该问题。
https://blog.csdn.net/gloryFlow/article/details/132240952
学习记录,每天不停进步。
相关文章:
iOS开发-WebRTC本地直播高分辨率不显示画面问题
iOS开发-WebRTC本地直播高分辨率不显示画面问题 在之前使用WebRTC结合ossrs进行推流时候,ossrs的播放端无法看到高分辨率画面问题。根据这个问题,找到了解决方案。 一、WebRTC是什么 WebRTC是什么呢? WebRTC (Web Real-Time Communicatio…...
python项目virtualenv环境部署正式项目和后台运行实践
pycharm创建virtualenv环境的项目: 在本地虚拟环境项目路径下生成依赖包记录文件,然后上传到linux 服务器项目路径下: 注意注意:要在虚拟环境中生成,才能将所有的项目依赖包构建在 requirements.txt文件中。 pip3 fre…...
平替 Docker - 玩转容器新利器 Podman Desktop (视频)
《OpenShift 4.x HOL教程汇总》 在 podman-desktop 1.2.1 podman 4.4 环境中验证。 文章目录 什么是 podman 和 podman-desktop安装 podman 和 podman-desktop 基本环境Image、Container 和 Pod 的基本操作拉取 Image运行 Container 将 Pod 部署到 Kubernetes安装 Kind 扩展插…...
nodejs+vue+elementui招聘求职网站系统的设计与实现-173lo
(1)管理员的功能是最高的,可以对系统所在功能进行查看,修改和删除,包括企业和用户功能。管理员用例如下: 图3-1管理员用例图 (2)企业关键功能包含个人中心、岗位类型管理、招聘信息…...
静态链接(7/13)
在一个软件项目中,为了完成特定功能,除了自定义函数,还可以使用别人已经封装好的函数库,如 C 函数库。库函数的使用避免了重复“造笼子”的重复工作,提高了代码复用率,大大减轻了软件开发的工作量。 库分为…...
jvs-rules API数据源配置说明(含配置APIdemo视频)
在JVS中,多数据源支持多种形态的数据接入,其中API是企业生产过程中常见的数据形态。使用数据源的集成配置,以统一的方式管理和集成多个API的数据。这些平台通常提供各种数据转换和处理功能,使得从不同数据源获取和处理数据变得更加…...
爬虫来介绍ChromeF12 谷歌开发者工具 -Network
了解网页基础(HTML、CSS、JavaScript) 了解HTTP基本原理 了解JSON格式 了解Ajax请求 了解爬虫基本原理 (一)、Chrome开发者工具面板概述 Elements 查找网页源代码HTML中的任一元素,手动修改任一元素的属性和样式且能实时在浏览器里面得到反馈。 比如我们在Event Listener…...
[足式机器人]Part4 机械设计 Ch00/01 绪论+机器结构组成与连接 ——【课程笔记】
本文仅供学习使用 本文参考: 《机械设计》 王德伦 马雅丽课件与日常作业可登录网址 http://edu.bell-lab.com/manage/#/login,选择观摩登录,查看2023机械设计2。 机械设计-Ch00Ch01——绪论机器结构组成与连接 Ch00-绪论0.1 何为机械设计——…...
Android isLoggable定制属于自己的log
Android原生自带的 android.util.Log,其中有一个 isLoggable 方法的运用 /** * Checks to see whether or not a log for the specified tag is loggable at the specified level.** The default level of any tag is set to INFO. This means that any level abov…...
【Spring Boot】构建RESTful服务 — 使用Swagger生成Web API文档
使用Swagger生成Web API文档 高质量的API文档在系统开发的过程中非常重要。本节介绍什么是Swagger,如何在Spring Boot项目中集成Swagger构建RESTful API文档,以及为Swagger配置Token等通用参数。 1.什么是Swagger Swagger是一个规范和完整的框架&…...
【实战】 九、深入React 状态管理与Redux机制(五) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(二十)
文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…...
PHP傻瓜也能搭建自己框架
PHP最简单自定义自己的框架(一) PHP最简单自定义自己的框架创建目录结构(二) PHP最简单自定义自己的框架定义常量自动生成目录(三) PHP最简单自定义自己的框架控制器自动加载运行(四…...
为什么商业基础软件需要开源
Bytebase 本身是一家商业软件公司,而作为最核心资产的代码从 Day 0 却是开源的。同时我们还是 star-history.com 的运营者,大家在各种开源渠道会看到它生成的图: 一直以来,常会被别人问起的一个问题,就是为什么 Byteba…...
【自用】云服务器 使用 docker 搭建 HomeAssistant + MQTT 物联网平台
总览 1.搭建流程概述 2.准备工作 3.开始搭建! 4.总结 如果想看 ESP32 或其他使用 MicroPython 编程的单片机如何连接到该云服务器,实现 HomeAssistant 控制 单片机的内容,请看我这篇博客的下一篇。 一、搭建流程概述 0.总体流程 我们需要…...
ABAP: SQL 多值查询
基础查数据 问题举例:例如查物料类型为ZFRT、ZROH和ZRSA的物料编码。 1、直接查询,三种不同类型的物料类型是或的关系。 SELECT DISTINCT ma~matnr ma~mtartFROM mara AS maINNER JOIN mbewh AS mbON ma~matnr mb~matnrINTO CORRESPONDING FIELDS OF…...
分布式学习最佳实践:从分布式系统的特征开始
正文 在延伸feature(分布式系统需要考虑的特性)的时候,我逐渐明白,这是因为要满足这些feature,才设计了很多协议与算法,也提出了一些理论。比如说,这是因为要解决去中心化副本的一致性问题&…...
第三章 图论 No.8最近公共祖先lca, tarjan与次小生成树
文章目录 lcaTarjan板子题:1172. 祖孙询问lca或tarjan:1171. 距离356. 次小生成树352. 闇の連鎖 lca O ( m l o g n ) O(mlogn) O(mlogn),n为节点数量,m为询问次数,lca是一种在线处理询问的算法 自己也是自己的祖先 倍…...
[Kubernetes]Kubeflow Pipelines - 基本介绍与安装方法
1. 背景 近些年来,人工智能技术在自然语言处理、视觉图像和自动驾驶方面都取得不小的成就,无论是工业界还是学术界大家都在惊叹一个又一个的模型设计。但是对于真正做过算法工程落地的同学,在惊叹这些模型的同时,更多的是在忧虑如…...
Sui网络的稳定性和高性能
Sui的最初的协议开发者设计了可扩展的网络,通过水平扩展的方式来保持可负担得起的gas费用。其他区块链与之相比,则使用稀缺性和交易成本来控制网络活动。 Sui主网上线前90天的数据指标证明了这一设计概念,在保持100%正常运行的同…...
RabbitMQ 安装教程
RabbitMQ 安装教程 特殊说明 因为RabbitMQ基于Erlang开发,所以安装时需要先安装Erlang RabbitMQ和Erlang版本对应关系 查看地址:www.rabbitmq.com/which-erlan… 环境选择 Erlang: 23.3及以上 RabbitMQ: 3.10.1Windows 安装 1. 安装Erlang 下载地…...
小型语言模型(SLM)实战:高效部署与成本优化指南
1. 小型语言模型(SLM)入门指南:2026年实战手册在AI技术快速迭代的今天,大型语言模型(LLM)虽然频频登上头条,但真正改变行业游戏规则的却是那些能在本地设备上运行的小型语言模型(SLM…...
基于Git提交历史的本地AI代码助手:Machtiani深度解析与实践指南
1. 项目概述:Machtiani,一个能与你的代码库深度对话的本地AI助手 如果你和我一样,每天都要面对一个拥有数千次提交、数万行代码的庞大项目,那么你一定理解那种在代码海洋中寻找特定逻辑或修复一个陈年Bug时的无力感。传统的全局搜…...
Inter字体完全指南:为数字界面选择最佳屏幕字体的终极解决方案
Inter字体完全指南:为数字界面选择最佳屏幕字体的终极解决方案 【免费下载链接】inter The Inter font family 项目地址: https://gitcode.com/gh_mirrors/in/inter 你是否曾在设计网站、应用或数字产品时,为字体选择而烦恼?屏幕上的文…...
TMSpeech终极指南:5分钟配置Windows本地实时语音转文字工具
TMSpeech终极指南:5分钟配置Windows本地实时语音转文字工具 【免费下载链接】TMSpeech 腾讯会议摸鱼工具 项目地址: https://gitcode.com/gh_mirrors/tm/TMSpeech 你是否厌倦了需要联网才能使用的语音转文字工具?担心会议内容被上传到云端泄露隐私…...
Meshroom完全指南:零基础掌握免费3D重建的终极教程
Meshroom完全指南:零基础掌握免费3D重建的终极教程 【免费下载链接】Meshroom Node-based Visual Programming Toolbox 项目地址: https://gitcode.com/gh_mirrors/me/Meshroom 想从普通照片变出逼真的3D模型吗?Meshroom就是你的魔法工具箱&#…...
用STM32F103的ADC+DMA搞定双摇杆数据采集,附CubeMX配置避坑指南
STM32F103双摇杆数据采集实战:CubeMX配置与DMA优化全解析 摇杆控制作为人机交互的核心组件,在无人机遥控、机器人控制等领域应用广泛。STM32F103C8T6凭借其出色的性价比和丰富的外设资源,成为这类应用的理想选择。本文将深入探讨如何通过ADC多…...
【限时公开】某头部AIGC平台内部Docker Sandbox配置基线(v23.0.1+Ubuntu 22.04 LTS适配版)
更多请点击: https://intelliparadigm.com 第一章:Docker Sandbox在AIGC平台中的安全隔离价值与演进背景 随着AIGC平台对多租户推理、用户自定义模型微调和第三方插件集成的需求激增,运行时环境的安全边界日益脆弱。Docker Sandbox 通过轻量…...
为什么92%的MCP 2026日志检测系统在POC阶段失败?资深架构师亲授4个反直觉调优原则
更多请点击: https://intelliparadigm.com 第一章:为什么92%的MCP 2026日志检测系统在POC阶段失败? MCP 2026(Multi-Channel Protocol 2026)是新一代分布式日志采集与异常模式识别协议,其设计目标是在毫秒…...
Method Draw:5分钟上手的轻量级SVG编辑器完全指南
Method Draw:5分钟上手的轻量级SVG编辑器完全指南 【免费下载链接】Method-Draw Method Draw, the SVG Editor for Method of Action 项目地址: https://gitcode.com/gh_mirrors/me/Method-Draw 你是否曾经需要快速创建一些简单的矢量图形,却不想…...
ServiceNow AgentLab:企业级AI智能体工作流自动化实战指南
1. 项目概述:当AI遇上企业级工作流自动化如果你在企业IT部门或者业务流程管理岗位待过,肯定对ServiceNow这个名字不陌生。它几乎是企业服务管理领域的“操作系统”,从IT服务台、IT运维到人力资源、财务、客户服务,无数复杂的业务流…...
