图书网站开发数据库的建立,游民星空是谁做的网站,佛山网站建设团队,网站上做扫一扫1.场景描述 服务端上传MP4视频文件#xff0c;iOS客户端通过URL播放该视频文件。提供视频接口#xff0c;可以进行视频下载或者直接播放#xff0c;但是iOS手机无法播放#xff0c;且PC端safari浏览器也无法播放。 2.问题描述 安卓手机可以正常播放视频#xff0c;iOS手机…1.场景描述 服务端上传MP4视频文件iOS客户端通过URL播放该视频文件。提供视频接口可以进行视频下载或者直接播放但是iOS手机无法播放且PC端safari浏览器也无法播放。 2.问题描述 安卓手机可以正常播放视频iOS手机无法播放且PC段safari浏览器也无法播放。 3.问题分析 1safari不支持整个文件流服务器必须支持分段请求。 2safari对于文件流的请求需要包含一个请求头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 ResponseEntitybyte[] 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 ResponseEntitybyte[] 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 ResponseEntitybyte[] 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.length1 || 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.使用上述方案可以实现各环境的视频嵌套播放已经验证过可以直接用各位根据自己的代码稍作调整即可。