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']; $type = ['jpg', 'jpeg', 'webp', 'gif', 'png'];
break; break;
case 'video': case 'video':
$type = ['rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4']; $type = ['rm', 'rmvb', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'webm'];
break; break;
case 'audio': case 'audio':
$type = ['mp3', 'wma', 'wav', 'amr']; $type = ['mp3', 'wma', 'wav', 'amr'];
@ -2233,7 +2233,7 @@ class Base
$type = ['zip']; $type = ['zip'];
break; break;
case 'file': 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; break;
case 'firmware': case 'firmware':
$type = ['img', 'tar', 'bin']; $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'])) { if (in_array($extension, ['jpg', 'jpeg', 'webp', 'gif', 'png'])) {
//图片尺寸 //图片尺寸
$paramet = getimagesize($array['file']); $paramet = getimagesize($array['file']);

View File

@ -1,7 +1,7 @@
services: services:
php: php:
container_name: "dootask-php-${APP_ID}" container_name: "dootask-php-${APP_ID}"
image: "kuaifan/php:swoole-8.0.rc14" image: "kuaifan/php:swoole-8.0.rc15"
shm_size: "2gb" shm_size: "2gb"
ulimits: ulimits:
core: 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'" :class-name="viewMode === 'desktop' ? 'common-preview-image-view' : 'common-preview-image-swipe'"
fullscreen> fullscreen>
<template v-if="list.length > 0"> <template v-if="list.length > 0">
<PreviewImageView v-if="viewMode === 'desktop'" :initial-index="index" :url-list="list" infinite/> <PreviewVideoView v-if="viewVideo" :item="viewVideo"/>
<PreviewImageSwipe v-if="viewMode === 'mobile'" :initial-index="index" :url-list="list" @on-destroy="show=false"/> <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> </template>
</Modal> </Modal>
</template> </template>
@ -64,12 +65,13 @@ body {
</style> </style>
<script> <script>
const PreviewVideoView = () => import('./components/video');
const PreviewImageView = () => import('./components/view'); const PreviewImageView = () => import('./components/view');
const PreviewImageSwipe = () => import('./components/swipe'); const PreviewImageSwipe = () => import('./components/swipe');
export default { export default {
name: 'PreviewImage', name: 'PreviewImage',
components: {PreviewImageSwipe, PreviewImageView}, components: {PreviewVideoView, PreviewImageSwipe, PreviewImageView},
props: { props: {
value: { value: {
type: Boolean, type: Boolean,
@ -104,6 +106,15 @@ export default {
} }
}, },
computed: { computed: {
viewVideo() {
if (this.list.length === 0) {
return false
}
const item = this.list.find(({src}) => {
return /\.mp4$/i.test(src)
})
return item || false
},
viewMode() { viewMode() {
if (this.mode) { if (this.mode) {
return this.mode return this.mode

View File

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

View File

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

View File

@ -3231,6 +3231,14 @@ export default {
data = this.operateItem data = this.operateItem
} }
const {msg} = data; 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)) { if (['jpg', 'jpeg', 'webp', 'gif', 'png'].includes(msg.ext)) {
this.onViewPicture(msg.path); this.onViewPicture(msg.path);
return return

View File

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

View File

@ -1018,6 +1018,48 @@
&.file { &.file {
display: inline-block; 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 { .file-box {
background-color: #ffffff; background-color: #ffffff;
display: flex; display: flex;