perf: 优化视频播放

This commit is contained in:
kuaifan 2024-06-03 11:32:12 +08:00
parent 1a36044de2
commit 49203c15a7
9 changed files with 191 additions and 8 deletions

View File

@ -2218,7 +2218,7 @@ class Base
$type = ['jpg', 'jpeg', 'webp', 'gif', 'png'];
break;
case 'video':
$type = ['rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4'];
$type = ['rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'webm'];
break;
case 'audio':
$type = ['mp3', 'wma', 'wav', 'amr'];
@ -2233,7 +2233,7 @@ class Base
$type = ['zip'];
break;
case 'file':
$type = ['jpg', 'jpeg', 'webp', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz', 'ai', 'avi', 'bmp', 'cdr', 'eps', 'mov', 'mp3', 'mp4', 'pr', 'psd', 'svg', 'tif'];
$type = ['jpg', 'jpeg', 'webp', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz', 'ai', 'avi', 'bmp', 'cdr', 'eps', 'mov', 'mp3', 'mp4', 'webm', 'pr', 'psd', 'svg', 'tif'];
break;
case 'firmware':
$type = ['img', 'tar', 'bin'];
@ -2320,6 +2320,17 @@ class Base
}
}
//
if (in_array($extension, ['mp4', 'webm'])) {
// 视频尺寸
$thumbFile = $array['file'] . '_thumb.jpg';
shell_exec("ffmpeg -i {$array['file']} -ss 1 -vframes 1 {$thumbFile} 2>&1");
if (file_exists($thumbFile)) {
$paramet = getimagesize($thumbFile);
$array['width'] = $paramet[0];
$array['height'] = $paramet[1];
$array['thumb'] = $array['path'] . '_thumb.jpg';
}
}
if (in_array($extension, ['jpg', 'jpeg', 'webp', 'gif', 'png'])) {
//图片尺寸
$paramet = getimagesize($array['file']);

View File

@ -1,7 +1,7 @@
services:
php:
container_name: "dootask-php-${APP_ID}"
image: "kuaifan/php:swoole-8.0.rc14"
image: "kuaifan/php:swoole-8.0.rc15"
shm_size: "2gb"
ulimits:
core:

View File

@ -0,0 +1,74 @@
<template>
<div ref="view" class="common-preview-video">
<video v-if="item.src" :width="videoStyle('width')" :height="videoStyle('height')" controls autoplay>
<source :src="item.src" type="video/mp4">
</video>
</div>
</template>
<style lang="scss" scoped>
.common-preview-video {
position: fixed;
bottom: 0;
left: 0;
right: 0;
top: 0;
backdrop-filter: blur(4px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
> video {
max-width: 100%;
max-height: 100%;
}
}
</style>
<script>
export default {
props: {
item: {
type: Object,
default: () => ({
src: '',
width: 0,
height: 0,
}),
},
},
data() {
return {
}
},
mounted() {
},
methods: {
videoStyle(type) {
let {width, height} = this.item;
const maxWidth = this.windowWidth;
const maxHeight = this.windowHeight;
if (width > maxWidth) {
height = height * maxWidth / width;
width = maxWidth;
}
if (height > maxHeight) {
width = width * maxHeight / height;
height = maxHeight;
}
if (type === 'width') return width;
if (type === 'height') return height;
return {
width: `${width}px`,
height: `${height}px`,
}
},
},
};
</script>

View File

@ -8,8 +8,9 @@
:class-name="viewMode === 'desktop' ? 'common-preview-image-view' : 'common-preview-image-swipe'"
fullscreen>
<template v-if="list.length > 0">
<PreviewImageView v-if="viewMode === 'desktop'" :initial-index="index" :url-list="list" infinite/>
<PreviewImageSwipe v-if="viewMode === 'mobile'" :initial-index="index" :url-list="list" @on-destroy="show=false"/>
<PreviewVideoView v-if="viewVideo" :item="viewVideo"/>
<PreviewImageView v-else-if="viewMode === 'desktop'" :initial-index="index" :url-list="list" infinite/>
<PreviewImageSwipe v-else-if="viewMode === 'mobile'" :initial-index="index" :url-list="list" @on-destroy="show=false"/>
</template>
</Modal>
</template>
@ -64,12 +65,13 @@ body {
</style>
<script>
const PreviewVideoView = () => import('./components/video');
const PreviewImageView = () => import('./components/view');
const PreviewImageSwipe = () => import('./components/swipe');
export default {
name: 'PreviewImage',
components: {PreviewImageSwipe, PreviewImageView},
components: {PreviewVideoView, PreviewImageSwipe, PreviewImageView},
props: {
value: {
type: Boolean,
@ -104,6 +106,15 @@ export default {
}
},
computed: {
viewVideo() {
if (this.list.length === 0) {
return false
}
const item = this.list.find(({src}) => {
return /\.mp4$/i.test(src)
})
return item || false
},
viewMode() {
if (this.mode) {
return this.mode

View File

@ -57,6 +57,16 @@ export default {
position = newPaths.findIndex(item => item === paths[position]);
paths = newPaths;
}
const videoPath = paths.find(src => {
return /\.mp4$/i.test(src)
});
if (videoPath) {
$A.eeuiAppSendMessage({
action: 'videoPreview',
path: videoPath
});
return
}
$A.eeuiAppSendMessage({
action: 'picturePreview',
position,

View File

@ -34,6 +34,17 @@
<div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
<div class="dialog-file">
<img v-if="msgData.msg.type === 'img'" class="file-img" :style="imageStyle(msgData.msg)" :src="msgData.msg.thumb" @click="viewFile"/>
<div v-else-if="isVideoFile(msgData.msg)" class="file-video" :style="imageStyle(msgData.msg)" @click="viewFile">
<img v-if="msgData.msg.thumb" :src="msgData.msg.thumb">
<video v-else :width="imageStyle(msgData.msg, 'width')" :height="imageStyle(msgData.msg, 'height')">
<source :src="msgData.msg.path" type="video/mp4">
</video>
<div class="file-play">
<div class="play-icon">
<i class="taskfont">&#xe745;</i>
</div>
</div>
</div>
<div v-else class="file-box" @click="downFile">
<img class="file-thumb" :src="msgData.msg.thumb"/>
<div class="file-info">
@ -565,7 +576,7 @@ export default {
return {};
},
imageStyle(info) {
imageStyle(info, type = 'style') {
const {width, height} = info;
if (width && height) {
let maxW = 220,
@ -581,14 +592,30 @@ export default {
tempH = maxH;
}
}
if (type === 'width') {
return tempW
}
if (type === 'height') {
return tempH
}
return {
width: tempW + 'px',
height: tempH + 'px',
};
}
if (type === 'width' || type === 'height') {
return 0
}
return {};
},
isVideoFile(msg) {
return msg.type === 'file'
&& msg.ext === 'mp4'
&& msg.width > 0
&& msg.height > 0;
},
playRecord() {
if (this.operateVisible) {
return

View File

@ -3231,6 +3231,14 @@ export default {
data = this.operateItem
}
const {msg} = data;
if (msg.ext === 'mp4') {
this.$store.dispatch("previewImage", {
src: msg.path,
width: msg.width,
height: msg.height,
})
return
}
if (['jpg', 'jpeg', 'webp', 'gif', 'png'].includes(msg.ext)) {
this.onViewPicture(msg.path);
return

View File

@ -3439,7 +3439,7 @@ export default {
* @param data
*/
previewImage({state}, data) {
if (!$A.isJson(data)) {
if (!$A.isJson(data) || !$A.isArray(data.list)) {
data = {index:0, list: [data]}
}
state.previewImageIndex = data.index;

View File

@ -1018,6 +1018,48 @@
&.file {
display: inline-block;
.file-video {
display: flex;
position: relative;
cursor: pointer;
> img,
> video {
width: 100%;
height: 100%;
}
.file-play {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.1);
.play-icon {
border: 2px solid #a0a0a0;
border-radius: 50%;
width: 42px;
height: 42px;
line-height: 42px;
display: flex;
align-items: center;
justify-content: center;
> i {
color: #a0a0a0;
font-size: 30px;
padding-left: 4px;
transform: scaleY(0.8);
}
}
}
}
.file-box {
background-color: #ffffff;
display: flex;