效果图
写在前面(吐槽)
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 add cordova-plugin-file-transfer
上传文件至服务器
上传方法
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);
_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"];
$str = "ffmpeg -y -i ". $ofile. " -s 720x960 -b:v 562k -c:v libx264 " . $nfile;
exec("$str", $output,$status);
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,
muted: false,
loop: false,
preload: 'auto',
language: 'zh-CN',
aspectRatio: '9:16',
sources: [{
type: "video/mp4",
src: ''
}],
poster:'http://81.68.107.23/uploads/poster.png',
notSupportedMessage: '此视频暂无法播放,请稍后再试',
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;
}
.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;
}
.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文件导致你们复制粘贴后不能正常运行,所以将此视频上传封装成了一个组件方便大家在项目中直接引用 这里直接将源文件和icon图片资源上传供大家下载查看完整的 下载资源
总结(永远记得做一个有灵魂的人)
1、一部分人写CSDN是为了自己记个笔记所以别人看不懂正常,可以理解 2、复制粘贴纸上谈兵别人的东西就没有什么意思了 3、技术水平有限,但是每一行都是自己亲历亲为实现的,权当做个记录 4、希望对大家有一定的借鉴意义,欢迎沟通交流:15651012186
参考链接
ffmpeg的安装详细步骤 vue-video-player重写部分样式 在此对二位博文作者表示感谢!
|