目录

Obtaining Video Thumbnails Using System Capabilities

Overview

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:

Obtaining the Default Video Thumbnail

[h2]How to Implement

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.

[h2]How to Develop

  1. Use PhotoViewPicker of the album management module @ohos.file.photoAccessHelper to select a video from Gallery and retrieve its URL.
    /**
     * 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 '';
      }
    }
  2. Use the getAssets() method to obtain the video resource based on the URL of the selected video.
    // 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();
  3. Configure the thumbnail size based on the video resource attributes and call the getThumbnail() method to obtain an image in PixelMap format.
    // 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.

[h2]Demo

Selecting a Video Frame as the Thumbnail

[h2]How to Implement

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.

[h2]How to Develop

  1. Launch the Gallery picker to select a video and obtain the file descriptor for the resource.
    /**
     * 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}`);
      })
    }
  2. Obtain video metadata based on the file descriptor.
    /**
     * 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;
    }
  3. Create an AVImageGenerator.
    this.avImageGenerator = await media.createAVImageGenerator();
    if (this.avImageGenerator) {
      this.avImageGenerator.fdSrc = this.avFileDescriptor;
    } else {
      hilog.error(0X0000, TAG, 'Create AVImageGenerator failed!');
      return;
    }
  4. Use the fetchFrameByTime() method to obtain the thumbnail at a specified time and return the image in PixelMap format.
    /**
     * 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;
      });
    }

[h2]Demo

FAQs

[h2]How do I obtain the thumbnail of an online video?

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.

Sample Code