A video thumbnail serves as a static preview image extracted from a video and is often used as a cover of the video. It facilitates rapid content browsing and selection in scenarios like video browsing, sharing, and management, thereby enhancing user experience. HarmonyOS provides specific module capabilities to help you obtain the thumbnail of a video file. There are two scenarios based on the application's strategy for acquiring thumbnails:
The default thumbnail of a video typically corresponds to its first frame and can be retrieved using the getThumbnail() method of the PhotoAsset class. The following example describes the scenario of obtaining the default thumbnail of a video stored in Gallery.
/**
* Pull up the gallery picker and select a video.
* @returns The url of the selected video.
*/
async selectVideo(): Promise<string> {
try {
let photoViewPicker = new photoAccessHelper.PhotoViewPicker();
return photoViewPicker.select({
MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE,
maxSelectNumber: 1
}).then((photoSelectResult: photoAccessHelper.PhotoSelectResult): string => {
if (photoSelectResult.photoUris.length <= 0) {
return '';
}
return photoSelectResult.photoUris[0];
})
} catch (error) {
hilog.error(0x0000, TAG, `selectVideo catch error, code: ${error.code}, message: ${error.message}`);
return '';
}
} // Obtain video resources.
let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
predicates.equalTo('uri', videoUrl);
let videoFetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> =
await this.phAccessHelper.getAssets({
fetchColumns: ['width', 'height', 'orientation'],
predicates: predicates
});
let photoAsset: photoAccessHelper.PhotoAsset = await videoFetchResult.getFirstObject(); // Configure thumbnail parameters.
let thumbnailSize: Size = { width: 0, height: 0 };
if (photoAsset.get(photoAccessHelper.PhotoKeys.ORIENTATION) === 90 ||
photoAsset.get(photoAccessHelper.PhotoKeys.ORIENTATION) === 270) {
thumbnailSize.width = photoAsset.get(photoAccessHelper.PhotoKeys.HEIGHT) as number;
thumbnailSize.height = photoAsset.get(photoAccessHelper.PhotoKeys.WIDTH) as number;
} else {
thumbnailSize.width = photoAsset.get(photoAccessHelper.PhotoKeys.WIDTH) as number;
thumbnailSize.height = photoAsset.get(photoAccessHelper.PhotoKeys.HEIGHT) as number;
}
return photoAsset.getThumbnail(thumbnailSize);
To use the getAsset() and getThumbnail() methods, the permission ohos.permission.READ_IMAGEVIDEO is required. For applications that require operations such as cloning, backing up, or synchronizing image/video files, you can request this permission, use the getAlbums() method to obtain album resources, and then call the two methods to obtain thumbnails. Alternatively, you can use the picker method to access the specified Gallery resources and call the two methods to obtain the thumbnail without obtaining the permission. This topic uses the picker mode.
In HarmonyOS, the AVImageGenerator class is used to obtain video thumbnails by enabling the selection of a frame at a specific time within the video to serve as the thumbnail. The following example describes the scenario of selecting a thumbnail for a video stored in Gallery.
/**
* Obtain video resources through AVImageGenerator.
*/
async imageGeneratorGetThumbnail() {
this.photoUtils.selectVideo().then(async (result: string) => {
// ...
this.fileAlbum = fileIo.openSync(result, fileIo.OpenMode.READ_ONLY);
this.avFileDescriptor = { fd: this.fileAlbum.fd };
// ...
}).catch((error: BusinessError) => {
hilog.error(0x0000, TAG,
`Invoke imageGeneratorGetThumbnail failed!, error code: ${error.code}, message: ${error.message}`);
})
} /**
* Get video infos through video file descriptor.
* @param avFileDescriptor AVFileDescriptor of video.
* @returns the size infos of video.
*/
async getVideoData(avFileDescriptor: media.AVFileDescriptor): Promise<VideoSizeData> {
let videoSize: VideoSizeData = new VideoSizeData();
try {
let avMetaDataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
avMetaDataExtractor.fdSrc = avFileDescriptor;
let metadata = await avMetaDataExtractor.fetchMetadata();
videoSize.photoSize.width = parseInt(metadata.videoWidth as string);
videoSize.photoSize.height = parseInt(metadata.videoHeight as string);
if (metadata.duration) {
videoSize.totalTime = parseInt(metadata.duration);
}
avMetaDataExtractor.release();
} catch (error) {
hilog.error(0x0000, TAG, `getVideoData catch error, code: ${error.code}, message: ${error.message}`);
}
return videoSize;
} this.avImageGenerator = await media.createAVImageGenerator();
if (this.avImageGenerator) {
this.avImageGenerator.fdSrc = this.avFileDescriptor;
} else {
hilog.error(0X0000, TAG, 'Create AVImageGenerator failed!');
return;
} /**
* Obtain a frame at a certain point in time of the video.
* @param time A certain point in time of the video.
*/
async fetchFrameByTime(time: number) {
this.pixelMap = await this.avImageGenerator?.fetchFrameByTime(time,
media.AVImageQueryOptions.AV_IMAGE_QUERY_CLOSEST_SYNC, this.videoSize.photoSize).catch((error: BusinessError)=>{
hilog.error(0x0000, TAG, `release catch error, code: ${error.code}, message: ${error.message}`);
return undefined;
});
} You are advised to use the setUrlSource() API added in API version 20 to obtain the data source corresponding to the URL of an online video through an AVMetadataExtractor instance, and then call the fetchFrameByTime() API to obtain its thumbnail.