跳到主要内容

使用AVImageGenerator获取视频帧(C/C++)

使用AVImageGenerator可以实现从原始媒体资源中获取指定时间的视频帧,本开发指导将以获取视频帧作为示例,向开发者讲解AVImageGenerator相关功能。

获取视频帧的全流程包含:创建AVImageGenerator对象、设置资源、获取视频帧、销毁资源。

开发步骤及注意事项

在 CMake 脚本中链接动态库。

target_link_libraries(entry PUBLIC libavimage_generator.so libace_napi.z.so)

使用OH_PixelmapNative_ConvertPixelmapNativeToNapi()接口将nativePixelMap对象转换为PixelMapnapi对象、OH_PixelmapNative_Release()接口释放OH_PixelmapNative对象资源,需引入如下头文件。

#include <multimedia/image_framework/image/pixelmap_native.h>

并在 CMake 脚本中链接如下动态库。

target_link_libraries(entry PUBLIC libpixelmap.so libpixelmap_ndk.z.so)

开发者使用系统日志能力时,需引入如下头文件。

#include <hilog/log.h>

并需要在 CMake 脚本中链接如下动态库。

target_link_libraries(entry PUBLIC libhilog_ndk.z.so)

(可选)开发者可以使用OH_AVMetadataExtractor_FetchMetadata()获取媒体资源时长信息OH_AVMETADATA_EXTRACTOR_DURATION,进而选择获取视频帧的时间。使用需引入如下头文件。

#include "multimedia/player_framework/avmetadata_extractor.h"
#include "multimedia/player_framework/avmetadata_extractor_base.h"

并需要在 CMake 脚本中链接如下动态库。

target_link_libraries(entry PUBLIC libavmetadata_extractor.so libnative_media_core.so)

开发者通过引入avimage_generator.havimage_generator_base.hnative_averrors.h头文件,使用获取视频帧相关API。

详细的API说明请参考AVImageGenerator API参考

  1. 使用OH_AVImageGenerator_Create()创建实例。

    #include <multimedia/player_framework/avimage_generator.h>
    // 创建OH_AVImageGenerator实例。
    OH_AVImageGenerator* generator = OH_AVImageGenerator_Create();
  2. 设置视频资源的文件描述符:调用OH_AVImageGenerator_SetFDSource()

    #include "napi/native_api.h"
    #include <multimedia/player_framework/avimage_generator.h>
    #include <multimedia/player_framework/native_averrors.h>

    int64_t offset = 0; // 媒体源在文件描述符中的偏移量。
    int32_t fileDescribe = -1; // 媒体文件描述符。
    int32_t fileSize = 0; // 媒体文件大小。

    // 设置视频资源的文件描述符。
    OH_AVErrCode avErrCode = OH_AVImageGenerator_SetFDSource(generator, fileDescribe, offset, fileSize);
    // 异常处理。
    if (avErrCode != AV_ERR_OK) {
    OH_AVImageGenerator_Release(generator);
    napi_throw_error(env, "EFAILED", "SetFDSource failed");
    return nullptr;
    }
  3. (可选)获取媒体资源时长信息,并指定获取视频帧的时间。

    #include "napi/native_api.h"
    #include "multimedia/player_framework/avmetadata_extractor.h"
    #include "multimedia/player_framework/avmetadata_extractor_base.h"
    static napi_value OhAVMetadataExtractorGetDuration(napi_env env, napi_callback_info info)
    {
    int64_t offset = 0;
    int32_t fileDescribe = -1;
    int64_t fileSize = 0;
    // 通过辅助函数,获取输入参数,实现见完整示例。
    if (!GetGetDurationParams(env, info, offset, fileDescribe, fileSize)) {
    return nullptr;
    }
    OH_AVMetadataExtractor* mainExtractor = OH_AVMetadataExtractor_Create();
    if (!mainExtractor) {
    napi_throw_error(env, "EFAILED", "Create metadata extractor failed");
    return nullptr;
    }
    OH_AVErrCode avErrCode = OH_AVMetadataExtractor_SetFDSource(mainExtractor, fileDescribe, offset, fileSize);
    if (avErrCode != AV_ERR_OK) {
    OH_AVMetadataExtractor_Release(mainExtractor);
    napi_throw_error(env, "EFAILED", "SetFDSource for metadata extractor failed");
    return nullptr;
    }
    OH_AVFormat* avMetadata = OH_AVFormat_Create();
    // 获取资源文件的元数据信息。
    avErrCode = OH_AVMetadataExtractor_FetchMetadata(mainExtractor, avMetadata);
    if (avErrCode != AV_ERR_OK) {
    OH_AVFormat_Destroy(avMetadata);
    OH_AVMetadataExtractor_Release(mainExtractor);
    napi_throw_error(env, "EFAILED", "Fetch metadata failed");
    return nullptr;
    }
    int64_t out;
    // 从元数据中获取资源文件的时长。
    if (!OH_AVFormat_GetLongValue(avMetadata, OH_AVMETADATA_EXTRACTOR_DURATION, &out)) {
    OH_AVFormat_Destroy(avMetadata);
    OH_AVMetadataExtractor_Release(mainExtractor);
    napi_throw_error(env, "EFAILED", "Get duration failed");
    return nullptr;
    }
    napi_value duration;
    napi_create_int64(env, out, &duration);
    OH_AVFormat_Destroy(avMetadata);
    OH_AVMetadataExtractor_Release(mainExtractor);
    return duration;
    }
  4. 获取指定时间的视频帧:调用OH_AVImageGenerator_FetchFrameByTime(),可以获取到一个OH_PixelmapNative对象,该对象可用于图片显示。

    使用完成需要调用OH_PixelmapNative_Release释放OH_PixelmapNative对象资源,详细使用方法请参阅Image_NativeModule

    #include "napi/native_api.h"
    #include <multimedia/image_framework/image/pixelmap_native.h>
    #include <multimedia/player_framework/avimage_generator.h>
    #include <multimedia/player_framework/avimage_generator_base.h>
    #include <multimedia/player_framework/native_averrors.h>

    // FetchFrameByTime的输入参数。
    struct FetchFrameParams {
    int64_t timeUs = 0; // 指定的时间(单位us)。
    int64_t offset = 0; // 媒体源在文件描述符中的偏移量。
    int32_t fileDescribe = -1; // 媒体文件描述符。
    int32_t fileSize = 0; // 媒体文件大小。
    int32_t options = OH_AVIMAGE_GENERATOR_QUERY_CLOSEST; // OH_AVIMAGE_GENERATOR_QUERY_CLOSEST表示选取离传入时间点最近的关键帧。
    };

    static napi_value OhAvImageGeneratorFetchFrameByTime(napi_env env, napi_callback_info info)
    {
    FetchFrameParams fetchFrameParams;
    // 通过辅助函数,获取输入参数,实现见完整示例。
    if (!GetFetchFrameByTimeParams(env, info, fetchFrameParams)) {
    return nullptr;
    }
    int64_t timeUs = fetchFrameParams.timeUs;
    int64_t offset = fetchFrameParams.offset;
    int32_t fileDescribe = fetchFrameParams.fileDescribe;
    int32_t fileSize = fetchFrameParams.fileSize;
    int32_t options = fetchFrameParams.options;
    // 创建OH_AVImageGenerator实例。
    OH_AVImageGenerator* generator = OH_AVImageGenerator_Create();
    // 异常处理。
    if (!generator) {
    napi_throw_error(env, "EFAILED", "Create generator failed");
    return nullptr;
    }
    // 设置视频资源的文件描述符。
    OH_AVErrCode avErrCode = OH_AVImageGenerator_SetFDSource(generator, fileDescribe, offset, fileSize);
    // 异常处理。
    if (avErrCode != AV_ERR_OK) {
    OH_AVImageGenerator_Release(generator);
    napi_throw_error(env, "EFAILED", "SetFDSource failed");
    return nullptr;
    }
    // 取指定时间的视频帧。
    OH_PixelmapNative* pixelMap = nullptr;
    avErrCode = OH_AVImageGenerator_FetchFrameByTime(generator, timeUs,
    (OH_AVImageGenerator_QueryOptions)options, &pixelMap);
    // 异常处理。
    if (avErrCode != AV_ERR_OK || !pixelMap) {
    OH_AVImageGenerator_Release(generator);
    napi_throw_error(env, "EFAILED", "FetchFrameByTime failed");
    return nullptr;
    }
    // 将nativePixelMap对象转换为PixelMapnapi对象。
    napi_value pixelmapNapi = nullptr;
    Image_ErrorCode errCode = OH_PixelmapNative_ConvertPixelmapNativeToNapi(env, pixelMap, &pixelmapNapi);
    // 释放OH_PixelmapNative资源。
    OH_PixelmapNative_Release(pixelMap);
    // 释放OH_AVImageGenerator资源。
    OH_AVImageGenerator_Release(generator);
    // 异常处理。
    if (errCode != IMAGE_SUCCESS) {
    napi_throw_error(env, "EFAILED", "Convert PixelMap failed");
    return nullptr;
    }
    return pixelmapNapi;
    }
  5. 释放资源:调用OH_AVImageGenerator_Release()销毁实例,释放资源。

    // 释放OH_AVImageGenerator资源。
    OH_AVImageGenerator_Release(generator);

运行示例工程

参考以下示例,获取一个视频指定时间的视频帧。

  1. 新建工程,下载完整示例工程,并将示例工程的资源复制到对应目录。

    AVImageGeneratorNDK
    entry/src/main/ets/
    └── pages
    └── Index.ets (获取缩略图界面)
    entry/src/main/
    ├── cpp
    │ ├── types
    │ │ └── libentry
    │ │ └── Index.d.ts (NDK函数对应的js映射)
    │ ├── CMakeLists.txt (CMake脚本)
    │ └── napi_init.cpp (NDK函数)
    └── resources
    ├── base
    │ ├── element
    │ │ ├── color.json
    │ │ ├── float.json
    │ │ └── string.json
    │ └── media

    └── rawfile
    └── H264_AAC.mp4 (视频资源)
  2. 编译新建工程并运行。