效果图
写在前面(吐槽)
1、网上的教程大部分都是虎头蛇尾的不全的。互相抄来抄去真的感觉就没有一个是真正自己去写一写的,不然这里面这么多的坑就没有一个人出来说说的?下面就写写我实现功能过程中的一些问题吧,代码绝对完整并且按照步骤来一定可以成功!
2、本文主要讲在Android中的实现,IOS端目前还在适配,不少问题到时候再另外单独发一篇
实现逻辑
1、客户端利用cordova-plugin-media-capture插件调用摄像机权限进行视频拍摄
2、拍摄的视频上传至服务器
3、服务端接收视频文件并转码保存删除源文件,将保存链接返回给客户端
4、客户端接收链接利用vedio插件进行显示播放
实现步骤
安装cordova-plugin-media-capture插件
这个没啥可说的直接上代码:
代码语言:text复制cordova plugin add cordova-plugin-media-capture
客户端调用摄像头拍摄视频
实现的过程中第一个坑
出现了,就是cordova这个插件方法navigator.device.capture.captureVideo
正如网上大部分教程一样,确实能很顺利的调起摄像头进行拍摄,但是拍摄完之后总是显示失败的!原因是这个插件是需要获取手机存储权限
的!然而偏偏这个插件就是没有先去获取这个存储权限!必须要自己写代码去获取权限!我就不信那些教程能不获取权限直接调用摄像头拍摄成功?要么就是他们在app中其他地方已经获取过存储权限了!比如调用图库的这个插件就会弹窗提示给权限!然后这个插件并不会,这是第一个坑!
调用方法前手动获取手机权限
首先要安装权限的插件cordova-plugin-android-permissions
代码语言:text复制cordova plugin add cordova-plugin-android-permissions
查看客户端是否有存储权限如果没有就申请获取存储权限
代码语言:text复制//申请存储权限
var permissions = cordova.plugins.permissions;
permissions.requestPermission(permissions.WRITE_EXTERNAL_STORAGE, successCallback, errorCallback)
var successCallback = function(s){}
var errorCallback = function(r){
alert("申请权限失败请重试");
}
调用相机进行短视频拍摄
代码语言:javascript复制 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成功回调方法中我们就可以获取到视频在客户端的保存路径了
代码语言:javascript复制 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
代码语言:javascript复制cordova plugin add cordova-plugin-file-transfer
上传文件至服务器
上传方法
代码语言:javascript复制//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给客户端
接收视频文件
代码语言:javascript复制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命令进行转码操作了
转码命令:
代码语言:text复制ffmpeg -y -i 需要转码的文件路径 -s 720x960 -b:v 562k -c:v libx264 转码成功后文件的保存路径
经过此步骤之后转码后的文件就只有几百K了,视频的质量也还可以
直接贴代码:
代码语言:php复制//设置转码后的文件路径(避免重复命令我们加一个时间戳随机数)
$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项目中执行:
代码语言:php复制npm install vue-video-player --save
2、在main.js入口文件中引入:
代码语言:php复制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、在使用的页面中引用:
代码语言:php复制import { videoPlayer } from 'vue-video-player'
import 'video.js/dist/video-js.css'
4、构建播放器容器:
代码语言:php复制 <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
代码语言: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
代码语言:css复制import './assets/css/vediocommon.css'
js方法
代码语言:javascript复制@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文件导致你们复制粘贴后不能正常运行,所以将此视频上传封装成了一个组件方便大家在项目中直接引用
这里直接将源文件和icon图片资源上传供大家下载查看完整的
下载资源
总结(永远记得做一个有灵魂的人)
1、一部分人写CSDN是为了自己记个笔记所以别人看不懂正常,可以理解
2、复制粘贴纸上谈兵别人的东西就没有什么意思了
3、技术水平有限,但是每一行都是自己亲历亲为实现的,权当做个记录
4、希望对大家有一定的借鉴意义,欢迎沟通交流:15651012186
参考链接
ffmpeg的安装详细步骤
vue-video-player重写部分样式
在此对二位博文作者表示感谢!