直播流播放实现

技术栈:

  1. 后端:node + ffmpeg + WebSocket
  2. 前端:vue + fiv.js

实现逻辑:

  • 后端启动WebSocket服务,根据ffmpeg工具实现实时转流,对实时流进行格式转换输出flv格式,前端使用flv.js插件播放flv格式的视频

一、后端

  1. 安装依赖包,fluent-ffmpeg是基于ffmpeg工具命令的依赖

    npm install fluent-ffmpeg ws websocket-stream --save
  1. 安装ffmpeg二进制,不安装服务端会出现报错:An error occurred: Cannot find ffmpeg

    npm i @ffmpeg-installer/ffmpeg
  1. 完整代码

    const WebSocket = require('ws')
    const webSocketStream = require('websocket-stream/stream')
    const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path
    const ffmpeg = require('fluent-ffmpeg')
    ffmpeg.setFfmpegPath(ffmpegPath)
    
    // 建立WebSocket服务
    const wss = new WebSocket.Server({ port: 8881, perMessageDeflate: false })
    
    // 监听连接
    wss.on('connection', handleConnection)
    
    // 连接时触发事件
    function handleConnection(ws, req) {
      // 获取前端请求的流地址(前端websocket连接时后面带上流地址)
      const url = req.url.slice(1)
      // 传入连接的ws客户端 实例化一个流
      const stream = webSocketStream(ws, { binary: true })
      // 通过ffmpeg命令 对实时流进行格式转换 输出flv格式
      const ffmpegCommand = ffmpeg(url)
        .addInputOption('-analyzeduration', '100000', '-max_delay', '1000000')
        .on('start', function () { console.log('Stream started.') })
        .on('codecData', function () { console.log('Stream codecData.') })
        .on('error', function (err) {
          console.log('An error occured: ', err.message)
          stream.end()
        })
        .on('end', function () {
          console.log('Stream end!')
          stream.end()
        })
        .outputFormat('flv').videoCodec('copy')
      // .outputFormat('flv').videoCodec('copy').noAudio() // 取消音频输出
    
      stream.on('close', function () {
        ffmpegCommand.kill('SIGKILL')
      })
    
      try {
        // 执行命令 传输到实例流中返回给客户端
        ffmpegCommand.pipe(stream)
      } catch (error) {
        console.log(error)
      }
    }

二、前端

  1. 安装依赖包

    npm install flv.js --save
  1. 完整代码

    <template>
        <div class="video-wrap">
            <div class="input-wrap">
                <input v-model="url" placeholder="请输入视频地址, 支持rtsp/rtmp格式" />
                <button @click="onPlay">播放</button>
            </div>
            <video muted="muted" controls width="100%" height="600" ref="video"></video>
        </div>
    </template>
    
    <script>
    import flvjs from 'flv.js';
    export default {
        data() {
            return {
                flvPlayer: null,
                url: 'rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid' 
            };
        },
        beforeDestroy() {
            this.destoryVideo();
        },
        methods: {
            // 播放
            onPlay() {
                if (this.url && this.isPushUrl(this.url)) {
                    console.log(1111111111);
                    this.play()
                }
            },
            // 判断地址是否正确
            isPushUrl(url) {
                const RegExp = /^((rtmp|rtsp|http|https):\/\/)(\S+\/)+\S+$/;
                return RegExp.test(url);
            },
            // 创建video
            createVideo() {
                if (flvjs.isSupported()) {
                    const videoElement = this.$refs.video;
                    this.flvPlayer = flvjs.createPlayer(
                        {
                            type: 'flv',
                            isLive: true,
                            hasAudio: true,
                            url: 'ws://localhost:8881/' + this.url
                        },
                        {
                            // cors: true, // 是否跨域
                            // enableWorker: true, // 是否多线程工作
                            enableStashBuffer: false, // 是否启用缓存
                            // stashInitialSize: 128, // 缓存大小(kb)  默认384kb
                            autoCleanupSourceBuffer: true, // 是否自动清理缓存
                            fixAudioTimestampGap: false, //false才会音视频同步
                            deferLoadAfterSourceOpen: false
                        }
                    );
                    this.flvPlayer.attachMediaElement(videoElement);
                    try {
                        this.flvPlayer.load();
                        this.flvPlayer.play();
                    } catch (error) {
                        console.log(error);
                    };
                    // 报错重连
                    this.flvPlayer.on(flvjs.Events.ERROR, (errType, errDetail) => {
                        console.log('errorType:', errType);
                        console.log('errorDetail:', errDetail);
                        this.play()
                    });
                }
            },
            // 销毁video
            destoryVideo() {
                if (this.flvPlayer) {
                    this.flvPlayer.pause();
                    this.flvPlayer.unload();
                    this.flvPlayer.detachMediaElement();
                    this.flvPlayer.destroy();
                    this.flvPlayer = null;
                }
            },
            // 重播/播放
            play() {
                if (this.flvPlayer) {
                    this.destoryVideo();
                }
                this.createVideo();
            }
        }
    };
    </script>
    
    <style scoped>
    .video-wrap {
        width: 850px;
        margin: 0 auto;
        padding: 20px;
        border: 1px solid #ccc;
    }
    
    video {
        background-color: #000;
    }
    
    .input-wrap {
        margin-bottom: 10px;
        display: flex;
        align-items: center;
    }
    
    input {
        height: 32px;
        line-height: 32px;
        border: 1px solid #ccc;
        padding: 0 10px;
        flex: 1;
    }
    
    input:focus-visible {
        outline: none;
    }
    
    button {
        height: 32px;
        width: 60px;
        margin-left: 10px;
    }
    </style>

三、测试url

  1. 公网 rtmp 测试地址:

    邓紫棋 多美丽mv (非常流畅秒开级别,强烈推荐)
    地址:rtmp://liteavapp.qcloud.com/live/liteavdemoplayerstreamid (可用)
    伊拉克 Al Sharqiya 电视台 (有卡顿延迟)
    地址:rtmp://ns8.indexforce.com/home/mystream (可用)
    韩国GOOD TV (不推荐太卡,很慢)
    地址:rtmp://mobliestream.c3tv.com:554/live/goodtv.sdp (可用)
  1. 公网 m3u8 测试地址:
    http格式地址

    计时器 m3u8 (可用)
    http://devimages.apple.com/iphone/samples/bipbop/gear1/prog_index.m3u8
    计时器 m3u8 (可用)
    http://devimages.apple.com/iphone/samples/bipbop/gear3/prog_index.m3u8
    计时器 m3u8 (可用)
    http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8
    大海 m3u8 (可用)
    http://kbs-dokdo.gscdn.com/dokdo_300/definst/dokdo_300.stream/playlist.m3u8

    https格式地址

    钢铁之泪 m3u8 (12:14分钟) (可用)
    https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8
    fMP4 m3u8 (10:00分钟) (可用)
    https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8
    钢铁之泪 MP4 m3u8 (12:14分钟) (可用)
    https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8
    实时 Akamai m3u8 (10:00分钟) (可用)
    https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8
    实时 Akamai m3u8 (2:00分钟) (可用)
    https://moctobpltc-i.akamaihd.net/hls/live/571329/eight/playlist.m3u8
    大熊兔 m3u8 (10:34分钟) (可用)
    https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8
  1. 公网 flv 测试地址:
    大熊兔flv (可用)

    https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_1mb.flv
    https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_2mb.flv
    https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_5mb.flv
    https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_10mb.flv
    https://sample-videos.com/video123/flv/720/big_buck_bunny_720p_20mb.flv
  1. 公网 mkv 测试地址:
    已测试 (可用)

    https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv
    https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_2mb.mkv
    https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_5mb.mkv
    https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_10mb.mkv
  1. 公网 3gp 测试地址:
    已测试 (可用)

    https://sample-videos.com/video123/3gp/144/big_buck_bunny_144p_1mb.3gp
    https://sample-videos.com/video123/3gp/144/big_buck_bunny_144p_2mb.3gp
    https://sample-videos.com/video123/3gp/144/big_buck_bunny_144p_5mb.3gp
    https://sample-videos.com/video123/3gp/144/big_buck_bunny_144p_10mb.3gp
  1. 公网 mp4 测试地址:
    已测试 (可用)

    http://www.w3school.com.cn/i/movie.mp4
    http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
    http://vjs.zencdn.net/v/oceans.mp4
    https://media.w3.org/2010/05/sintel/trailer.mp4
  1. 2023-11-24 更新(可用) 经测试上面mp4地址很卡,特此更新下面的地址

    https://v-cdn.zjol.com.cn/280443.mp4
    https://v-cdn.zjol.com.cn/276982.mp4
    https://v-cdn.zjol.com.cn/276984.mp4
    https://v-cdn.zjol.com.cn/276985.mp4
    https://media.w3.org/2010/05/sintel/trailer.mp4

结尾:

  1. 实现源码地址:https://gitee.com/jias0606/stream-to-video
  2. 测试URL文章地址:https://blog.csdn.net/u014696856/article/details/134444974
最后修改:2023 年 12 月 12 日
如果觉得我的文章对你有用,请随意赞赏