Cordova插件cordova-plugin-media-capture实现短视频的录制上传和播放

小编:管理员 35阅读 2022.09.13

效果图在这里插入图片描述写在前面(吐槽)

1、网上的教程大部分都是虎头蛇尾的不全的。互相抄来抄去真的感觉就没有一个是真正自己去写一写的,不然这里面这么多的坑就没有一个人出来说说的?下面就写写我实现功能过程中的一些问题吧,代码绝对完整并且按照步骤来一定可以成功!

2、本文主要讲在Android中的实现,IOS端目前还在适配,不少问题到时候再另外单独发一篇

实现逻辑

1、客户端利用cordova-plugin-media-capture插件调用摄像机权限进行视频拍摄

2、拍摄的视频上传至服务器

3、服务端接收视频文件并转码保存删除源文件,将保存链接返回给客户端

4、客户端接收链接利用vedio插件进行显示播放

实现步骤安装cordova-plugin-media-capture插件

这个没啥可说的直接上代码:

cordova plugin add cordova-plugin-media-capture
复制客户端调用摄像头拍摄视频

实现的过程中第一个坑出现了,就是cordova这个插件方法navigator.device.capture.captureVideo正如网上大部分教程一样,确实能很顺利的调起摄像头进行拍摄,但是拍摄完之后总是显示失败的!原因是这个插件是需要获取手机存储权限的!然而偏偏这个插件就是没有先去获取这个存储权限!必须要自己写代码去获取权限!我就不信那些教程能不获取权限直接调用摄像头拍摄成功?要么就是他们在app中其他地方已经获取过存储权限了!比如调用图库的这个插件就会弹窗提示给权限!然后这个插件并不会,这是第一个坑!

调用方法前手动获取手机权限

首先要安装权限的插件cordova-plugin-android-permissions

cordova plugin add cordova-plugin-android-permissions
复制

查看客户端是否有存储权限如果没有就申请获取存储权限

//申请存储权限
var permissions = cordova.plugins.permissions;
permissions.requestPermission(permissions.WRITE_EXTERNAL_STORAGE, successCallback, errorCallback)
var successCallback = function(s){}
var errorCallback = function(r){
	alert("申请权限失败请重试");
}
复制调用相机进行短视频拍摄
var options = {
			  limit: 1,
			  duration: 10,
			  quality: 1
			};
			navigator.device.capture.captureVideo(this.onSuccess, this.onError, options);
复制

1、这里对参数options进行一下说明

limit:拍摄视频的数量

duration:拍摄视频的时长(单位:s)

quality:拍摄视频的质量(0:低质量 1高质量)

这里遇到了第二个坑,其实也跟Cordova官方有关,毕竟比较冷门的插件,也情有可原。但是我始终觉得比Hbuild的那个一套代码走天下(小程序,Android,ios)好用的多

这里视频拍摄我们完全不能自定义拍摄的画质,官方只给了你两个选择,0低画质,这个低画质是真的低,低到就是你完全没办法看,所以拍摄质量其实就一个选项没得选择,那就是1高画质,搞到什么程度呢?部分手机拍摄出来的居然是4K视频!!这个坑就是高画质哪怕仅仅拍摄一两秒的视频都会有好几M大,一个是上传下载的时候服务器带宽压力,还有一个是这种极度高画质的视频在获取到链接放vedio渲染到前端显示的时候基本就是1s的视频都会卡顿,哪怕你的服务器是10M的带宽也是如此,那么这个坑就直接导致了需要多进行一个步骤---服务端转码保存

所以要么就是弃用这个插件用别的办法实现,要么就是硬着头皮直接来!所以没得选择!quality必须只能选择高画质了

2、在this.onSuccess成功回调方法中我们就可以获取到视频在客户端的保存路径了

onFail(message) {
		  //取消照相功能提示
		},
		onSuccess(mediaFiles) {
			var _this = this
		    var i, len;
		    for (i = 0, len = mediaFiles.length; i < len; i += 1) {
		        _this.path = mediaFiles[i].fullPath;
				_this.filename = mediaFiles[i].name;
		    }
		},
复制

this.path就是我们需要的路径

利用文件上传插件讲拍摄的视频上传至服务器安装cordova-plugin-file-transfer
cordova plugin add cordova-plugin-file-transfer
复制上传文件至服务器

上传方法

//fileURL就是上面步骤中文件的路径this.path
upload(fileURL) {
	var options = new FileUploadOptions();
	options.fileKey = "file1";
	options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);
	var params = {};
	params.value1 = "test";
	params.value2 = "param";
	options.params = params;
	var ft = new FileTransfer();
	//上传地址:下面步骤我会讲服务器接收文件的方法的
	var SERVER = "填写自己后台的服务API地址";
	ft.upload(fileURL, encodeURI(SERVER), success, fail, options);
}
复制

服务端接收文件的方法在下面步骤中有先别着急

success成功回调中会返回文件在服务器保存的url的

//上传成功
			var success = function (r) {
				var strs = JSON.parse(r.response);
				// alert("上传成功! Code = " + JSON.parse(r.response).data.vedioShowUrl);
				_this.show = true;
				_this.uploadFlag = false;
				_this.playerOptions.sources[0].src = JSON.parse(r.response).data.vedioShowUrl;
				_this.saveVedioUrl = JSON.parse(r.response).data.saveVedioUrl;
			}
复制

saveVedioUrl就是服务端返回的url

服务端接收视频文件并转码保存,返回URL给客户端接收视频文件
move_uploaded_file($_FILES["file1"]["tmp_name"],$_SERVER["DOCUMENT_ROOT"]."/Public/vedios/" . $_FILES["file1"]["name"]);
$ofile = $_SERVER["DOCUMENT_ROOT"]."/Public/vedios/" . $_FILES["file1"]["name"];
复制

文件保存在服务器的路径是$_SERVER["DOCUMENT_ROOT"]."/Public/vedios/" . $_FILES["file1"]["name"];

转码

1、转码我们需要使用ffmpeg来实现(本人服务器centos nginx)

这里第三个坑出现了,网上一堆的教程关于安装ffmpeg大部分都是瞎写的,全是纸上谈兵压根就是自己没有去写一写的,所以千万不要随便找一个教程就去安装,后面卸载可是个十分麻烦的事情

这里贴出来了一个用心写代码的兄弟的链接,非常好,链接上面已经贴出来了,再次非常感谢这位兄弟的教程,按照他的步骤一步步走就能成功安装了

在这里插入图片描述

2、接下来我们就是利用ffmpeg命令进行转码操作了

转码命令:

ffmpeg -y -i 需要转码的文件路径 -s 720x960 -b:v 562k -c:v libx264 转码成功后文件的保存路径
复制

经过此步骤之后转码后的文件就只有几百K了,视频的质量也还可以

直接贴代码:

//设置转码后的文件路径(避免重复命令我们加一个时间戳随机数)
$randnum = date('His').str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
$nfile = $_SERVER["DOCUMENT_ROOT"]."/Public/vedios/" . $randnum .$_FILES["file1"]["name"];
$nfile2 = "/Public/vedios/" . $randnum .$_FILES["file1"]["name"];
//exec函数执行ffmpeg终端转码命令
$str = "ffmpeg -y -i ". $ofile. " -s 720x960 -b:v 562k -c:v libx264 " . $nfile;
exec("$str", $output,$status);//$status为0即表示转码成功
//unlink($ofile)方法删除源文件
if(!$status && unlink($ofile)){
	$VedioStr = C('URL').$nfile2;
	$VedioUrl = $nfile2;
	$vedioData = array(
		'vedioShowUrl'=>$VedioStr,
	    'saveVedioUrl'=>$VedioUrl
	);
	$this->res['code'] = 200;
	$this->res['msg'] = '上传转码成功';
	$this->res['data'] = $vedioData;
	$this->response($this->res,'json');
}else{
	$this->res['code'] = 101;
	$this->res['msg'] = '转码错误请重试!';
	$this->res['data'] = $output;
	$this->response($this->res,'json');
}
复制客户端拿到返回的视频URL利用vedio插件进行显示安装vue-video-player插件

1、vue项目中执行:

npm install vue-video-player --save
复制

2、在main.js入口文件中引入:

import VideoPlayer from 'vue-video-player'
require('video.js/dist/video-js.css')
require('vue-video-player/src/custom-theme.css')
Vue.use(VideoPlayer)
复制

3、在使用的页面中引用:

import { videoPlayer } from 'vue-video-player'
import 'video.js/dist/video-js.css'
复制

4、构建播放器容器:

<video-player  class="video-player vjs-custom-skin"
		        id="videoDiv"
		        ref="videoPlayer"
		        :playsinline="true"
		        :webkit-playsinline="true"
		        :options="playerOptions"
				@pause="onPlayerPause($event)"
				@play="onPlayerPlay($event)"
				@ended="onPlayerEnded($event)"
		    >
			</video-player>
复制

options参数:

playerOptions: {
			  controls:false,
			  autoplay: false, // 如果为true,浏览器准备好时开始回放。
			  muted: false, // 默认情况下将会消除任何音频。
			  loop: false, // 是否视频一结束就重新开始。
			  preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
			  language: 'zh-CN',
			  aspectRatio: '9:16', // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
			  sources: [{
			    type: "video/mp4", // 类型
			    src: '' // url地址
			  }],
			  poster:'http://81.68.107.23/uploads/poster.png', // 封面地址
			  notSupportedMessage: '此视频暂无法播放,请稍后再试', // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
			  controlBar: {
			    timeDivider: true, // 当前时间和持续时间的分隔符
			    durationDisplay: true, // 显示持续时间
			    remainingTimeDisplay: false, // 是否显示剩余时间功能
			    fullscreenToggle: false // 是否显示全屏按钮
			  }
			},
复制修改播放器默认样式实现点击屏幕暂停和播放

这里默认的播放器样式很丑的,我们需要自定义样式实现点击视频屏幕播放和暂停功能

贴出来自定义的css

/*播放按钮设置成宽高一致,圆形,居中*/
.vjs-custom-skin > .video-js .vjs-big-play-button {
	background: url("../../assets/img/pause.png");
	background-color: rgba(255, 255, 255, 0.4);
    margin-left: -1em !important;
    width: 2em !important;
	background-size: cover;
	border: none;
	width: 100px;
	height: 100px;
}
.video-js .vjs-big-play-button .vjs-icon-placeholder:before {
	position: absolute;
	left: 0;
	width: 100%;
	height: 100%;
}
/* 去掉中间的播放箭头 */
.vjs-big-play-button .vjs-icon-placeholder {
    font-size: 0em;
}
/* 加载圆圈 */
.vjs-loading-spinner {
    font-size: 2.5em;
    width: 2em;
    height: 2em;
    border-radius: 1em;
    margin-top: -1em;
    margin-left: -1.5em;
}
 
/*control-bar布局时flex,通过order调整剩余时间的位置到进度条右边*/
.vjs-custom-skin > .video-js .vjs-control-bar .vjs-remaining-time{
  order:3 !important;
}
 
/*进度条背景轨道*/
.video-js .vjs-slider{
  border-radius: 1em;
}
 
/*进度条进度*/
.vjs-custom-skin > .video-js .vjs-play-progress, .vjs-custom-skin > .video-js .vjs-volume-level{
  border-radius: 1em;
}
 
/*鼠标进入播放器后,播放按钮颜色会变*/
.video-js:hover .vjs-big-play-button, .vjs-custom-skin>.video-js .vjs-big-play-button:active, .vjs-custom-skin>.video-js .vjs-big-play-button:focus{
  background-color: rgba(0,0,0,0.4) !important;
}
 
/*control bar*/
.video-js .vjs-control-bar{
  background-color: rgba(0,0,0,0.2) !important;
}
 
/*点击按钮时不显示蓝色边框*/
.video-js .vjs-control-bar button{
  outline: none;
}
复制

在上面步骤的main.js文件中引入我们刚刚创建的自定义css

import './assets/css/vediocommon.css'
复制

js方法

@pause="onPlayerPause($event)"@play="onPlayerPlay($event)"@ended="onPlayerEnded($event)" onPlayerClick

onPlayerPause($event) {
		  this.isPlay = false;
		},
		onPlayerPlay($event) {
		  this.isPlay = true;
		},
		onPlayerEnded($event) {},
		onPlayerClick() {
		  if (this.isPlay) {
		    this.player.pause();
		  } else {
		    this.player.play();
		  }
		},
复制源码文件

由于项目中很多地方可能涉及到引用的本地的一些icon文件导致你们复制粘贴后不能正常运行,所以将此视频上传封装成了一个组件方便大家在项目中直接引用

总结(永远记得做一个有灵魂的人)

1、一部分人写CSDN是为了自己记个笔记所以别人看不懂正常,可以理解

2、复制粘贴纸上谈兵别人的东西就没有什么意思了

3、技术水平有限,但是每一行都是自己亲历亲为实现的,权当做个记录

关联标签: