|
|
@@ -529,67 +529,9 @@ export class Utility {
|
|
|
|
|
|
return format;
|
|
|
}
|
|
|
- //获取从文件管理器获得的视频资源的属性值
|
|
|
- static async uriGetAssetsFromFile(context:Context,uri:string,type:number,isLoadPixelMap?:boolean): Promise<VideoItem> {
|
|
|
- let item:VideoItem = new VideoItem('',uri,uri,type,0,'')
|
|
|
- try {
|
|
|
- console.info('asset file.uri: ', uri);
|
|
|
-
|
|
|
-
|
|
|
- let file = fs.openSync(uri, fs.OpenMode.READ_ONLY | fs.OpenMode.CREATE)
|
|
|
- console.info("file.fd " + file.fd);
|
|
|
- let fdfd = 'fd://' + file.fd
|
|
|
- //3、通过fs.stat方法获取stat对象
|
|
|
- console.info('asset file.name: ', file.name);
|
|
|
- console.info('asset file.uri: ', uri);
|
|
|
- console.info('asset file.fd: ', file.fd);
|
|
|
- console.info('asset file.path: ', file.path);
|
|
|
- item = new VideoItem(file.name,uri,uri,type,0,'')
|
|
|
- await fs.stat(file.fd).then(async (stat: fs.Stat) => {
|
|
|
- console.info("get file info succeed, the size of file is " + stat.size);
|
|
|
- let videoSize = stat.size
|
|
|
- // let videoTime = stat.ctime
|
|
|
-
|
|
|
- let fileSize = Utility.formatFSize(videoSize)
|
|
|
- let cTime = Utility.getFormatDateStr(stat.mtime,'yyyy-MM-dd HH:mm')
|
|
|
-
|
|
|
- // console.info('asset stat.ino: ', stat.ino);
|
|
|
- // console.info('asset stat.mode: ', stat.mode);
|
|
|
- // console.info('asset stat.uid: ', stat.uid);
|
|
|
- // console.info('asset stat.ino: ', stat.gid);
|
|
|
- // console.info('asset stat.size: ', stat.size);
|
|
|
- console.info('asset stat.ctime: ', stat.ctime);
|
|
|
- // console.info('asset stat.mtime: ', stat.mtime);
|
|
|
- // console.info('asset stat.duration: ', duration);
|
|
|
-
|
|
|
-
|
|
|
- let pixelMap:image.PixelMap|undefined = undefined
|
|
|
- if(isLoadPixelMap){
|
|
|
- //获取缩略图
|
|
|
- if(Utility.isVideoByExtension(uri)){
|
|
|
- pixelMap = await Utility.getFetchFrameByTime(uri)
|
|
|
- }else{
|
|
|
- pixelMap = await Utility.getFetchMetadataFromFdSrcByPromise(uri)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- item = new VideoItem( file.name,uri ,uri,type,videoSize,cTime,pixelMap,fileSize,
|
|
|
- await ImageUtil.pixelMapToBase64Str(pixelMap))
|
|
|
-
|
|
|
|
|
|
|
|
|
|
|
|
- })
|
|
|
- } catch (error) {
|
|
|
- console.error('uriGetAssetsFromFile failed with err: ' + JSON.stringify(error));
|
|
|
- }
|
|
|
-
|
|
|
- return item
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
static async getFilePixelMapBig(uri:string){
|
|
|
let pixelMap:image.PixelMap|undefined = undefined
|
|
|
if(Utility.isMusicByExtension(uri)){
|
|
|
@@ -954,23 +896,25 @@ export class Utility {
|
|
|
stream.disposition?.attached_pic === 1
|
|
|
);
|
|
|
console.info('readMetaInfoFFmpeg asset hasCover: ', hasCover);
|
|
|
+ let md5Name = await MD5.digestSync(inputPath)
|
|
|
+ let imagePath = `${context.filesDir}${FileUtil.separator}${md5Name}.jpg`;
|
|
|
+ console.info('readMetaInfoFFmpeg asset imagePath: ', imagePath);
|
|
|
// 如果有封面图片,则提取
|
|
|
- if (hasCover) {
|
|
|
-
|
|
|
- try {
|
|
|
- let md5Name = await MD5.digestSync(inputPath)
|
|
|
- let imagePath = `${context.filesDir}${FileUtil.separator}${md5Name}.jpg`;
|
|
|
- console.info('readMetaInfoFFmpeg asset imagePath: ', imagePath);
|
|
|
+ try {
|
|
|
+ if (hasCover) {
|
|
|
+ //提取封面
|
|
|
+ await getFFmpegCover(inputPath, imagePath);
|
|
|
+ imagePath = fileUri.getUriFromPath(imagePath)
|
|
|
+ videoItem.pixelMapPath = imagePath;
|
|
|
+ }else if(Utility.isVideoByExtension(inputPath)){
|
|
|
//提取封面
|
|
|
- await getFFmpegCover(inputPath, imagePath);
|
|
|
+ await getVideoFFmpegCover(inputPath, imagePath);
|
|
|
imagePath = fileUri.getUriFromPath(imagePath)
|
|
|
videoItem.pixelMapPath = imagePath;
|
|
|
-
|
|
|
- } catch (error) {
|
|
|
- console.warn(' 提取封面图片失败:', error.message);
|
|
|
}
|
|
|
+ } catch (error) {
|
|
|
+ console.warn(' 提取封面图片失败:', error.message);
|
|
|
}
|
|
|
-
|
|
|
console.info('Successfully parsed metadata:', videoItem);
|
|
|
resolve(videoItem);
|
|
|
})
|
|
|
@@ -1628,35 +1572,6 @@ function getFileNameWithoutExtension(filePath: string): string {
|
|
|
return lastDotIndex > 0 ? fileName.substring(0, lastDotIndex) : fileName;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * 从视频文件中提取封面
|
|
|
- * @param inputPath 音乐文件路径
|
|
|
- * @returns Promise<void>
|
|
|
- */
|
|
|
-async function extractCoverImage(inputPath: string, outputPath: string): Promise<void> {
|
|
|
- const commands = [
|
|
|
- 'ffmpeg',
|
|
|
- '-i', inputPath,
|
|
|
- '-an', // 禁用音频
|
|
|
- '-vcodec', 'copy', // 直接复制视频流
|
|
|
- '-f', 'image2', // 强制输出为图片
|
|
|
- '-y', // 覆盖输出文件
|
|
|
- outputPath
|
|
|
- ];
|
|
|
-
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- FFmpeg.execute(commands, {
|
|
|
- logCallback: (logLevel: number, logMessage: string) => {
|
|
|
- console.log(`[${logLevel}]${logMessage}`);
|
|
|
- },
|
|
|
- outputCallback: (message: string) => {
|
|
|
- console.log(`FFmpeg output: ${message}`);
|
|
|
- },
|
|
|
- }).then(() => resolve())
|
|
|
- .catch((error: BusinessError) => reject(error));
|
|
|
- });
|
|
|
-}
|
|
|
-
|
|
|
|
|
|
/**
|
|
|
* 从音乐文件中提取封面
|
|
|
@@ -1680,6 +1595,28 @@ async function getFFmpegCover(inputPath: string, outputPath: string) {
|
|
|
console.error(`FFmpeg execution failed with error: ${error.message}`);
|
|
|
});
|
|
|
}
|
|
|
+/**
|
|
|
+ * 从视频文件中提取封面 提前视频第5帧的封面
|
|
|
+ * @param inputPath 文件路径
|
|
|
+ * @returns Promise<void>
|
|
|
+ */
|
|
|
+async function getVideoFFmpegCover(inputPath: string, outputPath: string) {
|
|
|
+ let commands = ["ffmpeg", "-y","-i", inputPath, "-ss", "00:00:05", "-t", "1","-r",'1','-q:v','2','-f','image2', outputPath];
|
|
|
+ FFmpeg.execute(commands, {
|
|
|
+ logCallback: (logLevel: number, logMessage: string) => {
|
|
|
+ console.info(`[FFmpegX LOG] [${logLevel}]${logMessage}`)
|
|
|
+ },
|
|
|
+ progressCallback: (message: string) => {
|
|
|
+ console.info(`[FFmpegX progress]${JSON.stringify(FFProgressMessageParser.parse(message))}`)
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .then(() => {
|
|
|
+
|
|
|
+ })
|
|
|
+ .catch((error: Error) => {
|
|
|
+ console.error(`FFmpegX execution failed with error: ${error.message}`);
|
|
|
+ });
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* 从音乐文件中提取歌词内容
|
|
|
@@ -1825,7 +1762,7 @@ interface SupportedFormats {
|
|
|
// 声明并初始化支持的音频格式(符合类型定义)
|
|
|
const SUPPORTED_FORMATS: SupportedFormats = {
|
|
|
LOSSY: new Set(['mp3', 'aac', 'ogg', 'opus', 'wma']),
|
|
|
- LOSSLESS: new Set(['flac', 'alac', 'ape', 'wav', 'aiff'])
|
|
|
+ LOSSLESS: new Set(['flac', 'alac', 'ape', 'wav', 'aiff', 'dsf','aif'])
|
|
|
};
|
|
|
|
|
|
/**
|