前端实现H265编码的m3u8视频流播放

2023-12-26 17:34:41

前言

视频监控是智慧城市、智慧园区等WebGIS类系统中最为常见的硬件对接设备,最常用的监控视频流格式为m3u8格式,但是m3u8格式通常都是h.265编码格式的,我搜遍了几乎所有前端视频播放插件,几乎普通的播放器插件都不支持h.265格式的视频编码。本文就带领大家了解H265视频编码,并实现前端播放H265编码的视频。

1. 什么是H.265编码?

目前很多摄像机采用了H.265的编码标准,H.264编码的摄像机逐渐减少,为什么H.265会流行?H.264和H.265有何不同?

H.265是ITU-TVCEG继H.264之后所制定的新的视频编码标准。H.265标准围绕着现有的视频编码标准H.264,保留原来的某些技术,同时对一些相关的技术加以改进。新技术使用先进的技术用以改善码流、编码质量、延时和算法复杂度之间的关系,达到最优化设置。具体的研究内容包括:提高压缩效率、提高鲁棒性和错误恢复能力、减少实时的时延、减少信道获取时间和随机接入时延、降低复杂度等。H264由于算法优化,可以低于1Mbps的速度实现标清数字图像传送;H265则可以实现利用1~2Mbps的传输速度传送720P(分辨率1280*720)普通高清音视频传送。

H.265旨在在有限带宽下传输更高质量的网络视频,仅需原先的一半带宽即可播放相同质量的视频。这也意味着,我们的智能手机、平板机等移动设备将能够直接在线播放1080p的全高清视频。H.265标准也同时支持4K(4096×2160)和8K(8192×4320)超高清视频。可以说,H.265标准让网络视频跟上了显示屏“高分辨率化”的脚步。 

H.265虽然有点有很多,但是也有最大劣势。因为大佬级别公司神仙打架凡人遭殃,h265编码的视频不能直接在电脑端浏览器播放(部分电脑端的播放器软件支持播放),手机端(主要是安卓和苹果)是可以在浏览器直接播放的。所以,如果要使用h265编码的视频,你的浏览器端客户只能限制在手机端,电脑端浏览器用户考虑其他方案。

2. 解决Web端播放H265的方法

1.?第一种就是使用ffmpeg(FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案)进行转码,这种方案可能比较稳定,但是成本较高,而且实现比较复杂。

2. 使用前端视频播放插件,我在开发过程中尝试了很多很多前端的视频插件,都无法播放H265编码的视频。终于发现了这个开源免费的前端播放插件EasyPlayer.js。它通过和webassembly结合,实现了web端支持H265视频的播放,使用起来也很简单,GitHub开源地址:

GitHub - tsingsee/EasyPlayer.js: EasyPlayer.js H5播放器,是一款免费的能够同时支持HTTP、RTMP、HTTP-FLV、HLS(m3u8)直播与点播等多种协议,支持H.264、H.265、AAC等多种音视频编码格式,支持mse、asm、wasm等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器。EasyPlayer.js H5 Player support HTTP/RTMP/HTTP-FLV/HLS(m3u8) live streaming & vod streaming,support H.264/H.265/AAC video & audio codec,support mse/asm/wasm decode mode,support Windows/Linux/Android/iOS platform,EasyPlayer.js uses leading-edge technology.EasyPlayer.js H5播放器,是一款免费的能够同时支持HTTP、RTMP、HTTP-FLV、HLS(m3u8)直播与点播等多种协议,支持H.264、H.265、AAC等多种音视频编码格式,支持mse、asm、wasm等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器。EasyPlayer.js H5 Player support HTTP/RTMP/HTTP-FLV/HLS(m3u8) live streaming & vod streaming,support H.264/H.265/AAC video & audio codec,support mse/asm/wasm decode mode,support Windows/Linux/Android/iOS platform,EasyPlayer.js uses leading-edge technology. - GitHub - tsingsee/EasyPlayer.js: EasyPlayer.js H5播放器,是一款免费的能够同时支持HTTP、RTMP、HTTP-FLV、HLS(m3u8)直播与点播等多种协议,支持H.264、H.265、AAC等多种音视频编码格式,支持mse、asm、wasm等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器。EasyPlayer.js H5 Player support HTTP/RTMP/HTTP-FLV/HLS(m3u8) live streaming & vod streaming,support H.264/H.265/AAC video & audio codec,support mse/asm/wasm decode mode,support Windows/Linux/Android/iOS platform,EasyPlayer.js uses leading-edge technology.icon-default.png?t=N7T8https://github.com/tsingsee/EasyPlayer.js

EasyPlayer.js简介:EasyPlayer.js H5播放器,是一款免费的能够同时支持HTTP、RTMP、HTTP-FLV、HLS(m3u8)直播与点播等多种协议,支持H.264、H.265、AAC等多种音视频编码格式,支持mse、asm、wasm等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器。?

3. 使用EsayPlayer.js实现前端播放H.265编码的视频流

1. Vue2项目安装EasyPlayer视频播放插件
  npm install @easydarwin/easyplayer --save
?2. 解压后根据说明文档将文件移动到指定位置

(1)node_modules/@easydarwin/easyplayer/dist/component/EasyPlayer.swf 移动到 静态文件 根目录

(2)node_modules/@easydarwin/easyplayer/dist/component/crossdomain.xml 移动到 静态文件 根目录

(3)node_modules/@easydarwin/easyplayer/dist/component/EasyPlayer-lib.min.js 移动到 静态文件 根目录

(4)特别注意:播放H.265视频需要将:node_modules/@easydarwin/easyplayer/dist/component/EasyPlayer.wasm 到 静态文件 根目录

3. 在项目中引入和使用H5视频播放插件

(1)在index.html文件中引入EasyPlayer-lib.min.js

<script src="./EasyPlayer-lib.min.js"></script>

(2)在组件中使用EasyPlayer播放插件

<template>
    <div class="monitor-container">
        <div class="monitor-list-container">
            <div class="monitor-list-title">
                费县视频监控
            </div>
            <div class="monitor-list-scroll-container">
                <div class="monitor-class-name" @click="monitorShow = !monitorShow">
                    <i class="el-icon el-icon-s-grid"></i>
                    费县森林防火视频监控({{ monitorList.length }})
                    <i class="el-icon  el-icon-arrow-down" style="float:right;margin-top:16px;"></i>
                </div>
                <div v-show="monitorShow">
                    <div class="monitor-item" v-for="(item,index) in monitorList" :key="index" >
                        <i class="el-icon el-icon-video-camera"></i>
                        {{ item.cameraname }}
                    </div>
                </div>

                <div class="monitor-class-name" @click="monitor2Show = !monitor2Show">
                    <i class="el-icon el-icon-s-grid"></i>
                    市应急指挥视频监控({{ monitorList2.length }})
                    <i class="el-icon  el-icon-arrow-down" style="float:right;margin-top:16px;"></i>
                </div>
                <div  v-show="monitor2Show">
                    <div class="monitor-item" v-for="(item,index) in monitorList2" :key="index" @click="playVideo(item,index)">
                        <i class="el-icon el-icon-video-camera"></i>
                        {{ item.jkdmckjg }}
                    </div>
                </div>
                

            </div>
        </div>
        <div class="video-container">
            <div class="layout-container">

            </div>
                <EasyPlayer
                v-for="(item,index) in playArrays" :key="index"
                style="width:450px;height:250px;float:left;margin-right:15px;margin-bottom:15px;"
                :videoUrl="item"
                :aspect="aspect"
                live
                @message="$message"
                :fluent="fluent"
                :autoplay="true"
                stretch
                ></EasyPlayer>
        </div>
    </div>
</template>

<script>
import EasyPlayer from '@easydarwin/easyplayer'
import axios  from 'axios';
import { getMethodCommon } from '../../../api/common';

import 'video.js/dist/video-js.css'
import videojs from "video.js";
import "videojs-contrib-hls";

export default{
    components:{
        EasyPlayer
    },
    data(){
        return {
            videoUrl:"",
            aspect:"16:9",
            fluent:true,
            playArrays:[],
            monitorShow:false,
            monitor2Show:true,
            monitorList:[],
            monitorList2:[],
            player:null,
        }
    },
    created(){
        this.getHKmonitorlist();
        this.getYJmonitorlist();
    }, 
    mounted() {
        let _this = this;
        setTimeout(()=>{
            
        },5000)
    },
 
    methods:{
        getVideo() {
            videojs("myvideo",{
                bigPlayButton: false,
                textTrackDisplay: false,
                posterImage: true,
                errorDisplay: false,controlBar: true
            },
            function() {
                this.play();
            });
        },
        playVideo(item,index){
            if(this.playArrays.find((it,idx)=>{
                return it == "http://***.***.***.***/live/"+item.jkdgbidzlkjg+".m3u8"
            })){
                this.$message({
                    type:"error",
                    message:"已经添加至播放列表"
                })
                return;
            }
            if(this.playArrays.length>=4){
                this.playArrays.shift();
            }
            this.playArrays.push("http://***.***.***.***:7012/live/"+item.jkdgbidzlkjg+".m3u8")
        },

        // 获取海康监控列表
        getHKmonitorlist(){
            axios({
                method:"get",
                url:"http://***.***.***.***:9007/geoserver/ksp/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=ksp%3Amonitornest&maxFeatures=10000&outputFormat=application%2Fjson",
            }).then(res=>{
                res.data.features.forEach((item,index)=>{
                    let obj = item.properties;
                    this.monitorList.push(obj);
                    if(index<=3){
                        this.playArrays.push("http://***.***.***.***:7012/live/"+item.jkdgbidzlkjg+".m3u8")
                    }
                })
                
            })
        },
        // 市应急局监控设备
        getYJmonitorlist(){
            getMethodCommon("/YingJiJu/LoadCameraInfo?county=费县&pageIndex=1&pageSize=999").then(res=>{
                if(res.code ==  200){
                    this.monitorList2 = res.data;

                }
            })
        },

    }
}
</script>

<style scoped>

.monitor-container{
    width:100%;
    height:100%;
    background:#30645eaa;
    padding:15px;
    background-image: url(/img/biaohui.png);
    background-size:100% 100%;
}

.monitor-list-container{
    width:240px;
    height:100%;
    float:left;
}

.monitor-list-title{
    width:100%;
    height:60px;
    font-size:20px;
    text-indent:15px;
    color:#fff;
    cursor:pointer;
}

.monitor-list-scroll-container{
    width: calc( 100% - 12px);
    height: calc(100% - 60px);
    overflow-y: auto;
    padding-right:12px;
}

.monitor-class-name{
    width:100%;
    height:42px;
    line-height:42px;
    color:#fff;
}
.monitor-item{
    width:100%;
    height:24px;
    line-height:24px;
    color:#cfcfcf;
    font-size:12px;
    text-indent: 4px;
    overflow: hidden;
    cursor: pointer;
}
.monitor-item:hover{
    background:#30645e;
}

.video-container{
    width: calc( 100% - 240px);
    float:right;
    height:100%;
}

.layout-container{
    width:100%;
    height:50px;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
  border: 0;
}

::-webkit-scrollbar {
  height: 10px;
  width: 10px;
  background: transparent;
  border-radius: 5px;
}

::-webkit-scrollbar-thumb {
  padding-top: 100px;
  -webkit-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);
  background-color: rgba(0, 0, 0, 0.4);
  min-height: 28px;
  border-radius: 4px;
  background-clip: padding-box;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
  border: 0;
}

::-webkit-scrollbar-thumb:hover {
    -webkit-box-shadow: inset 1px 1px 0 rgba(0, 0, 0, 0.1),
    inset -1px -1px 0 rgba(0, 0, 0, 0.07);
  background-color: #797979;
}

::-webkit-scrollbar-thumb:active {
  -webkit-box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.35);
  background-color: rgba(0, 0, 0, 0.5);
}
</style>

项目截图:

文章来源:https://blog.csdn.net/qq_41765777/article/details/135224358
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。