前端播放大视频卡顿的解决(m3u8视频流)

Posted 无知的小菜鸡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端播放大视频卡顿的解决(m3u8视频流)相关的知识,希望对你有一定的参考价值。

前言

最近在一个大屏看板项目中有一个需求是:要求视频和看板要进行来回切换。
最开始的做法是将MP4视频放在项目里,在本地运行时是没什么问题的,但是在往仓库里提交代码时出现了问题。当单个文件超过100MB时会导致代码提交失败;
后来的解决方案是将视频文件放到服务器上,项目里直接加载视频在服务器上的地址。但是这样也存在一个问题,就是视频加载会卡顿。video标签是边加载边播放,这样造成了视频播放几秒后会加载视频导致视频卡住,影响实际效果。

查询到的解决方案是将mp4视频转换成m3u8视频流的格式进行播放,因此打算尝试一下。下面会分别介绍:
1、将mp4视频转换为m3u8视频流
2、前端如何播放m3u8视频

将mp4视频转换为m3u8视频流

m3u8格式

m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8。M3U文件是一个记录索引的纯文本文件,打开它时播放软件并不是播放它,而是根据它的索引找到对应的音视频文件的网络地址进行在线播放。

方法/步骤

主流的方式是通过 m3u8格式视频转码工具 FFmpeg 来实现的

下载

从网上找了个百度云下载地址:https://pan.baidu.com/s/1dCK-TrOcUfC6pdKi2Y1e6g
提取码:2pdo

下载完解压后可以在bin文件嘉下看到三个可执行文件,配置好相应的环境变量后即可使用

环境变量配置


在cdm终端里输入:ffmpeg -version,如下图表示安装成功。

常用命令
ffmpeg 常用命令

分割视频
在视频所在的文件夹下打开cmd终端,输入:

 ffmpeg -i video1.mp4 -profile:v  baseline -level 3.0 -start_number 0 -hls_time 1 -hls_list_size 0 -f hls demo.m3u8
  • -i 指定输入的文件名

  • -profile:v baseline 大概意思是档次转成基本画质,有四种画质级别,分别是baseline, extended, main, high,从低到高

  • -level 3.0 大概也是视频画质级别吧,基本上是从1到5,

  • -start_number 0 表示从0开始

  • -hls_time 1 标识每1秒切一个

  • -f hls 将视频转为hls格式

  • -hls_list_size 0 ,设置播放列表保存的最多条目,设置为 0 会保存有所片信息,默认值为5。

其他的命令不清楚,需要什么功能,基本都可以百度到

成功后可以得到下面的文件

注意:
ts文件的切割还与两个帧之间的时间间隔有关,任何一个ts分片的第一帧必须是1帧,否则无法进行播放。因此有时候并不会按照指定的时间进行分割
解决:
既然知道要1秒产生一个ts分片,那就必须产生切片的过程中,强制一秒中产生一个关键帧。设置关键帧间隔,设置间隔为 2 秒的参数如下:-force_key_frames "expr:gte(t,n_forced*2)“

 ffmpeg -i video1.mp4 -force_key_frames "expr:gte(t,n_forced*2)" -profile:v  baseline -level 3.0 -start_number 0 -hls_time 1 -hls_list_size 0 -f hls demo.m3u8

57秒的视频一共生产了30个片段,有可能我理解的还是有些问题,毕竟从来没用用过

如果有播放器的话,将m3u8这个文件拖到播放器里就可以进行播放了

前端播放

前端播放m3u8视频需要借助:video.jsvideojs-contrib-hls.js

安装依赖

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

使用

import 'video.js/dist/video-js.css';
import videojs from 'video.js';
import 'videojs-contrib-hls';
<video id="singleVideo" autoplay="autoplay" class="video-js vjs-default-skin"></video>

this.singlePlayer = videojs('singleVideo',
    autoplay: true,// 自动播放
    controls: true,// 控件显示
    width: '440',// 视频框宽度
    height: '264',// 视频框高度
    preload: 'auto', //定义视频加载模式
    loop:true, //是否循环播放
);
let res = 'http://61.175.121.73:83/pag/10.13.7.2/7302/33052182001320012936/0/MAIN/TCP/live.m3u8';
if (res) 
    this.singlePlayer.src( src: res, type: 'application/x-mpegURL' );
    this.singlePlayer.play();

video标签上添加的类video-js vjs-default-skinvideojs上的样式,如果不添加会有显示问题。
videojs的属性和方法应该大部分都是与video标签对应的

效果图

问题

服务器上的视频在播放时有可能会报跨域,例如:

一般是nginx没有配置m3u8的文件格式,可以让运维人员看一下:nginx HLS m3u8播放视频跨域问题

视频播放因视频过大产生卡顿

本文章旨在记录解决网页播放较大视频文件这一问题中积累到的知识点。

一、前后端技术都不变的基础上,如何提升视频播放速度

后端上传视频文件走的直接是普通文件上传,提供的文件接口也是media。
前端仅使用了<video src="">,src中的链接即后端提供的url。

这时候会发生,播放视频很卡的现象,当视频大于100M会出现基本每秒的播放都要卡顿。

使用nginx的静态文件代理,url含media直接让它到nginx的指定路径下找文件,nginx的该文件夹和django的media文件夹是共享的。这么处理速度上来很多,但还是有点卡(跟老网站的直接读静态文件相比)
docker-compose.yml

version: "3"

services:
  db:
    image: postgres
    expose:
      - "5432"
    environment:
      POSTGRES_PASSWORD: '***'
      POSTGRES_USER: 'postgres'
      POSTGRES_DB: '***'
      PGDATA: '/var/lib/postgresql/data/pgdata'
    volumes:
        - ./postgres/data:/var/lib/postgresql/data/pgdata
    restart: always

  web:
    build: ./web
    expose:
      - "8000"
    volumes:
      - ./web/media:/home/**/media
      - ./web/cntechsite:/home/**/cntechsite
      - ./uwsgi:/tmp # 挂载uwsgi日志
    depends_on:
      - db
    # environment:
    #   - DEBUG=False
    tty: true #同docker run指令参数,表示分配tty设备,该可以支持终端登录
    stdin_open: true

  nginx:
    build: ./nginx
    restart: always
    ports:
      - "**:80"
    expose:
      - "80"
    volumes:
      - ./web/media:/usr/share/nginx/html/media
    depends_on:
      - web
    links:
      - web

nginx/Dockerfile

FROM nginx:latest

# 删除原有配置文件,创建静态资源文件夹和ssl证书保存文件夹
RUN rm /etc/nginx/conf.d/default.conf \\
    && mkdir -p /usr/share/nginx/html/media
# && mkdir -p /usr/share/nginx/html/static \\
# && mkdir -p /usr/share/nginx/ssl


# 设置Media文件夹用户和用户组为Linux默认www-data, 并给予可读和可执行权限,
# 否则用户上传的图片无法正确显示。
RUN chown -R www-data:www-data /usr/share/nginx/html/media \\
    && chmod -R 775 /usr/share/nginx/html/media

# 添加配置文件
ADD ./nginx.conf /etc/nginx/conf.d/

# 添加ssl证书
ADD ./**.crt /etc/nginx/certs/
ADD ./**.key /etc/nginx/certs/

# 关闭守护模式
CMD ["nginx", "-g", "daemon off;"]

nginx/nginx.conf

upstream django 
    ip_hash;
    server web:8000; # Docker-compose web服务端口


server 
    listen 80 ssl; # 监听80端口
    server_name localhost; # 可以是nginx容器所在ip地址或127.0.0.1,不能写宿主机外网ip地址

    charset utf-8;
    client_max_body_size 10240M; # 限制用户上传文件大小
    # client_body_buffer_size 100M;

    ssl_certificate     /etc/nginx/certs/ssl-33-cntechcom2020.crt;
    ssl_certificate_key /etc/nginx/certs/ssl-33-cntechcom2020.key;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    #location /static 


    location / 
        include /etc/nginx/uwsgi_params;
        uwsgi_pass django;
        uwsgi_read_timeout 1200;
        uwsgi_connect_timeout 600;
        uwsgi_send_timeout 1200;
        uwsgi_max_temp_file_size 10240M;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP  $remote_addr;
        # proxy_pass http://django; # 使用uwsgi通信,而不是http,所以不使用proxy_pass。
    

    location /media  
        alias /usr/share/nginx/html/media;
    



    access_log /var/log/nginx/access.log main;
    error_log /var/log/nginx/error.log warn;

    server_tokens off;

做了一下比较,老网站使用了阿里云的负载均衡。我寻思就一个服务器,用负载均衡有用吗,还是加了一下,结果真的有用。至于这个原理我就不懂。

二、对上传视频进行压缩

一中的方法感觉对小体积视频比较有效,但体积一旦变大可能就会有些危险,因为没有从本质解决问题。对上传视频进行压缩也算是一种无奈之举。

三、采用主流视频网站的解决方案

这里就涉及到大改代码了。搜了一下解决方案,直接贴链接了,因为还没打算改。
视频在线播放卡慢,如何实现视频分片加载呢?前段 vue,后台 go
网页视频加载慢
求助:关于视频播放的方案

以上是关于前端播放大视频卡顿的解决(m3u8视频流)的主要内容,如果未能解决你的问题,请参考以下文章

视频播放因视频过大产生卡顿

Cesium性能优化:如何平衡场景渲染与视频播放?

阿里云实践 - HTML5断点播放m3u8视频(videojs)

如何打造支撑多种视频播放诉求的大前端播放器?

Chimee - 简单易用的H5视频播放器解决方案

m3u8格式转换mp4