微信小程序-音视频剪辑
起因:英语配音
源码在文章尾部,可直接Copy使用
最近在做一个英语配音的小程序项目,涉及的核心技术是:音视频剪辑。其实相关的成程序产品已经有很多了,所以花了几天时间也就搞定了,讲解一下其中核心技术:
- 1.将一段英语视频中的音轨与视轨分离。
- 2.用户进行录音,仿照英文进行朗读,并临时保存录音后的音频数据
- 3.将视频分离后的视轨与录音音频进行合成为一个新的视频
- 4.正常播放合成后的视频(新视频)
音视频剪辑
- 第一步首先创建一个用于播放视频的video标签,并设置id的值
<view class="video-wrapper"><video id="myVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" binderror="videoErrorCallback" show-center-play-btn='{{false}}' show-play-btn="{{true}}" controls picture-in-picture-mode="{{['push', 'pop']}}" bindenterpictureinpicture='bindVideoEnterPictureInPicture' bindleavepictureinpicture='bindVideoLeavePictureInPicture'></video></view>
- 初始化(根据小程序内置API)
- 创建视频控制器:videoContext , 用于视频播放,暂停等控制操作
- 创建录音管理器对象: recorderManager,用于录音开始,终止等控制操作
- 创建音频文件操作对象:innerAudioContext,用于对录音后保存的音频mp3文件进行操作,用于设置音频文件地址,静音,播放,暂停等操作
- 创建一个音视频操作对象,保存在data上:mediaContainer。通过此属性来对媒体文件(音频/视频)进行各种操作,比如分离视频中的音频,奖音轨和视轨合并。
方法讲解
- 需要用到的4个对象直接在onReady生命周期中进行初始化.
- 录音调用并保存:startRecord(). 录音完成后,触发录音结束方法endRecord(),回调方法success中将获取临时音频文件地址。根据此地址将音频文件中的音轨数据提取出来,并保存在mediaContainer之中。提取方法为extractDataSource().
- 播放录音:bindPlayRecord() 播放录音方法,必带参数src,指向音频文件地址,由录音时的回调方法中获取 res.tempFilePath。同时移动端音频通常默认静音:this.innerAudioContext.obeyMuteSwitch = false;
- 将视频中的音轨与视轨进行分离:chooseVideo(), 其中success毁掉方法的返回值mt,mt.tracks[0]为音轨 ,mt.tracks[1]为视轨(频)。需要注意的是此时将音频暂时保存在手机中:exportVideoMedia()。
注意:使用真机调试! 音频中的音轨抽取 与 视频中的视轨抽取,都是调用的同一个对象MediaContainer上方法 this.data.mediaContainer.extractDataSource()
源码
// pages/videosound/videosound.js
const app = getApp();Page({inputValue: "",data: {savedFilePath: "",total: 3, // 配音总数step: 0, // 当前配音isSpeaking: false, // 是否正在说话recordTempFilePath: "", // 录音临时缓存地址recordFrameList: [], // 所有录音片段},onReady() {this.videoContext = wx.createVideoContext("myVideo"); // 音频控制器this.recorderManager = wx.getRecorderManager(); // 录音对象this.innerAudioContext = wx.createInnerAudioContext(); // 播放对象this.data.mediaContainer = wx.createMediaContainer();},destroy() {this.videoContext.destroy();},bindPlaySourceSound() {console.log("1");this.videoContext.play();},bindPlaySeek(numberPostion) {this.videoContext.seek(20);this.videoContext.play();},recordCurrent() {// 参考 https://blog.csdn.net/qq_37257212/article/details/79093470},startRecord() {const options = {duration: 5000,sampleRate: 16000, // 采样率,有效值 8000/16000/44100numberOfChannels: 1, // 录音通道数,有效值 1/2encodeBitRate: 96000, // 编码码率format: "mp3", // 音频格式,有效值 aac/mp3frameSize: 50, // 指定帧大小,单位 KB};//开始录音this.recorderManager.start(options);this.recorderManager.onStart(() => {console.log("开始录音");});this.setData({isSpeaking: true,});//错误回调this.recorderManager.onError((res) => {console.log(res);});},endRecord() {this.recorderManager.onStop((res) => {if (res.duration < 1000) {wx.showToast({title: "录音时间太短",});return;} else {this.setData({isSpeaking: false,});this.data.recordTempFilePath = res.tempFilePath; // 文件临时路径let mt = this.data.mediaContainer.extractDataSource({source: res.tempFilePath,success: (mt) => {this.data.audioKind = mt.tracks[0];this.data.recordFrameList.push(mt.tracks[0]);this.data.mediaContainer.addTrack(this.data.audioKind);},fail: (err) => {console.log(err);},});// this.uploadFileRecord(res);}});this.recorderManager.onError((res) => {console.log("小伙砸你录音失败了!");});},bindPlayRecord(e) {var that = this;this.innerAudioContext.src = this.data.recordTempFilePath;this.innerAudioContext.play();this.innerAudioContext.obeyMuteSwitch = false;this.innerAudioContext.onEnded((res) => {that.innerAudioContext.stop();});},// 开始合成。真机可以。跳转页面后的缓存视频已经去掉了音频通道,bindComposeRecord() {this.toNextPage();},toNextPage() {wx.navigateTo({url: "/pages/videoresult/videoresult?src=" + this.data.savedFilePath,});},uploadFileRecord(res) {wx.showLoading({title: "发送中...",});var tempFilePath = res.tempFilePath; // 文件临时路径console.log("文件临时路径", tempFilePath);wx.uploadFile({url: "", //上传服务器的地址filePath: tempFilePath, //临时路径name: "file",header: {contentType: "multipart/form-data", //按需求增加},formData: null,success: function (res) {console.log("上传成功");wx.hideLoading();that.setData({recordTempFilePath: tempFilePath,});},fail: function (err) {wx.hideLoading();console.log(err.errMsg); //上传失败},});},// wxfile://tmp_9ded76d75506015bafb1c30d49d66827f6909af54e256aac.mp4chooseVideo: function () {wx.chooseVideo({sourceType: ["album", "camera"],maxDuration: 60,camera: "back",success: (res) => {let videoPath = res.tempFilePath;let mt = this.data.mediaContainer.extractDataSource({source: videoPath,success: (mt) => {console.log(mt);this.data.videoKind = mt.tracks[1];// this.data.audioKind = mt.tracks[0]; // 视频中的音频抽出来this.data.mediaContainer.addTrack(this.data.videoKind);this.exportVideoMedia();},fail: (err) => {console.log(err);},});},fail: (err) => {console.log(err);},});},exportVideoMedia() {var that = this;//3.导出视频this.data.mediaContainer.export({success: (result) => {console.log(result);let tempArr1 = result.tempFilePath.split("//");let tempArr2 = tempArr1[1].split("/");let tempArr3 = tempArr2[tempArr2.length - 1].split(".");let tempString2 = "";for (let i = 0; i < tempArr2.length - 1; i++) {tempString2 += tempArr2[i] + "/";}let newPath =tempArr1[0] +"//" +tempString2 +new Date().getTime() +"." +tempArr3[1];// 导出新视频的名字每次都是一样的,估计有缓存什么的,我用时间戳重命名新导出的文件var filemanage = wx.getFileSystemManager().renameSync(result.tempFilePath, newPath);wx.saveFile({tempFilePath: newPath, // 传入一个本地临时文件路径success(res) {console.log(res.savedFilePath); // res.savedFilePath 为一个本地缓存文件路径that.data.savedFilePath = res.savedFilePath;},});wx.downloadFile({tempFilePath: newPath, // 传入一个本地临时文件路径success(res) {console.log(res); // res.savedFilePath 为一个本地缓存文件路径},});// 4.移除内容,清空容器this.data.mediaContainer.removeTrack(this.data.videoKind);this.data.mediaContainer.removeTrack(this.data.audioKind);},});},
});
源码star
------ 如果文章对你有用,感谢右上角 >>>点赞 | 收藏 <<<
微信小程序-音视频剪辑相关推荐
- 腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践
概述 本文来自腾讯视频云终端技术总监rexchang(常青)技术分享,内容分别介绍了微信小程序视音视频和WebRTC的技术特征.差异等,并针对两者的技术差异分享和总结了微信小程序视音视频和WebRTC ...
- 腾讯技术分享:微信小程序音视频技术背后的故事
1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...
- 微信小程序 RTMP 音视频 通话 ffmpeg_WebRTC与微信小程序音视频互通方案设计与实现...
背景 在之前的WebRTC实时音视频通话之语音通话设计与实践中介绍了58 TEG部门基于 WebRTC 的实时音视频通话解决方案. 考虑到腾讯微信的小程序平台提供了音视频通话与直播的支持,如果能打通基 ...
- 技术分享:微信小程序音视频与WebRTC互通的技术思路和实践
1.概述 本文内容分别介绍了微信小程序视音视频和WebRTC的技术特征.差异等,并针对两者的技术差异分享和总结了微信小程序视音视频和WebRTC互通的实现思路以及技术方案.希望能带给你启发. 分别介绍 ...
- 微信小程序音视频合成API解读
选择视频合成 let mc = wx.createMediaContainer() wx.chooseVideo({sourceType: ['album', 'camera'],maxDuratio ...
- 常青:小程序音视频能力再升级
LiveVideoStack采访了腾讯云音视频业务终端研发团队负责人常青,针对小程序音视频能力技术升级.场景支持.政策审核以及未来演进趋势进行了详细的探讨. 文 / 常青 策划 / LiveVideo ...
- 小程序音视频能力技术负责人解读“小程序直播”
策划 / LiveVideoStack 责编 / 包研 一夜之间,"小程序+直播"成为多媒体开发者热议的话题.从底层技术实现到接口开放程度,是否绑定腾讯云?价格体系?低延迟性能如何 ...
- 小程序音视频功能的原理及应用
本文由云+社区发表 作者:常青 腾讯视频云是做什么的?腾讯视频云既不做数据库,也不做存储,也不做网络,我们只做音视频服务,也就是直播.点播.视频通话.这类面向B类客户的音视频PAAS业务. 今天主要是 ...
- 动手搭建第一个小程序音视频Demo
腾讯云提供了全套技术文档和源码来帮助您快速构建一个音视频小程序,但是再好的源码和文档也有学习成本,为了尽快的能调试起来,我们还提供了一个免费的一键部署服务:您只需轻点几下鼠标,就可以在自己的账号下获得 ...
最新文章
- 利用ngxtop实时监控nginx的访问情况
- ELK 使用4-Kafka + zookpeer
- npm WARN enoent ENOENT: no such file or directory
- java源码导入eclipse_如何导入外部的源码到eclipse中
- 中国什么时候才能全面普及 1 Gbps 下行的网速?
- oracle基本的操作命令,oracle命令基本操作
- 人工智障学习笔记——机器学习(16)降维小结
- 汉诺塔--递归和非递归实现
- opencv之解决Module opencv_ovis disabled because OGRE3D was not found
- 如何在VS2005下生成动态运行时库
- LeetCode解题思路—快慢指针
- 生成订单30分钟未支付,则自动取消,该怎么实现?原来大公司的最有解是这样的!...
- 海洋工作室成立啦!!
- 2021-09-06单纯形计算方法(
- 理解概念IMAP4、IMAP4rev1 client protocol、POP3、SMTP、MIME、RFC822
- 53、backtrader的一些基本概念---如何用backtrader画图?
- PostgreSQL 配置文件 postgresql.conf 及 postgresql.auto.conf
- R7900P/R7960P/R8000P梅林固件
- coutendl;什么意思?
- 数据中心电气设计怎么做?丨规范、负荷计算、设备选型、微模块/液冷机房…...