当前位置: 首页 > news >正文

SpringBoot结合Vue 播放 m3u8 格式视频

1、将MP4转M3U8格式

使用ffmpeg 命令

基于命令

ffmpeg -i 1.mp4 -c:v copy  -c:a copy  -strict -2  -f hls  -hls_time 5  -hls_list_size 0  -hls_segment_filename  %04d.ts  index.m3u8

具体java 工具类如下:

import lombok.extern.slf4j.Slf4j;import java.io.*;/***** @author xuancg* @date 2025/2/25*/
@Slf4j
public class FfmpegUtil {public static void main(String[] args) {File mp4 = new File("C:\\Users\\BHL\\Desktop\\2025-09-20-10-00-48-0.mp4");File dir =  new File("C:\\Users\\BHL\\Desktop\\1");System.out.println(convertM3u8(mp4.getAbsolutePath(), dir.getAbsolutePath()));}public static boolean doExeCommd(String cmd) {return new FfmpegUtil().exec(cmd);}/*** 转换为m3u8* ffmpeg -i 1.mp4 -c:v copy  -c:a copy  -strict -2  -f hls  -hls_time 5  -hls_list_size 0  -hls_segment_filename %04d.ts  index.m3u8* @param file 原始视频文件的绝对路径* @param dir 转换后的m3u8文件存放的目录*/public static boolean convertM3u8(String file, String dir) {String cmd = String.format("ffmpeg -i \"%s\" -c:v copy  -c:a copy  -strict -2  -f hls  -hls_time 5  -hls_list_size 0  " +" -hls_segment_filename \"%s%s \"%s/index.m3u8\" ", file, dir, "/%04d.ts\"", dir);return doExeCommd(cmd);}private  boolean exec(String cmd) {log.info("待执行的命令:" + cmd);try {Runtime rt = Runtime.getRuntime();Process proc = rt.exec(cmd);InputStream stderr = proc.getErrorStream();InputStreamReader isr = new InputStreamReader(stderr);BufferedReader br = new BufferedReader(isr);String line = null;while ((line = br.readLine()) != null){log.debug("执行结果" + line);}return true;} catch (IOException e) {e.printStackTrace();}return false;}
}

2、下载m3u8文件

通用文件下载接口

注意:

针对m3u8格式需要定义特殊的contentType

response.setHeader("Content-Type", "application/vnd.apple.mpegurl");

具体代码如下:

 import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;/*** 通用请求处理** @author xuancg*/
@RestController
@RequestMapping("/profile")
@Slf4j
public class ProfileController {@Resourceprivate MinioFileService minioFileService;@GetMapping("/**")public void profile(HttpServletRequest request, HttpServletResponse response) {String path = request.getServletPath();if(path.startsWith("/profile")){path = path.substring(8);}// TODO minio下载,依据实际自定义File tempFile = minioFileService.download(path);if(null != tempFile && tempFile.isFile()){preview(tempFile, response);}}public void preview(File file, HttpServletResponse response) {try(InputStream ins = new FileInputStream(file);ServletOutputStream outStream = response.getOutputStream()) {String fileName = file.getName();// 替换文件名中的非数字、字母、点、下划线fileName = fileName.replaceAll("[^0-9a-zA-Z._-]", "");// 设置响应头response.setHeader("Content-Disposition", "attachment;filename=" + fileName);response.setContentLength(ins.available());// 如果是m3u8 格式 设置if(fileName.endsWith(".m3u8")){response.setHeader("Content-Type", "application/vnd.apple.mpegurl");} else{response.setContentType(FileUtils.getContentType(file.getName()));}// 写入文件内容byte[] buffer = new byte[4096];int bytesRead = -1;while ((bytesRead = ins.read(buffer)) != -1) {outStream.write(buffer, 0, bytesRead);}outStream.flush();} catch (Exception e) {log.error("下载失败", e);}}}

3、创建m3u8播放器

3.1 引入依赖

npm install video.js videojs-contrib-hls --save

3.2 定义播放器

在 component/M3u8Player文件夹下
创建  index.vue 文件

<template><div class="m3u8-player-container"><div class="player-wrapper"><video ref="videoPlayer" class="video-js vjs-big-play-centered" controls:width="width":height="height"><p class="vjs-no-js">请启用JavaScript以观看视频</p></video></div><!-- <div class="control-panel" v-if="showControlPanel"><div class="form-group"><label for="m3u8Url">M3U8地址:</label><input type="text" id="m3u8Url" v-model="videoUrl" placeholder="输入M3U8视频地址"class="url-input"></div><button @click="loadVideo" class="load-button":disabled="!videoUrl">加载视频</button></div> --><div class="status-message" v-if="statusMessage">{{ statusMessage }}</div></div></template><script>import videojs from 'video.js';import 'video.js/dist/video-js.css';import 'videojs-contrib-hls';export default {name: 'M3u8Player',props: {// 视频地址videoUrl: {type: String,default: ''},// 播放器宽度width: {type: String,default: '100%'},// 播放器高度height: {type: String,default: 'auto'},// 是否显示控制面板showControlPanel: {type: Boolean,default: true}},data() {return {player: null,statusMessage: '',baseUrl: process.env.VUE_APP_BASE_API,};},mounted() {// 初始化播放器this.initPlayer();// 如果有初始视频地址,自动加载if (this.videoUrl) {this.loadVideo();}},beforeUnmount() {// 销毁播放器实例if (this.player) {this.player.dispose();this.player = null;}},methods: {// 初始化播放器initPlayer() {const videoElement = this.$refs.videoPlayer;// 创建播放器实例this.player = videojs(videoElement, {autoplay: false,controls: true,responsive: true,fluid: true,sources: []});// 监听错误事件this.player.on('error', (error) => {console.error('视频播放错误:', error);this.statusMessage = '视频播放出错,请检查地址是否正确';});// 监听加载事件this.player.on('loadedmetadata', () => {this.statusMessage = '';});},// 加载视频loadVideo() {if (!this.player) {this.initPlayer();}if (!this.videoUrl) {this.statusMessage = '请输入有效的M3U8地址';return;}// 显示加载状态this.statusMessage = '正在加载视频...';// 设置视频源this.player.src({src: this.baseUrl + this.videoUrl,type: 'application/x-mpegURL' // M3U8格式});// 尝试加载视频this.player.load();}},watch: {// 监听视频地址变化,自动加载新视频videoUrl(newVal) {if (newVal && this.player) {this.loadVideo();}}}};</script><style scoped>.m3u8-player-container {max-width: 1200px;margin: 0 auto;padding: 20px;}.player-wrapper {border-radius: 8px;overflow: hidden;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);background-color: #000;}.control-panel {margin-top: 20px;display: flex;gap: 10px;align-items: center;}.form-group {flex: 1;}.url-input {width: 100%;padding: 8px 12px;border: 1px solid #ddd;border-radius: 4px;font-size: 14px;}.load-button {padding: 8px 16px;background-color: #42b983;color: white;border: none;border-radius: 4px;cursor: pointer;transition: background-color 0.3s;}.load-button:disabled {background-color: #cccccc;cursor: not-allowed;}.load-button:not(:disabled):hover {background-color: #359e75;}.status-message {margin-top: 10px;padding: 8px;border-radius: 4px;color: #666;font-size: 14px;}</style>

3.3 加载组件

修改main.js 文件

import M3u8Player from '@/components/M3u8Player'Vue.component('M3u8Player', M3u8Player)

4、加载播放

<m3u8-player

                :videoUrl="url"

                width="100%"

                :showControlPanel="true"

              />

5、补充Nginx 代理配置

可以使用本地磁盘 方式  alias /etc/nginx/hls;  

或者使用远程资源下载  proxy_pass    http://192.168.1.1:8080/profile/hls;

其中 hls 为自定义路径

location /profile/hls {proxy_pass    http://192.168.1.1:8080/profile/hls;# alias /etc/nginx/hls/;  # 注意:使用 alias,不是 rootproxy_set_header  Host            $host;proxy_set_header  X-Real-IP       $remote_addr;proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;add_header Cache-Control no-cache;add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods GET;# 关键:设置正确的 MIME 类型types {application/vnd.apple.mpegurl m3u8;video/MP2T ts;}default_type application/vnd.apple.mpegurl;}
http://www.dtcms.com/a/422893.html

相关文章:

  • 网站推广目标关键词龙岩网站设计找哪家好
  • 【论文阅读】ASPS: Augmented Segment Anything Model for Polyp Segmentation
  • 精读C++20设计模式——结构型设计模式:享元模式
  • FT8430-LRT非隔离5V100MA电源芯片,满足小家电、智能照明、MCU供电需求,替代阻容降压(典型案例,电路图)
  • [论文阅读]Benchmarking Poisoning Attacks against Retrieval-Augmented Generation
  • 精读C++20设计模式:结构型设计模式:装饰器模式
  • (数据结构)链表OJ——刷题练习
  • 怎么做网站源码温州建网站
  • 云服务器做淘客网站苏州网站制作及推广
  • hive启动报错
  • (基于江协科技)51单片机入门:6.串口
  • UE5 小知识点 —— 09 - 旋转小问题
  • Git 暂存文件警告信息:warning: LF will be replaced by CRLF in XXX.java.
  • 石狮网站建设价格万网网站根目录
  • VBA ADO使用EXCEL 8.0驱动读取 .xlsx 格式表格数据-有限支持
  • freeswitch集成离线语音识别funasr
  • 建设网站管理规定源码做网站图文教程
  • Qt 入门:构建跨平台 GUI 应用的强大框架
  • Spring WebFlux调用生成式AI提供的stream流式接口,实现返回实时对话
  • 【学习笔记】高质量数据集
  • 微美全息科学院(WIMI.US):互信息赋能运动想象脑电分类,脑机接口精度迎来突破!
  • 协议 NTP UDP 获取实时网络时间
  • 公司网站可以分两个域名做吗残疾人网站服务平台
  • spark pipeline 转换n个字段,如何对某个字段反向转换
  • 学习React-18-useCallBack
  • 长沙制作网站的公司与传统市场营销的区别与联系有哪些
  • 从语言到向量:自然语言处理核心转换技术的深度拆解与工程实践导论(自然语言处理入门必读)
  • 无人设备遥控器之无线发射接收技术篇
  • 《从数组到动态顺序表:数据结构与算法如何优化内存管理?》
  • 浏览器正能量网站2021网页设计免费模板图片