Front-end FLV video live broadcast solution

Background of the project:

1. Give an address in the background and continuously push the flv video stream.

2. The front end needs to receive the video stream and find a suitable playback plug-in.

At the beginning:

In fact, the practical one is xgplayer (Xigua Video).

Official website address: Watermelon Player

I am using the live broadcast and flv plug-in: Xigua Player | xgplayer-flv .

But it cannot be played, the phenomenon is that it keeps loading ;

Later, after checking a lot of information, I found an issue:

Streaming data is downloaded normally, but xgplayer-flv cannot be played · Issue #604 · bytedance/xgplayer · GitHub .

I have the same situation, but I don't have a solution yet. Explain that this road is blocked .

There's a bright future:

After searching for a long time, I found a universal playback plug-in——  Jessibuca .

Official website address: Jessibuca

how to use:

How to use the front end? It is recommended to download relevant resources directly and import them statically.

Three resources need to be downloaded, as shown below:

How to find these three resources? Just go and look for it in the network of the official , I won’t go into details.

Usage details in vue:

First, the above three files are imported into public. Only jessibuca.js needs to be introduced in the index.html file .

<!-- 

public下的index.html 直接引入js文件

-->



....


<script src="<%= BASE_URL %>jessibuca.js"></script>





.....

Then, create the video playback component  LiveVideoPlay.vue:

<script>
export default {
  name: "LiveVideoPlay",
  props: {
    // 播放地址
    playUrl: {
      type: String,
      required: true,
    },
    // 目标domid
    id: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      player: null,
    };
  },
  methods: {
    // 初始化视频组件
    initPlayer() {
      if (Jessibuca) {
        this.player = new Jessibuca({
          container: document.getElementById(this.id), //jessibuca需要容器
          videoBuffer: 0.2, // 缓存时长
          isResize: false,
          loadingText: "疯狂加载中...",
          useMSE: true,
          useWCS: true,
          debug: true,
          background: "@/assets/icons/svg/no-video.svg",
          supportDblclickFullscreen: true,
          showBandwidth: true, // 显示网速
          operateBtns: {
            fullscreen: true,
            screenshot: true,
            play: true,
            audio: true,
          },
          forceNoOffscreen: true,
          isNotMute: false,
          timeout: 10,
        });
        //console.log("this.player ----- ", this.player, this.playUrl);
        this.player.play(this.playUrl);
      }
    },
  },
  beforeDestroy() {
    // 销毁视频
    if (this.player) {
      this.player.destroy();
      this.player = null;
    }
  },
  mounted() {
    this.initPlayer();
  },
};
</script>
<template>
  <div class="video-player-outer" :id="id"></div>
</template>
<style>
.video-player-outer {
  width: 100%;
  height: 100%;
}
</style>

Finally, directly referenced in the parent component:

// 父组件中直接使用该组件

<script>
import LiveVideoPlay from "./LiveVideoPlay.vue";
export default {
    name: '',
    components: {
        LiveVideoPlay 
    },
    data () {
        return {
            playUrl1: null,
            playUrl2: null,
            showV1: false,
            showV2: false,
        }
    },
    methods: {
        handlePlayVideo(v) {
      if (v == 1) {
        this.playUrl1 =
          "https://xxxxxx/live/02.live.flv";
        this.showV1 = true;
      } else if (v == 2) {
        this.playUrl2 =
          "https://xxxxxx/live/02.live.flv";
        this.showV2 = true;
      }
    },
    StopPlayVideo(v) {
      if (v == 1) {
        this.showV1 = false;
      } else if (v == 2) {
        this.showV2 = false;
      }
    }, 
    },
}

</script>

<template>

    <div class="box">
          <div class="video-box-item">
            <el-button @click="handlePlayVideo(1)">播放视频1</el-button>
            <el-button @click="StopPlayVideo(1)">停止视频1</el-button>
            <LiveVideoPlay v-if="showV1" :playUrl="playUrl1" id="v1" />
          </div>

          <div class="video-box-item">
            <el-button @click="handlePlayVideo(2)">播放视频2</el-button>
            <el-button @click="StopPlayVideo(2)">停止视频2</el-button>
            <LiveVideoPlay v-if="showV2" :playUrl="playUrl2" id="v2" />
          </div>
    </div>

</template>

As above, you can try to see if your playback address can successfully play the video. If your demand is not that high and you don’t consider the delay, this is basically enough and there is no need to scroll down.

However, if your requirements are relatively high and you don’t want to buy the paid version of jecibuca, then please continue reading below, there are better solutions.

The best of the best:

Now this function has been implemented, but the problem of video delay is more prominent. For example, if I control the camera to rotate its position, in the above solution, it will be obvious that the camera triggers the rotation and then the return video is obviously delayed. What should I do? If you If the requirements are not high, then the above solution is sufficient, but if low latency is required , then you have to use another killer tool -  LiveQing .

Official website address:  LivePlayer H5 player | Qingshi video streaming service solution

How to use? Vue2 is roughly divided into these steps (for vue3+vite, please refer to the official website):

1. Install Liveplayer:

npm install @liveqing/liveplayer

2. Install the webpack plug-in copy-webpack-plugin

npm install [email protected]

Note: If your version is vuecli4.0+, then the above version is enough. But if your version is vuecli5.0+, you need to upgrade the copywebpack-plugins version, such as  [email protected] .Personally tested and effective, be sure to pay attention!!!

3. Configure vue.config.js

/**  vue.config.js   */

// *****  注意 还是vuecli版本的问题
// *****  如果你的vuelci4.0+  就用下边这个配置

const CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {

    ...


    configureWebpack: (config) => {
        config.devtool = "source-map";
        config.output.libraryExport =
                      "default"; /* 解决import UMD打包文件时, 组件install方法执行报错的问题!! */



        // 增加配置如下  主要是 plugins

        const plugins = [
          new CopyWebpackPlugin([
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml",
            },
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf",
            },
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
              to: "livePlayer/",
            },
      ]),
    ];
        config.plugins.push(...plugins);

      
    }
  },


    ...

}


// *****  如果你的vuelci5.0+  就用下边这个配置

const CopyWebpackPlugin = require("copy-webpack-plugin");


module.exports = {


    .....


    chainWebpack(config) {
        
        // 增加插件
        
        config.plugin('copy').use(CopyWebpackPlugin, [

           {
                 patterns: [
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml",
            },
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf",
            },
            {
              from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
              to: "livePlayer/",
            },
      ]
            }
        ])

        
    }
    


}

4. Introduce js files into index.html in public

5. Encapsulate the video playback component

<template>
  <LivePlayer
    class="component-wrapper video-panel"
    :class="{ fullscreen: flag }"
    :videoUrl="options.url"
    :videoTitle="options.title"
    :poster="options.poster"
    :controls="options.controls"
    :autoplay="options.autoplay"
    :live="options.live"
    :hide-snapshot-button="options.hideSnapshot"
    :muted="options.muted"
    :fluent="options.fluent"
    :stretch="options.stretch"
    :aspect="options.aspect"
    :loading="options.loading"
    :hide-big-play-button="options.hideBigPlay"
    @fullscreen="onFullscreen"
  >
    <slot></slot>
  </LivePlayer>
</template>

<script>
import LivePlayer from "@liveqing/liveplayer";

export default {
  name: "LiveVideoRtcPlayer",
  components: {
    LivePlayer,
  },
  props: {
    params: {
      type: String,
    },
  },
  data() {
    return {
      flag: false,
    };
  },
  computed: {
    options() {
      return {
        // 播放地址
        url: this.params,
        // 视频标题
        title: "",
        // 视频封面图片
        poster: "",
        // 播放器控制栏
        controls: true,
        // 隐藏截图
        hideSnapshot: true,
        // 是否直播
        live: true,
        // 是否自动播放
        autoplay: true,
        // 是否静音
        muted: true,
        // 流畅模式
        fluent: true,
        // 是否拉伸
        stretch: true,
        // 全屏 - 适应div
        aspect: "fullscreen",
        // 指示加载状态
        loading: true,
        // 隐藏起播状态下的大播放按钮
        hideBigPlay: true,
      };
    },
  },
  created() {
    console.log("配置 ----- ", this.options);
  },
  beforeDestroy() {
    if (this.options) {
      this.options.url = "";
    }
    this.onExitFullscreen();
  },
  methods: {
    onExitFullscreen() {
      this.flag = false;
    },
    onFullscreen(status) {
      this.flag = status;
      if (!status) {
        this.onExitFullscreen();
        return;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.component-wrapper.video-panel {
  position: relative;
  width: 100%;
  height: 100%;

  .video-wrapper .video-js {
    background-color: rgba(32, 46, 71, 0.6);

    .video-title {
      top: 4px;
      right: unset;
      left: 4px;
      padding: 4px 6px;
      max-width: 80%;
      font-size: 16px;
    }

    .video-control {
      position: absolute;
      top: 100%;
      left: 50%;
      transform: translate(-50%, -140%);
      margin-top: 0;
    }
  }

  &.fullscreen .video-wrapper .video-js {
    .video-title {
      top: 60px;
      right: unset;
      left: 20px;
      padding: 5px 8px 6px;
      background: rgba(4, 16, 37, 0.6);
      border-radius: 4px;
    }
  }
}
</style>

6. Reference the playback component in the parent component

<template>
  <div id="app">
    <!-- 视频 -->
    <div class="video-box">
      <el-button @click="handlePlayVideo(1)">播放视频1</el-button>
      <el-button @click="StopPlayVideo(1)">停止视频1</el-button>
      <div class="video-box-item">
        <LiveVideoRtcPlayer v-if="showV1" :params="playUrl1" id="v1" />
      </div>
      <el-button @click="handlePlayVideo(2)">播放视频2</el-button>
      <el-button @click="StopPlayVideo(2)">停止视频2</el-button>
      <div class="video-box-item">
        <LiveVideoRtcPlayer v-if="showV2" :params="playUrl2" id="v2" />
      </div>
    </div>
  </div>
</template>

<script>
//import Child from "./Child.vue";
//import LiveVideoPlay from "./LiveVideoPlay.vue";
import LiveVideoRtcPlayer from "./LiveVideoRtcPlayer.vue";
export default {
  name: "App",
  components: {
    //LiveVideoPlay,
    LiveVideoRtcPlayer,
  },
  data() {
    return {
      playUrl1: null,
      playUrl2: null,
      showV1: false,
      showV2: false,
    };
  },
  methods: {
    handlePlayVideo(v) {
      if (v == 1) {
        // this.playUrl1 =
        //   "https://xxxxxxxxxxxx/live/02.live.flv";
        this.playUrl1 =
          "webrtcs://xxxxxxxxxxxxx/live/index/api";
        this.showV1 = true;
      } else if (v == 2) {
        this.playUrl2 = 'xxxxx 播放地址';
        this.showV2 = true;
      }
    },
    StopPlayVideo(v) {
      if (v == 1) {
        this.showV1 = false;
      } else if (v == 2) {
        this.showV2 = false;
      }
    },
  },
};
</script>

<style lang="scss" scoped>
#app {
  height: 100%;
}

#app ::v-deep .box {
  font-size: 30px;
}

.video-box {
  width: 100%;
  height: 600px;
  overflow: hidden;

  &-item {
    width: 300px;
    height: 400px;
    float: left;
    overflow: hidden;
    background-color: #f1f2f3;
    margin-left: 50px;
    position: relative;
  }
}
</style>
<style lang="scss"></style>

Test it out, nice.

I'm tired, so be it.

Guess you like

Origin blog.csdn.net/jmszl1991/article/details/135133425