鸿蒙选择本地视频文件,并获取首帧预览图

虎子船长
发布于 2025-8-7 14:06
浏览
0收藏

由于文件权限获取不太方便,现在使用的是 picker 的方式获取本地视频文件。文件位于我的手机/下载目录下。

操作分为几步:

  1. 获取文件地址;
  2. 获取视频信息;
  3. 首帧截图;
  4. 显示截图;

获取文件地址

typescripttry
let context = CCAppContext.context.getHostContext()!
let documentSelectOptions = new picker.DocumentSelectOptions();
fileSuffixFilters = ['视频|.mp4', '视频|.avi']
let documentPicker = new picker.DocumentViewPicker(context);
select(documentSelectOptions).then((documentSelectResult: Array<string>) =>
console.info('DocumentViewPicker.select successfully, documentSelectResult uri: ' + JSON.stringify(documentSelectResult));
if (documentSelectResult.length > 0) {
let uri = documentSelectResult[0] // 这个是获取到的文件地址
catch((err: BusinessError) =>
console.error(`DocumentViewPicker.select failed with err, code is: ${err.code}, message is: ${err.message}`);
  });
} catch
let err: BusinessError = error as BusinessError;
console.error(`DocumentViewPicker failed with err, code is: ${err.code}, message is: ${err.message}`);
}

获取视频信息 & 获取首帧截图 & 显示图片

typescripttry
// 打开视频文件获取文件描述符
let fd = await fileIo.open(videoPath, fileIo.OpenMode.READ_ONLY)

const extractor = await media.createAVMetadataExtractor()
fdSrc = { fd: fd.fd

let metaData = await extractor.fetchMetadata()
this.imageWidth = parseInt(metaData.videoWidth || '1') // 视频宽度
this.imageHeight = parseInt(metaData.videoHeight || '1') // 视频高度
let orientation = metaData.videoOrientation // 视频旋转,截图有可能有旋转角度

const avImageGenerator = await media.createAVImageGenerator()
fdSrc = { fd: fd.fd

// 配置缩略图参数
const param: media.PixelMapParams
width: this.imageWidth,
height: this.imageHeight,
  }
this.pixelMap = await avImageGenerator.fetchFrameByTime(
0, // 0表示首帧(单位微秒)
AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,
    param
  )
await avImageGenerator.release() // 释放资源
close(fd) // 关闭文件
} catch
console.error(`Get thumbnail failed: ${error.code}, ${error.message}`)
}

完整代码

typescriptimport { fileIo, fileUri, picker } from '@kit.CoreFileKit';
import { BusinessError } from '@ohos.base'
import { media } from '@kit.MediaKit';

@Entry
struct test {
@State pixelMap: PixelMap | undefined = undefined
@State imageWidth: number = 1
@State imageHeight: number = 1
@State orientation: number = 0

chooseFile() {
try
let context = getContext()
let documentSelectOptions = new picker.DocumentSelectOptions();
fileSuffixFilters = ['视频|.mp4', '视频|.avi']
let documentPicker = new picker.DocumentViewPicker(context);
select(documentSelectOptions).then((documentSelectResult: Array<string>) =>
console.info('DocumentViewPicker.select successfully, documentSelectResult uri: ' + JSON.stringify(documentSelectResult));
if (documentSelectResult.length > 0) {
let uri = documentSelectResult[0]
this.getFirstFrame(uri)
        }
catch((err: BusinessError) =>
console.error(`DocumentViewPicker.select failed with err, code is: ${err.code}, message is: ${err.message}`);
      });
catch
let err: BusinessError = error as BusinessError;
console.error(`DocumentViewPicker failed with err, code is: ${err.code}, message is: ${err.message}`);
    }
  }

async getFirstFrame(videoPath: string) {
try
// 打开视频文件获取文件描述符
let fd = await fileIo.open(videoPath, fileIo.OpenMode.READ_ONLY);

const extractor = await media.createAVMetadataExtractor()
fdSrc = { fd: fd.fd

let metaData = await extractor.fetchMetadata()
this.imageWidth = parseInt(metaData.videoWidth || '1')
this.imageHeight = parseInt(metaData.videoHeight || '1')
this.orientation = parseInt(metaData.videoOrientation || '0')

const avImageGenerator = await media.createAVImageGenerator();
fdSrc = { fd: fd.fd

// 配置缩略图参数
const param: media.PixelMapParams
width: this.imageWidth,
height: this.imageHeight
      };
this.pixelMap = await avImageGenerator.fetchFrameByTime(
0, // 0表示首帧(单位微秒)
AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,
        param
      );
await avImageGenerator.release(); // 释放资源
close(fd); // 关闭文件
catch
console.error(`Get thumbnail failed: ${error.code}, ${error.message}`);
    }
  }

build() {
Column() {
Text('截图')
fontSize('22fp')
fontColor(Color.Black)
onClick(() =>
this.chooseFile()
        })

Image(this.pixelMap)
objectFit(ImageFit.Cover)
width('30%')
aspectRatio(1)
orientation(this.orientation)
    }
justifyContent(FlexAlign.Center)
alignItems(HorizontalAlign.Center)
width('100%')
height('100%')
  }
}


作者:xyccstudio
链接:https://juejin.cn/post/7526304394235133986

分类
标签
1
收藏
回复
举报
回复
    相关推荐