第四节 Vue集成腾讯推流和播放功能

亮子 2022-08-23 09:30:38 11276 0 0 0

1、集成推流和播放器

在vue项目的public目录下的index.html中添加如下脚本,脚本必须引入在 index.html的body中。

<script src="https://video.sdk.qcloudecdn.com/web/TXLivePusher-2.0.1.min.js" charset="utf-8"></script>
<script src="https://web.sdk.qcloud.com/player/tcplayerlite/release/v2.4.1/TcPlayer-2.4.1.js" charset="utf-8"></script>

2、推流页面

<template>
    <div>
        <div><h3>主持人直播</h3></div>
        <div>
            <!-- 推流的视频展示 -->
            <div style="margin-top:30px; float: left; width:780px;">
              <div id="id_local_video" style="width:780px;height:450px;border:1px solid blue; float: left; margin: 10px;" ></div>
              <div style="margin: 20px;">
                  <el-button type="primary" @click="openCamera">打开摄像头</el-button>
                  <el-button type="primary" @click="closeCamera">关闭摄像头</el-button>
                  <el-button type="primary" @click="startScreenCapture">共享屏幕</el-button>
                  <el-button type="primary" @click="stopScreenCapture">关闭共享</el-button>
              </div>
              <div style="margin: 20px;">
                  <el-button type="primary" @click="startMicrophone">打开麦克风</el-button>
                  <el-button type="primary" @click="stopMicrophone">关闭麦克风</el-button>
                  <el-button type="primary" @click="startPush">开始直播</el-button>
                  <el-button type="primary" @click="stopPush">停止直播</el-button>
                  <el-button type="primary" @click="openUserList()">所有成员</el-button>
              </div>

            </div>
        </div>
    </div>
</template>

<script>
    import { getRoomInfoById } from '@/api/api.js'
    export default {
        name: 'PushVideoPage',
        props: {
          roomId: { type: [String,Number], default: 0 },
        },
        data() {
            return {
                livePusher: null,
                roomInfo: null,
            }
        },
        mounted() {
            console.log('roomId='+this.roomId);
            //--1 初始化腾讯云播放器
            this.readyPusher()
            
            //--2 获取房间信息
            let param = {id: this.roomId};
            getRoomInfoById(param).then(res => {
                console.log('getRoomInfoById', res);
                if(res.data.code == 200) {
                    this.roomInfo = res.data.data;
                }
            })
            
        },
        methods: {
            //初始化腾讯推流组件
            readyPusher(){
                this.livePusher = new TXLivePusher();
                // 指定本地视频播放器容器:
                this.livePusher.setRenderView('id_local_video');
                // 设置视频质量
                this.livePusher.setVideoQuality('720p');
                // 设置音频质量
                this.livePusher.setAudioQuality('standard');
                // 自定义设置帧率
                this.livePusher.setProperty('setVideoFPS', 25);
                console.log('readyPusher OK');
              //获取视频效果管理实例
              this.videoEffectManager = this.livePusher.getVideoEffectManager();
              //开启混流
              this.videoEffectManager.enableMixing(true);
              //设置混流参数
              this.videoEffectManager.setMixingConfig({
                videoWidth: 1280,
                videoHeight: 720,
                videoFramerate: 15
              });
            },
            openCamera() {
                // 打开摄像头
                this.livePusher.startCamera();
            },
            closeCamera() {
                // 关闭摄像头
                this.livePusher.stopCamera();
            },
            startScreenCapture() {
                // 打开共享桌面
                this.livePusher.startScreenCapture();
            },
            stopScreenCapture() {
                // 关闭共享桌面
                this.livePusher.stopScreenCapture();
            },
            startMicrophone() {
                // 打开麦克风
                this.livePusher.startMicrophone();
            },
            stopMicrophone() {
                // 关闭麦克风
                this.livePusher.stopMicrophone();
            },
            startPush() {
                // this.livePusher.startPush("webrtc://live.shenmazong.com/live/36301?txSecret=134321418f9cfc673c9bfc141c0ecf03&txTime=6309C85A");
                // this.livePusher.startPush("webrtc://live.shenmazong.com/live/32301?txSecret=ae4323ac78e0d0e6c7580674824286ba&txTime=6308BB23");
                this.livePusher.startPush(this.roomInfo.pushUrl)
            },
            stopPush() {
                // this.livePusher.stopPush("webrtc://live.shenmazong.com/live/32301?txSecret=ae4323ac78e0d0e6c7580674824286ba&txTime=6308BB23");
                this.livePusher.stopPush(this.roomInfo.pushUrl)
            },
        }
    }
</script>

<style>
</style>

3、播放页面

<template>
    <div>
        <div><h3>观众看直播</h3></div>
        <div>
            <div id="id_test_video" style="float: left;margin-left: 123px">
            </div>
        </div>
    </div>
</template>

<script>
    import { getRoomInfoById } from '@/api/api.js'
    export default {
        name: 'PlayVideoPage',
        props: {
          roomId: { type: [String,Number], default: 0 },
        },
        data() {
            return {
                roomInfo: null,
            }
        },
        mounted() {
            console.log('roomId='+this.roomId);
            //--2 获取房间信息
            let param = {id: this.roomId};
            getRoomInfoById(param).then(res => {
                console.log('getRoomInfoById', res);
                if(res.data.code == 200) {
                    this.roomInfo = res.data.data;
                    this.joinRoom();
                }
            });
            
        },
        methods: {
            joinRoom() {
              this.player = new TcPlayer('id_test_video', {
                   "m3u8": this.roomInfo.playUrl,
                   "autoplay" : true,
                   "poster" : this.roomInfo.coverUrl,
                   "width" :  '660',//视频的显示宽度,请尽量使用视频分辨率宽度
                   "height" : '490'//视频的显示高度,请尽量使用视频分辨率高度
              });
            },
        }
    }
</script>

<style>
</style>

4、设置路由

  {
    path: '/push/:roomId',
    name: 'PushRoom',
    props: true,
    component: () => import('../views/PushVideoPage.vue')
  },
  {
    path: '/play/:roomId',
    name: 'PlayRoom',
    props: true,
    component: () => import('../views/PlayVideoPage.vue')
  },

5、后端接口

package com.shenmazg6.controller;

import com.shenmazg6.service.TbRoomService;
import com.shenmazg6.utils.ResultResponse;
import com.shenmazg6.vo.IdVo;
import com.shenmazg6.vo.PageInfoVo;
import com.shenmazg6.vo.RoomInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 军哥
 * @version 1.0
 * @description: TbRoomController
 * @date 2022/12/22 15:46
 */

@RestController
@Slf4j
@RequestMapping(value = "/room")
public class TbRoomController {

    @Autowired
    TbRoomService tbRoomService;

    @PostMapping(value = "/add")
    public ResultResponse add(@RequestBody RoomInfoVo roomInfoVo) {
        return tbRoomService.add(roomInfoVo);
    }

    @PostMapping(value = "/list")
    public ResultResponse list(@RequestBody PageInfoVo pageInfoVo) {
        return tbRoomService.listByPage(pageInfoVo);
    }

    @PostMapping(value = "/get")
    public ResultResponse get(@RequestBody IdVo idVo) {
        return tbRoomService.getRoomById(idVo);
    }
}

6、接口实现

package com.shenmazg6.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shenmazg6.pojo.TbRoom;
import com.shenmazg6.service.TbRoomService;
import com.shenmazg6.mapper.TbRoomMapper;
import com.shenmazg6.utils.CopyBeanUtils;
import com.shenmazg6.utils.IdWorker;
import com.shenmazg6.utils.ResultResponse;
import com.shenmazg6.utils.TxLiveUtils;
import com.shenmazg6.vo.IdVo;
import com.shenmazg6.vo.PageInfoVo;
import com.shenmazg6.vo.RoomInfoVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
* @author Think
* @description 针对表【tb_room(直播房间表)】的数据库操作Service实现
* @createDate 2022-12-22 15:45:15
*/
@Service
public class TbRoomServiceImpl extends ServiceImpl<TbRoomMapper, TbRoom>
    implements TbRoomService{

    @Override
    public ResultResponse add(RoomInfoVo roomInfoVo) {
        //--1 复制属性
        TbRoom tbRoom = new TbRoom();
        CopyBeanUtils.copy(roomInfoVo, tbRoom);

        //--2 生成推流地址
        tbRoom.setRoomNo(""+ IdWorker.getId());
        String pushUrl = TxLiveUtils.makePushUrl(tbRoom.getRoomNo(), roomInfoVo.getCloseTime());
        tbRoom.setPushUrl(pushUrl);

        //--3 生成播放地址
        String playUrl = TxLiveUtils.makePlayUrl(tbRoom.getRoomNo());
        tbRoom.setPlayUrl(playUrl);

        //--3 写入数据库
        tbRoom.setCoverUrl("https://upload.shenmazong.com/upload/955bb2ca-b4d6-4ab5-8e1e-69c35f277af7.png");
        save(tbRoom);

        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse listByPage(PageInfoVo pageInfoVo) {
        // 得到列表数据
        Page<TbRoom> p = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());
        Page<TbRoom> tbRoomPage = page(p, new QueryWrapper<TbRoom>().lambda().orderByDesc(TbRoom::getRoomId));

        // 数据转换
        Page<RoomInfoVo> infoVoPage = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());
        BeanUtils.copyProperties(tbRoomPage, infoVoPage);

        List<RoomInfoVo> collect = tbRoomPage.getRecords().stream().map(item -> {
            RoomInfoVo roomInfoVo = new RoomInfoVo();
            BeanUtils.copyProperties(item, roomInfoVo);
            return roomInfoVo;
        }).collect(Collectors.toList());

        infoVoPage.setRecords(collect);

        return ResultResponse.SUCCESS(infoVoPage);
    }

    @Override
    public ResultResponse getRoomById(IdVo idVo) {

        TbRoom tbRoom = getById(idVo.getId());
        if(tbRoom == null) {
            return ResultResponse.FAILED(404, "房间不存在");
        }

        return ResultResponse.SUCCESS(tbRoom);
    }
}

参考文章