苹果手机video标签播放视频问题(播放mp4视频遇到的坑)

1.场景描述
服务端上传MP4视频文件,iOS客户端通过URL播放该视频文件。提供视频接口,可以进行视频下载或者直接播放,但是iOS手机无法播放,且PC端safari浏览器也无法播放。
2.问题描述
安卓手机可以正常播放视频,iOS手机无法播放,且PC段safari浏览器也无法播放。
3.问题分析
(1)safari不支持整个文件流,服务器必须支持分段请求。
(2)safari对于文件流的请求需要包含一个请求头Range, 和一个响应头Content-Range

4.针对问题分析,进行文件分段传输,以下代码已经验证,可行,代码如下:

package com.example.yonyou.dyp.com;import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;/*** @description: iOS手机无法播放,且PC端safari浏览器也无法播放问题修复* @author Lancy* @date: 2023/12/8 17:11*/
@RestController
@RequestMapping("/videos")
public class VideoController {@GetMapping("/{videoFileName}")public ResponseEntity<byte[]> streamVideo(@RequestHeader(value = "Range", required = false) String rangeHeader,HttpServletRequest request) throws IOException {String filePath = "D:/video/20230801_093526.mp4";// 获取视频文件的Resource对象(假设convertToLocalResource提供了这个方法)Resource videoResource = convertToLocalResource(filePath);// 处理Range请求if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {return handleRangeRequest(videoResource, rangeHeader);} else {return handleFullRequest(videoResource);}}private ResponseEntity<byte[]> handleRangeRequest(Resource videoResource, String rangeHeader) throws IOException {// 解析Range请求头long[] range = parseRange(rangeHeader, videoResource.contentLength());// 获取视频的部分数据byte[] videoBytes = getPartialVideo(videoResource, range[0], range[1]);// 设置Content-Range头部HttpHeaders headers = createRangeHeaders(videoBytes.length, range[0], range[1], videoResource.contentLength());return new ResponseEntity<>(videoBytes, headers, HttpStatus.PARTIAL_CONTENT);}private ResponseEntity<byte[]> handleFullRequest(Resource videoResource) throws IOException {// 获取完整视频的数据byte[] videoBytes = getFullVideo(videoResource);// 设置Content-Range头部HttpHeaders headers = createFullHeaders(videoBytes.length, videoResource.contentLength());return new ResponseEntity<>(videoBytes, headers, HttpStatus.OK);}private long[] parseRange(String rangeHeader, long contentLength) {// 解析Range请求头String[] range = rangeHeader.substring(6).split("-");long start = Long.parseLong(range[0]);long end = range.length==1 || range[1].isEmpty() ? contentLength - 1 : Long.parseLong(range[1]);return new long[]{start, end};}private byte[] getPartialVideo(Resource videoResource, long start, long end) throws IOException {// 获取部分视频数据try (InputStream videoStream = videoResource.getInputStream()) {long length = end - start + 1;byte[] videoBytes = new byte[(int) length];videoStream.skip(start);videoStream.read(videoBytes, 0, (int) length);return videoBytes;}}private HttpHeaders createRangeHeaders(long contentLength, long start, long end, long totalLength) {// 设置Content-Range头部HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.parseMediaType("video/mp4"));headers.setContentLength(contentLength);headers.add("Content-Range", "bytes " + start + "-" + end + "/" + totalLength);return headers;}private byte[] getFullVideo(Resource videoResource) throws IOException {// 获取完整视频的数据try (InputStream videoStream = videoResource.getInputStream()) {byte[] videoBytes = new byte[(int) videoResource.contentLength()];videoStream.read(videoBytes, 0, videoBytes.length);return videoBytes;}}private HttpHeaders createFullHeaders(long contentLength, long totalLength) {// 设置Content-Range头部HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.parseMediaType("video/mp4"));headers.setContentLength(contentLength);headers.add("Content-Range", "bytes 0-" + (contentLength - 1) + "/" + totalLength);return headers;}public  Resource convertToLocalResource(String filePath) {File file = new File(filePath);if (file.exists() && file.isFile()) {return new FileSystemResource(file);} else {throw new IllegalArgumentException("File does not exist or is not a regular file: " + filePath);}}}

5.使用上述方案可以实现各环境的视频嵌套播放,已经验证过,可以直接用,各位根据自己的代码稍作调整即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/209138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是HTML?

✨前言✨ 本文主要介绍什么是HTML以及W3C &#x1f352;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f352;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 文章目录 什么是HTMLHTML发展史HTML的特点什么…

Linux权限理解(1)

目录 1.shell命令以及运行原理 2.Linux权限的概念 Linux权限管理 01.文件访问者的分类&#xff08;人&#xff09; 02.文件类型和访问权限&#xff08;事物属性&#xff09; a) 文件类型 b)基本权限 03.文件权限值的表示方法 04.文件访问权限的相关设置方法 a)chmod …

「JavaScript每日一练」系列——提高你的JS技能(第一天)

以后我会陆续发布关于JavaScript知识点以及案例面试题 文章目录 文章目录 题目 一、详细讲解 二、代码 1.引入库 总结 题目 输入一个数字&#xff0c;判断是不是水仙花数自恋数&#xff08;自幂数 各位的3次方十位的三次方百位的三次方等于153&#xff09; ----输出true或fals…

软件合集(项目开发中会用到的软件)

jeecg&#xff08;JeecgBoot 文档中心&#xff09; JeecgBoot是一款基于BPM的低代码平台&#xff01;前后端分离架构 SpringBoot 2.x&#xff0c;SpringCloud&#xff0c;Ant Design&Vue&#xff0c;Mybatis-plus&#xff0c;Shiro&#xff0c;JWT&#xff0c;支持微服务。…

FPGA设计时序分析概念之Timing Arc

目录 1.1 Timing Arc概念 1.2 Timing Arcs的类型 1.3 Timing Sense(时序感知) 1.4 参考资料 1.1 Timing Arc概念 在时序工具对设计进行时序分析时&#xff0c;经常会看到一个概念Timing Arch(时序弧)。Timing Arc是一个信号一个单元Cell的输入引脚Pin到该单元输出引脚Outpu…

python epub文件解析

python epub文件解析 代码BeautifulSoup 介绍解释 代码 import ebooklib from bs4 import BeautifulSoup from ebooklib import epubbook epub.read_epub("逻辑思维训练1200题.epub")# 解析 for item in book.get_items():# 提取书中的文本内容if item.get_type() …

Redis主从架构中从节点的master_link_status:down

项目场景&#xff1a; 在搭建Redis的主从架构时&#xff0c;查看Redis的从节点状态时发现其连接的主节点的状态为down&#xff0c;并且查看主节点的状态时发现连接的从节点数量为0。 问题描述 原因分析&#xff1a; 可能在主节点中配置了密码&#xff0c;即requirepass。 解决…

算法:常见的链表算法

文章目录 链表算法两数相加两两交换链表中的节点重排链表合并K个升序链表K个一组翻转链表 总结 本篇总结常见的链表算法题和看他人题解所得到的一些收获 链表算法 关于链表的算法&#xff1a; 画图&#xff1a;画图可以解决绝大部分的数据结构的问题&#xff0c;任何的算法题…

视觉学习笔记12——百度飞浆框架的PaddleOCR 安装、标注、训练以及测试

系列文章目录 虚拟环境部署 参考博客1 参考博客2 参考博客3 参考博客4 文章目录 系列文章目录一、简单介绍1.OCR介绍2.PaddleOCR介绍 二、安装1.anaconda基础环境1&#xff09;anaconda的基本操作2&#xff09;搭建飞浆的基础环境 2.安装paddlepaddle-gpu版本1&#xff09;安装…

语言模型GPT与HuggingFace应用

受到计算机视觉领域采用ImageNet对模型进行一次预训练&#xff0c;使得模型可以通过海量图像充分学习如何提取特征&#xff0c;然后再根据任务目标进行模型微调的范式影响&#xff0c;自然语言处理领域基于预训练语言模型的方法也逐渐成为主流。以ELMo为代表的动态词向量模型开…

C#8.0本质论第十七章--构建自定义集合

C#8.0本质论第十七章–构建自定义集合 17.1更多集合接口 17.1.1IList< T >和IDictionary< TKey , TValue > 这两个接口决定了集合类型是侧重于通过位置索引来获取值&#xff0c;还是侧重于通过键来获取值。 实现这两个接口的类都必须提供索引器。 17.1.2IColl…

在线教育小程序正在成为教育行业的新生力量

教育数字化转型是目前教育领域的一个热门话题&#xff0c;那么到底什么是教育数字化转型&#xff1f;如何做好教育数字化转型&#xff1f; 教育数字化转型是利用信息技术和数字工具改变和优化教育的过程。主要特征包括技术整合、在线学习、个性化学习、大数据分析、云计算、虚拟…

【C++学习手札】基于红黑树封装模拟实现map和set

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 &#x1f49c;本文前置知识&#xff1a; 红黑树 ♈️今日夜电波&#xff1a;漂流—菅原纱由理 2:55━━━━━━️&#x1f49f;──────── 4:29 …

Appium获取toast方法封装

一、前置说明 toast消失的很快&#xff0c;并且通过uiautomatorviewer也不能获取到它的定位信息&#xff0c;如下图&#xff1a; 二、操作步骤 toast的class name值为android.widget.Toast&#xff0c;虽然toast消失的很快&#xff0c;但是它终究是在Dom结构中出现过&…

【计算机网络】HTTP请求

目录 前言 HTTP请求报文格式 一. 请求行 HTTP请求方法 GET和POST的区别 URL 二. 请求头 常见的Header 常见的额请求体数据类型 三. 请求体 结束语 前言 HTTP是应用层的一个协议。实际我们访问一个网页&#xff0c;都会像该网页的服务器发送HTTP请求&#xff0c;服务…

使用Java将图片添加到Excel的几种方式

1、超链接 使用POI&#xff0c;依赖如下 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency>Java代码如下,运行该程序它会在桌面创建ImageLinks.xlsx文件。 …

GPT-4V 在机器人领域的应用

在科技的浩渺宇宙中&#xff0c;OpenAI如一颗璀璨的星辰&#xff0c;于2023年9月25日&#xff0c;以一种全新的方式&#xff0c;向世界揭示了其最新的人工智能力作——GPT-4V模型。这次升级&#xff0c;为其旗下的聊天机器人ChatGPT装配了语音和图像的新功能&#xff0c;使得用…

『Linux升级路』进度条小程序

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;Linux &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、预备知识 &#x1f4d2;1.1缓冲区 &#x1f4d2;1.2回车和换行 二、倒计…

修改正点原子综合实验的NES模拟器按键控制加横屏

​​​​​​​ 开发板&#xff1a;stm32f407探索者开发板V2 屏幕是4.3寸-800-480-MCU屏 手头没有V3开发板&#xff0c;只有V2&#xff0c;所以没法测试 所以只讲修改哪里&#xff0c;请自行修改 先改手柄部分&#xff0c;把手柄改成按键 找到左边的nes文件夹中的nes_mai…

采用轨到轨输出设计 LTC6363HMS8-2、LTC6363HMS8-1、LTC6363HRD、LTC6363IDCB差分放大器I

产品详情 LTC6363 系列包括四个全差分、低功耗、低噪声放大器&#xff0c;具有经优化的轨到轨输出以驱动 SAR ADC。LTC6363 是一款独立的差分放大器&#xff0c;通常使用四个外部电阻设置其增益。LTC6363-0.5、LTC6363-1 和 LTC6363-2 都有内部匹配电阻&#xff0c;可分别创建…