唠嗑部分
视频点播方案如下:
1.播放器通过 http协议从http服务器上下载视频文件进行播放
问题:必须等到视频下载完才可以播放,不支持快进到某个时间点进行播放
2.播放器通过rtmp协议连接媒体服务器以实时流方式播放视频
使用rtmp协议需要架设媒体服务器,造价高,对于直播多采用此方案。
3.播放器使用HLS协议连接http服务器(Nginx、Apache等)实现近实时流方式播放视频
HLS协议规定:基于Http协议,视频封装格式为ts,视频的编码格式为H264,音频编码格式为MP3、AAC或者AC-3
什么是HLS?
HLS的工作方式是:将视频拆分成若干ts格式的小文件,通过m3u8格式的索引文件对这些ts小文件建立索引。一般10秒一个ts文件,播放器连接m3u8文件播放,当快进时通过m3u8即可找到对应的索引文件,并去下载对应的ts文件,从而实现快进、快退以近实时的方式播放视频。
IOS、Android设备、及各大浏览器都支持HLS协议。
今天我们使用SpringBoot+Nginx实现一下视频在线点播
言归正传
1、ffmpeg的使用
FFmpeg被许多开源项目采用,QQ影音、暴风影音、VLC等。
下载:FFmpeg https://www.ffmpeg.org/download.html#build-windows
将安装们目录配置于环境变量之中
检测是否安装成功
生成m3u8/ts文件
使用ffmpeg生成 m3u8的步骤如下:
第一步:先将avi视频转成mp4
ffmpeg.exe -i lucene.avi -c:v libx264 -s 1280x720 -pix_fmt yuv420p -b:a 63k -b:v 753k -r 18 .lucene.mp4
下面把各参数意思大概讲讲,大概了解意思即可,不再此展开流媒体专业知识的讲解。
-c:v 视频编码为x264,x264编码是H264的一种开源编码格式。
-s 设置分辨率
-pix_fmt yuv420p:设置像素采样方式,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0,它的作用是根据采样方式来从码流中还原每个像素点的YUV(亮度信息与色彩信息)值。
-b 设置码率,-b:a和-b:v分别表示音频的码率和视频的码率,-b表示音频加视频的总码率。码率对一个视频质量有很大的作用。
-r:帧率,表示每秒更新图像画面的次数,通常大于24肉眼就没有连贯与停顿的感觉了。
第二步:将mp4生成m3u8
ffmpeg -i F:testtest.mp4 -c:v copy -c:a copy -f ssegment -segment_format mpegts -segment_list F:m3u8hlstest.m3u8 -segment_time 10 F:m3u8hlstest%05d.ts
-hls_time 设置每片的长度,单位为秒
-hls_list_size n: 保存的分片的数量,设置为0表示保存所有分片
-hls_segment_filename :段文件的名称,%05d表示5位数字
生成的效果是:将test.mp4视频文件每10秒生成一个ts文件,最后生成一个m3u8文件,m3u8文件是ts的索引文件。
使用VLC打开m3u8文件,测试播放效果,VLC 是一款自由、开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD、音频 CD、VCD 及各类流媒体协议。
m3u8转MP4文件
ffmpeg -i F:m3u8hls16797714183488634901679771418348863490.m3u8 -c copy aaaa.mp4
2、Java使用ffmpeg生成m3u8
file:
upload-path: "F:\movie_online"
ffmpeg-path: D:\software\ffmpeg\ffmpeg-n5.1-latest-win64-lgpl-shared-5.1\bin\ffmpeg.exe
target-path: "F:\m3u8\hls\"
代码
FileHandleUtil.java
@Component
public class FileHandleUtil {
private String filePath;
private String targetPath;
private String ffmpegPath;
// originFile 文件全路径 fileName 文件名
public void mp4TranM3u8Ts(String originFile, String fileName){
File file = new File(originFile);
if (!file.exists()) {
throw new RuntimeException("源文件不存在");
}
File targetFile = new File(targetPath + fileName);
if (!targetFile.exists()) {
targetFile.mkdir();
}
String output = targetPath + fileName + File.separator + fileName + ".m3u8";
List<String> command = new ArrayList<>();
command.add(ffmpegPath);
command.add("-i");
command.add(originFile);
command.add("-c:v");
command.add("copy");
command.add("-c:a");
command.add("copy");
command.add("-f");
command.add("ssegment");
command.add("-segment_format");
command.add("mpegts");
command.add("-segment_list");
command.add(output);
command.add("-segment_time");
command.add("10");
String ts = targetPath + fileName + File.separator + fileName + "%05d.ts";
command.add(ts);
ProcessUtil.execute(command);
}
}
ProcessUtil.java
public class ProcessUtil {
public static String execute(List<String> command) {
StringBuffer inputStringBuffer = new StringBuffer();
StringBuffer errorStringBuffer = new StringBuffer();
try {
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
System.out.println("============inputStream============");
// 处理InputStream
Thread t1 = new Thread(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getInputStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String inputLine = "";
while ((inputLine = buffer.readLine()) != null) {
System.out.println(inputLine);
inputStringBuffer.append(inputLine);
}
//退出循环后表示结束流
System.out.println("===》》退出循环后表示结束流");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t1.setName("deviceName");
t1.start();
System.out.println("============errorStream============");
// 处理ErrorStream
new Thread(() -> {
InputStream input = null;
InputStreamReader reader = null;
BufferedReader buffer = null;
try {
input = process.getErrorStream();
reader = new InputStreamReader(input);
buffer = new BufferedReader(reader);
String errorLine = "";
while ((errorLine = buffer.readLine()) != null) {
System.out.println(errorLine);
errorStringBuffer.append(errorLine);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (buffer != null) {
buffer.close();
}
if (reader != null) {
reader.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
/**
* 只会存在一个输入流返回
*/
if (inputStringBuffer != null) {
return inputStringBuffer.toString();
}
if (errorStringBuffer != null) {
return errorStringBuffer.toString();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
}
文件上传部分省略了,在文件上传后,使用上述工具类将视频转为m3u8/ts文件,保存在配置好的F:m3u8hls目录即可
3、Nginx文件服务器配置
server {
listen 80;
server_name localhost;
charset utf-8;
location ^~ /hls/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias F:/m3u8/hls/;
expires -1;
add_header Cache-Control no-cache;
}
}
文件夹目录
4、H5代码
需要使用两个库,可在cdn下载,相关资料也会上传群文件
>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试视频播放title>
<script type="text/javascript" src="video-6.7.3.js">script>
<script type="text/javascript" src="videojs-contrib-hls-5.14.1.min.js">script>
"video.js_6.7.3.min.css" rel="stylesheet" type="text/css"/>
head>
<body>
="example-video" width="800" height="600" controls poster="http://127.0.0.1:8888/hls/add.png" class="video-js vjs-default-skin vjs-big-play-centered">
<source src="http://127.0.0.1/hls/1679771414267805698/1679771414267805698.m3u8" type="application/x-mpegURL">
video>
<input type="button" onclick="switchvideo()" value="switch"/>
<script type="text/javascript">
var player = videojs('example-video');
function switchvideo() {
player.src({
src: 'http://127.0.0.1/hls/1679769948731760641/1679769948731760641.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
})
player.play();
}
script>
body>
html>
5、测试
在nginx安装目录下启动nginx,打开页面
结语
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=14637,转载请注明出处。
评论0