选择本地视频文件,并获取首帧预览图
由于文件权限获取不太方便,现在使用的是 picker 的方式获取本地视频文件。文件位于我的手机/下载目录下。
操作分为几步:
- 获取文件地址;
- 获取视频信息;
- 首帧截图;
- 显示截图;
获取文件地址
typescript
try {
let context = CCAppContext.context.getHostContext()!
let documentSelectOptions = new picker.DocumentSelectOptions();
documentSelectOptions.fileSuffixFilters = ['视频|.mp4', '视频|.avi']
let documentPicker = new picker.DocumentViewPicker(context);
documentPicker.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 (error) {
let err: BusinessError = error as BusinessError;
console.error(`DocumentViewPicker failed with err, code is: ${err.code}, message is: ${err.message}`);
}
获取视频信息 & 获取首帧截图 & 显示图片
typescript
try {
// 打开视频文件获取文件描述符
let fd = await fileIo.open(videoPath, fileIo.OpenMode.READ_ONLY)
const extractor = await media.createAVMetadataExtractor()
extractor.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()
avImageGenerator.fdSrc = { fd: fd.fd }
// 配置缩略图参数
const param: media.PixelMapParams = {
width: this.imageWidth,
height: this.imageHeight,
}
this.pixelMap = await avImageGenerator.fetchFrameByTime(
0, // 0表示首帧(单位微秒)
media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,
param
)
await avImageGenerator.release() // 释放资源
fileIo.close(fd) // 关闭文件
} catch (error) {
console.error(`Get thumbnail failed: ${error.code}, ${error.message}`)
}
完整代码
typescript
import { 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();
documentSelectOptions.fileSuffixFilters = ['视频|.mp4', '视频|.avi']
let documentPicker = new picker.DocumentViewPicker(context);
documentPicker.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 (error) {
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()
extractor.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();
avImageGenerator.fdSrc = { fd: fd.fd };
// 配置缩略图参数
const param: media.PixelMapParams = {
width: this.imageWidth,
height: this.imageHeight
};
this.pixelMap = await avImageGenerator.fetchFrameByTime(
0, // 0表示首帧(单位微秒)
media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC,
param
);
await avImageGenerator.release(); // 释放资源
fileIo.close(fd); // 关闭文件
} catch (error) {
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%')
}
}