H5 js方式实现前端视频压缩

2 篇文章 0 订阅
1 篇文章 0 订阅

1.项目做人脸识别,要求录制人脸读数视频后进行上传处理。但是手机上录制的视频非常大,安卓上3s的视频就有5M左右大小。所以尝试做了前端的js压缩处理。一般来说视频压缩是在服务端通过ffmpeg做压缩。但是这个据说对服务器的要求也很高。前端是不好做压缩处理的,但是也不是不可以做,性能不好而已。在github上查了下试了几种前端的压缩组件。最后我试了一个用的比较好用顺手,是轻量级的,适合H5。链接如下https://github.com/ffmpegjs/ffmpeg.js

2.用法github上已经有了。我这里贴一下它examples里这次参考的html 的代码做备份。

<html>
  <head>
    <script src="/dist/ffmpeg.dev.js"></script>
    <style>
      html, body {
        margin: 0;
        width: 100%;
        height: 100%
      }
      body {
        display: flex;
        flex-direction: column;
        align-items: center;
      }
    </style>
  </head>
  <body>
    <h3>Record video from webcam and transcode to mp4 (x264) and play!</h3>
    <div>
      <video id="webcam" width="320px" height="180px"></video>
      <video id="output-video" width="320px" height="180px" controls></video>
    </div>
    <button id="record" disabled>Start Recording</button>
    <p id="message"></p>
    <script>
      const { createWorker } = FFmpeg;
      const worker = createWorker({
        corePath: '../../node_modules/@ffmpeg/core/ffmpeg-core.js',
        logger: ({ message }) => console.log(message),
      });


      const webcam = document.getElementById('webcam');
      const recordBtn = document.getElementById('record');
      const startRecording = () => {
        const rec = new MediaRecorder(webcam.srcObject);
        const chunks = [];
        
        recordBtn.textContent = 'Stop Recording';
        recordBtn.onclick = () => {
          rec.stop();
          recordBtn.textContent = 'Start Recording';
          recordBtn.onclick = startRecording;
        }


        rec.ondataavailable = e => chunks.push(e.data);
        rec.onstop = async () => {
          transcode(new Uint8Array(await (new Blob(chunks)).arrayBuffer()));
        };
        rec.start();
      };


      (async () => {
        webcam.srcObject = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
        await webcam.play();
        recordBtn.disabled = false;
        recordBtn.onclick = startRecording;
      })();


      const transcode = async (webcamData) => {
        const message = document.getElementById('message');
        const name = 'record.webm';
        message.innerHTML = 'Loading ffmpeg-core.js';
        await worker.load();
        message.innerHTML = 'Start transcoding';
        await worker.write(name, webcamData);
        await worker.transcode(name,  'output.mp4');
        message.innerHTML = 'Complete transcoding';
        const { data } = await worker.read('output.mp4');


        const video = document.getElementById('output-video');
        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
      }
    </script>
  </body>
</html>

3.下面是我的总结。这个前端的ffmpeg.js首先引用有两种,如果你是js直接写的H5,可以通过下面的方式直接引入

<script src="https://unpkg.com/@ffmpeg/ffmpeg@0.6.1/dist/ffmpeg.min.js"></script>
const { createWorker } = FFmpeg;

如果是ES的方式,需要通过npm安装

npm install @ffmpeg/ffmpeg

const { createWorker } = require('@ffmpeg/ffmpeg');
const worker = createWorker();

4.那么在我的项目里,前端压缩的时候我其实一开始就是借鉴上面的代码,只用了transcode方法的部分,通过把uni.chooseVideo调取本地摄像头,录制的视频用webm读取然后转为mp4格式,达到压缩目的

const { createWorker } = FFmpeg;
const worker = createWorker();
uni.chooseVideo({
          sourceType: ['camera'],
          camera: 'front',
          success(chooseRes) {
               //chooseRes.tempFilePath为本地录制好的视频blob格式的地址   
                 await worker.load();
                 const name = 'record.webm';
                 await worker.write(name, chooseRes.tempFilePath);
                 await worker.transcode(name,  'output.mp4');
                 const { data } = await worker.read('output.mp4');
                 const src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
                 self.uploadVideo(chooseRes.tempFilePath)
          }
        })

5.这种方法可以达到效果,但是会有两个新的问题,【1】耗时很长,4s的视频在手机上需要快40s左右进行压缩,时间太久了。微信浏览器录制的视频非常大,都压不动。可见这种方法性能并不好。【2】uni-app的uni-chooseVideo不支持H5方法调用前置摄像头,而这边希望调前置摄像头,用这种方法无法调用前置摄像头。后来采用上面html的方法,进行改造。通过测试发现,读取前置摄像头的数据然后在video里呈现,这样的video src本身就比较小,不需要压缩,这样的方式可以避开录制本地视频非常大,同时能调用H5前置摄像头。在uni-app的Hbuilder中自己写了camera录制视频的组件,代码如下

<template>
    <view class="pageContent">
        <view>
            <video id="webcam" :class="cameraVisible?'recordSrc':'hiddenClass'" muted="true" controls="false" ></video>
        </view>
          <video class="recordSrc playvideo" controls :src="recordBlob" :class="cameraVisible?'hiddenClass':'recordSrc'"></video>
            </div>
            <button class="button"  @click="startRecording" v-if="step==0">开始录制</button>
            <button class="button" @click="stopRecording" v-if="step == 1">停止录像</button>
            <button class="button restart" @click="restart" v-if="step==2">重新录制</button>
            <button class="button upload" @click="uploadVideo" v-if="step==2">上传视频</button>
    </view>
</template>


<script>
import {uploadVideo} from '../../api/global.js'
import {doVideo} from '../../api/smz.js'
    export default {
        data() {
            return {
                 message:"",
                 mediaObject:'',
                 rec:'',
                 chunks:[],
                 recordBlob:'',
                 step:"0"  ,//0:开始录像, 1:录像中,2:停止录像
                 cameraVisible: true, // 显示/隐藏相机
            }
        },
        onLoad() {
            },
        onReady() {
            this.init();
            
         },
        components: {


        },
        methods: {
            async init(){
                    this.videoContext = uni.createVideoContext('webcam');
                    const dom = document.getElementsByClassName("uni-video-video")[0]
                    await navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(function(media) {
                        console.log('getUserMedia completed successfully.');
                        dom.srcObject = media
                      }).catch(function(error) {
                        console.log(error.name + ": " + error.message);
                        alert(error.name + ": " + error.message)
                      });
                    console.log(dom.srcObject)
                    this.mediaObject = dom.srcObject;
                    await this.videoContext.play();    
                },
                    
            startRecording (){
              // alert("开始录像了")
              this.step = "1"
              this.rec = new MediaRecorder(this.mediaObject);
              
              this.chunks = [];
              this.rec.start();
              // alert("启动录像成功")
            },    
            stopRecording(){
                this.step = "2";
                this.cameraVisible = false;
                this.rec.stop();
                //alert("停止成功")
                this.rec.ondataavailable = e => this.chunks.push(e.data);
                //alert("导数据了")
                this.rec.onstop = async () => {
                    //alert("输出录像blob:"+URL.createObjectURL(new Blob(this.chunks, { type: 'video/mp4' })))
                    console.log(URL.createObjectURL(new Blob(this.chunks, { type: 'video/mp4' })))
                    this.recordBlob = URL.createObjectURL(new Blob(this.chunks, { type: 'video/mp4' }));
                };
            },
            async restart(){
                this.step = "0";
                this.cameraVisible = true;
                console.log(this.mediaObject)
                // await this.videoContext.play();
            },
            uploadVideo(){
                //关闭摄像头
                if (this.mediaObject) {
                    console.log(this.mediaObject);
                   console.log(this.mediaObject.getTracks());
                   this.mediaObject.getTracks()[0].stop();
                   this.mediaObject.getTracks()[1].stop();
                 }
                const self = this
                console.log(self.recordBlob)
               //进行下一步处理。。。。。。
            },
        
          
    }
    }
        
</script >
   
<style scoped>
    uni-page-body{
        height: 100%
    }
    uni-view{
        display:contents;
    }
     html, body {
        margin: 0;
        width: 100%;
        height: 100%
      }
      body {
        display: flex;
        flex-direction: column;
        align-items: center;
      }
      .recordSrc {
          width:100%;
          height:100%;
          position:absolute;
      }
      .playvideo{
          left:0
          
      }
      .button {
              position: absolute;
              bottom: 11%;
              left: 50%;
              margin-left: -50px;
              width: 100px;
              border-radius: 42px;
              background-color: red;
       }
      .restart{
              left:25%;
      }
      .upload{
              left:75%;
      }
      .hiddenClass {
          visibility: hidden;
      }
      
      
</style>

这种方式在我的安卓机上chrome浏览器支持,微信浏览器也支持,但是原生的华为浏览器不支持,IOS不可以用。具体如何在IOS中做到兼容还在探索中。有好方法的朋友欢迎指正。

  • 9
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: WebRTC是一种实时通信技术,可以在网页浏览器之间建立点对点的音视频通信连接。通过使用WebRTC技术,可以实现基于H5的直播功能。 首先,H5是指使用HTML5、CSS3和JavaScript等技术开发的网页。WebRTC在H5中的应用主要是通过调用浏览器提供的API来实现。 在实现WebRTC的H5直播中,需要借助一些第三方库或框架,如PeerJS、SimpleWebRTC等。这些库可以简化WebRTC的应用开发过程。 具体实现直播功能的步骤如下: 1. 前端浏览器通过JavaScript调用浏览器提供的getUserMedia API,获取用户的音视频流。 2. 使用WebRTC API创建一个本地的Peer对象,该对象代表当前用户的浏览器。 3. 将获取到的用户音视频流添加到Peer对象中,并将其发送给后台服务器。 4. 后台服务器接收到音视频流后,会将其转发给其他观众的浏览器。 5. 其他观众的浏览器会通过WebRTC API创建一个远程的Peer对象,代表其他用户的浏览器。 6. 远程的Peer对象会将接收到的音视频流添加到自己的浏览器中,实现实时的音视频播放。 通过以上步骤,就可以实现基于H5的WebRTC直播功能。这种方式能够实现低延迟的音视频传输,提供更好的用户体验。同时,由于是点对点通信,不依赖其他中间服务器的转发,可以减少服务器资源的占用。 当然,在实际开发中还需要考虑一些其他方面,如流媒体服务器的选择、网络传输优化和错误处理等。但总的来说,WebRTC的H5直播实现相对较为简单,可以为用户提供更加流畅的直播体验。 ### 回答2: WebRTC是一种实现实时音视频通信的开放标准。H5是指HTML5,是一种用于制作网页的标准技术。 利用WebRTC技术实现直播H5,可以通过以下步骤实现: 1. 前端页面开发:使用HTML5、CSS和JavaScript等前端技术,创建一个具有直播功能的网页。 2. 获取用户媒体设备:通过getUserMedia API,获取用户的音视频流。 3. 媒体传输:使用RTCPeerConnection API,通过UDP或TCP协议将音视频流传输到服务器。 4. 服务器处理:服务器接收到音视频流后,可以进行一些处理,例如转码、压缩等。 5. 观众接入:观众可以通过浏览器访问直播网页,前端通过JavaScript技术与服务器建立连接,接收服务器传输的音视频流进行播放。 6. 直播控制:前端页面可以添加一些控制按钮,例如开始/停止直播、切换摄像头、静音等功能。 WebRTC实现直播H5的优点是实时性好,延迟较低,且不需要安装相关插件。同时,它的开放标准使得开发者可以根据自己的需求进行自定义开发。 当然,在实际开发过程中还需要考虑其他方面的问题,例如安全性、性能优化等。但总体来说,利用WebRTC技术实现直播H5可以为用户提供更便捷、高效的直播体验。 ### 回答3: WebRTC是一种通过浏览器实时通信的技术,而H5是指HTML5标准,可以实现丰富的多媒体功能。通过结合WebRTC和H5技术,可以实现直播功能。 首先,使用WebRTC可以获取用户的音视频流。通过浏览器的getUserMedia API,可以访问用户的摄像头和麦克风,获取实时的音视频数据。这样就可以实现直播主播的视频流。 接下来,使用WebRTC的RTCPeerConnection和RTCDataChannel API可以建立起实时的点对点通信,实现主播和观众之间的双向通信。主播将自己的音视频流发送给观众,而观众也可以将自己的音视频流发送给主播或其他观众。 同时,H5提供了丰富的媒体处理功能。使用H5的Canvas技术,可以将获取到的视频数据渲染到网页中的画布上,实现视频的播放。使用H5的Audio标签,可以将获取到的音频数据播放出来。 此外,H5还提供了一些控制标签和API,如video、audio和MediaSource等,用于实现直播的控制和处理。 综上所述,通过WebRTC实现直播 H5,我们可以借助WebRTC获取实时的音视频数据,并通过H5技术实现视频的播放和处理,从而实现直播功能。这样,用户可以通过浏览器观看直播,无需安装额外的客户端软件,提供了更加便捷和灵活的直播方式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值