Iphone-H5-Video标签播放视频流笔记

2020-11-17  本文已影响0人  潇潇剑_易水阁

折腾中成长

一:源起:
某天,A君话ios视频播放不了,但是Android和Web是可以播放的,一如当年听到 IE XXX 不行那样,可手头上并没iphone,一直用android机开发和调试,于是一头雾水的我,搜索到可能视频格式问题,结果什么格式都试过了,始终无果,直到搜索的关键词到一些帖子看到可能和请求头Range有关,但是解决过程还是跌跌撞撞,毕竟很多并没提到如何解决,当前的语言解决方案,当然解决后的自己在回看这些帖子时,才会觉得,实在也就这些,只不过当时雾中的自己看不清而已,最后,设备才是关键,一直没iphone,靠猜真是浪费青春。。。

一:问题起因排查:

  1. 视频格式问题,其实验证这个,只需要将视频地址改为本地存在视频的地址即可,不能单看后缀名,这也是为何要验证这个的原因,需要排查,但是造成的可能性不大
  2. 排查接口是否为本地资源还是视频流,若是本地资源,这个就好办了,检查路径是否正确以及是否存在该文件,若不是,才考虑后台流传输逻辑(比如下文所提到的解决方法)
  3. 检查请求头,这也是我一开始忽略导致方向迷失的原因,网络传输,这些很重要,需要分析出现的非常规的参数,或者说,自己应该清楚这些参数代表的意义
  4. 检查页面是否存在报错导致,检查video标签是否正确,其实这个正确在第一点也能一并验证出了
  5. 平台差异的确存在,Windos和Android的浏览器大部分(其实还没看见,稳妥点)对video标签是采取常规加载,而Safari则是采取分段加载,当然要不要分段这个选择权要不要该交给服务端,还是终端去确定这个又是另一个话题了

二:Iphone-H5-视频流播放:

  1. 第一次请求头,必包含 Range:bytes=0-1 (其实重点仅为Range这个key)
  2. 响应头必需要包含:
// 视频流格式,iphone支持mp4,但是注意码率这些,第一次必须返回此参数,后续的分段可不返回,省事的就所有都默认发送
Content-Type: video/mp4
// 该参数必须且不能错误,极其重要的参数
Content-Range: bytes 0-1/25536
// 该参数必须且不能错误,极其重要的参数
ContentLength: 1
  1. .NET 4.0 WebApi后台视频流分段传输参考源码(适用支持http协议且该协议带有Range规范的软件,也适合断点下载的场景,对于资源来说,不分是不是video还是文本,当然按上面的提到的点或者看http关于Range的规范也是不分语言或者该语言的哪种版本,此处仅仅为当时项目用到4.0而已):
public HttpResponseMessage ResourceSegmentLoad()
        {
            // 每次请求响应状态码均为 206,无须判断最后一次分段时返回200,省事
            var response = new HttpResponseMessage(HttpStatusCode.PartialContent);
            // 获取range,若是无返回的对象为null
            var range = Request.Headers.Range?.Ranges.FirstOrDefault();
            // 分段的起始位置,若为null,默认0
            long? from = range == null ? 0 : range.From;
            // 分段的结束位置,若为null,默认1
            long? to = range == null ? 1 : range.To;
            byte[] bytes = null;
            // 具体如何获取,自行解决
            string path = "你的资源文件地址";
            // 具体如何获取,自行解决
            string mediaType = "资源的文件类型";
            long fileLength = 0;
            var file = new FileInfo(path);
            if (file.Exists)
            {
                using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    fileLength = fileStream.Length;
                    // 对应的文件流跳转到指定的分段起始位置开始读操作,Begin为从资源流0开始位置计算
                    fileStream.Seek(from.Value, SeekOrigin.Begin);
                    using (BinaryReader binaryReader = new BinaryReader(fileStream))
                    {
                        to = to == null ? fileLength - 1 : to.Value;
                        // 分段大小
                        int length = Convert.ToInt32(to - from) + 1;
                        // 仅仅加载分段指定范围的数据
                        bytes = binaryReader.ReadBytes(length);
                    }
                }
            }
            // 切勿使用StreamContent
            response.Content = new ByteArrayContent(bytes);
            // 该类型谨谨遵循 http 规范
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType);
            // 对应生成的header参数为 $"Content-Range: bytes {from}-{to}/{fileLength}"
            response.Content.Headers.ContentRange = new ContentRangeHeaderValue(from.Value, to.Value, fileLength);
            // 此处很容易误填fileLength,实际上是你放进Content 的bytes的大小
            response.Content.Headers.ContentLength = bytes?.Length ?? 0;

            return response;
        }

三:幕:

折腾之后,总想着为啥要这么折腾,故总结如下:
1.使用分段加载资源的好处:
1.0 提高大文件的响应速度(不用加载完就返回,单次来看好似是这么回事 <-< )
1.1 减少io的占用(还是单次来看 <-< )
1.2 减少用户等待时间(单次来看,总体断断续续的,用户会疯,毕竟用户不在意这些)
1.3 对分片控制强烈的如植入广告或者其他之类的收费分段的有利
1.4 容易多路不同资源的异步加载,同资源不同等级性质加载等等
1.5 减少掉包率这些导致的重传占用时间
1.6 对于单次需要缓冲到的数据才能快进,分段能更好跳跃到指定点加载,优化用户体验节省时间
2.使用分段加载资源的坏处:
2.0 增加传输的次数,毕竟原理仅仅为单次发送改为多次发送(合理的分割除外)
2.1 在大传输速率下,若客户端没有适应性的策略,依然固定分段范围和大小的,则会导致没必要的传输次数
2.2 多次的加载虽然缩短响应时间,但是http协议之间处理的时间加在一起,无疑会浪费,或许将来的合并犹如io复用那样,达到最佳的分割范围与请求次数
最后,我已悄悄把之前的全加载统一改为分段加载,不管是哪种pc又或者哪种phone访问,都执行此策略,这次解决的不仅仅是iphone播放不了的问题,而是实际上目前采取的方案,虽然5G越来越近了,对于平常的视频加载来说,存在的分割范围就是实际上请求的文件大小时,这种机制存在的意义可能更多是功能性,而非传输瓶颈
上一篇下一篇

猜你喜欢

热点阅读