uniapp开发app 上传视频切片上传
<u-toast ref="uploadFileToast">
<view style="font-weight: bold;font-size: 30rpx;">正在上传视频</view>
<view>当前进度 {{curUploadVideoProgress}}%</view>
</u-toast>
js部分
uni.chooseVideo({
count: this.videoMaxCount,
// compressed: this.platform == 'ios' ? false : true, //苹果不压缩 压缩会导致苹果视频 变横屏
compressed: false,
pageOrientation:'auto',
camera: this.cameraList[this.cameraIndex].value, //'front'、'back',默认'back'
sourceType: ['album', 'camera'],
success: async e => {
console.log('原文件视频e: ', e);
uni.getVideoInfo({
src:e.tempFilePath,
success:async (detailedInformation) => {
console.log('视频详细信息detailedInformation: ', detailedInformation);
that.uploadVideoChunks(e, detailedInformation ,(r) => {
that.videoList = [];
that.videoList = [r]
});
}
})
// this.fileVideo(e)
},
fail: (fail) => {
console.log('上传失败', fail)
that.showManualAuth('android.permission.CAMERA');
},
complete: () => {
try {
plus.navigator.setFullscreen(false)
} catch (error) {
}
}
}),
// 负责将视频文件分片并发上传
async uploadVideoChunks(e,detailedInformation,callBack) {
if (e.size > 300 * 1024 * 1024) {
uni.showToast({
title: '视频过大,请您上传300Mb以内视频',
icon: 'none',
duration: 2000
});
return
}
let that = this
const filePath = e.tempFilePath;
const fileSize = e.size;
const CHUNK_SIZE = 1024 * 1024 * 10; // 每个分片的大小,这里设置为5MB
const totalChunks = Math.ceil(fileSize / CHUNK_SIZE); // 总切片数
const extension = filePath.substring(filePath.lastIndexOf('/') + 1).split('.').pop();
const fileName = `${this.randomString(10)+ new Date().getTime()}.${extension}`; // 视频文件名
console.log('视频文件名: ', fileName);
const chunkPromises = [];
const chunkProgresses = new Array(totalChunks).fill(0);// 用于存储每个分片的上传进度
for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
const start = chunkIndex * CHUNK_SIZE;
const end = Math.min(start + CHUNK_SIZE, fileSize);
const chunk = await this.sliceFile(filePath, start, end);
console.log('chunk: ', chunk);
const uploadPromise = this.uploadChunk(chunk, fileName, chunkIndex, totalChunks , (progress) => {
// 更新当前分片的进度
chunkProgresses[chunkIndex] = progress;
// 计算总的上传进度
const totalProgress = chunkProgresses.reduce((sum, current) => sum + current, 0) / totalChunks;
this.curUploadVideoProgress = Math.round(totalProgress);
// console.log(`当前上传进度: ${that.curUploadVideoProgress}%`);
});
chunkPromises.push(uploadPromise);
}
try {
that.$refs.uploadFileToast.show({
type: 'loading',
title: '',
message: "",
iconUrl: 'https://cdn.uviewui.com/uview/demo/toast/loading.png',
duration: 999999
})
let ressss = await Promise.all(chunkPromises);
that.$refs.uploadFileToast.hide()
uni.showLoading({
mask: true,
title: '视频处理中,请稍等...'
})
this.curUploadVideoProgress = 0;
console.log('ressss: ', ressss);
let params = {
name: fileName,
chunks: totalChunks,
merge: 1
}
// 通知服务器合并分片并压缩处理
console.log('通知服务器合并分片params: ', params);
this.$circleApi.uploadfile(params).then(result => {
console.log('视频所有分片上传完成',result);
let params = {
url: result.url,
file_class: result.file_class,
mimetype: detailedInformation.type,
filesize: result.filesize || 0,
width: result.width || 0,
height: result.height || 0,
}
console.log('保存数据库params: ', params);
// 保存数据库
this.$circleApi.postCircleDynamicSavefiles(params).then((resPCDSF) => {
console.log('保存数据库成功resPCDSF: ', resPCDSF);
let r = {
url: result.vedio_url,
id: resPCDSF.files_id
}
uni.hideLoading();
callBack(r)
}).catch(err => {
uni.$u.toast("文件上传失败");
uni.hideLoading();
console.log('err: ', err);
})
}).catch(err => {
uni.$u.toast("文件上传失败");
that.$refs.uploadFileToast.hide()
console.log('err: ', err);
})
} catch (error) {
console.error('分片上传过程中出现错误:', error);
uni.$u.toast("文件上传失败");
that.$refs.uploadFileToast.hide()
}
},
// 从视频文件中截取指定范围的分片。
async sliceFile(filePath, start, end) {
return new Promise((resolve, reject) => {
// 将相对路径转换为绝对路径
const absolutePath = plus.io.convertLocalFileSystemURL(filePath);
plus.io.resolveLocalFileSystemURL(absolutePath, function (entry) {
entry.file(function (file) {
const blob = file.slice(start, end);
resolve(blob);
}, function (e) {
reject(e);
});
}, function (e) {
reject(e);
});
});
},
// 将单个分片上传到服务器
async uploadChunk(chunk, fileName, chunkIndex, totalChunks , onProgress) {
console.log(`开始上传第 ${chunkIndex + 1} 个分片,共 ${totalChunks} 个分片`)
const token = 'Bearer ' + this.userInfo.token
let platform = uni.getSystemInfoSync().platform
let types = 'Android'
if (platform === 'ios') {
types = 'iOS'
} else if (platform === 'android') {
types = 'Android'
} else {
types = 'llkj'
}
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: base.baseUrl + '/circle/dynamic/multiUpload', // 替换为实际的上传接口地址
filePath: chunk.fullPath,
name: 'file',
header:{
"Content-Type": "multipart/form-data",
'Authorization': token,
'Api-Client': types,
},
formData: {
name: fileName,
chunk: chunkIndex,
chunks: totalChunks,
},
success: (res) => {
resolve(res)
console.log('上传结果res: ', res);
},
fail: (err) => {
reject(err);
}
});
uploadTask.onProgressUpdate((res) => {
const progress = res.progress;
if (onProgress) {
onProgress(progress);
}
});
});
},
}