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

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

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

#### 开发步骤及注意事项

在 CMake 脚本中链接动态库。

target\_link\_libraries(entry PUBLIC libavimage\_generator.so libace\_napi.z.so)

使用[OH\_PixelmapNative\_ConvertPixelmapNativeToNapi()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-pixelmap-native-h#oh_pixelmapnative_convertpixelmapnativetonapi)接口将nativePixelMap对象转换为PixelMapnapi对象、[OH\_PixelmapNative\_Release()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-pixelmap-native-h#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()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avmetadata-extractor-h#oh_avmetadataextractor_fetchmetadata)获取媒体资源时长信息[OH\_AVMETADATA\_EXTRACTOR\_DURATION](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avmetadata-extractor-base-h#变量)，进而选择获取视频帧的时间。使用需引入如下头文件。

#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.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-h)、[avimage\_generator\_base.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-base-h)和[native\_averrors.h](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-averrors-h)头文件，使用获取视频帧相关API。

详细的API说明请参考[AVImageGenerator API参考](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimagegenerator)。

1.  使用[OH\_AVImageGenerator\_Create()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-h#oh_avimagegenerator_create)创建实例。
    
    #include <multimedia/player\_framework/avimage\_generator.h>
    // 创建OH\_AVImageGenerator实例。
    OH\_AVImageGenerator\* generator = OH\_AVImageGenerator\_Create();
    
2.  设置视频资源的文件描述符：调用[OH\_AVImageGenerator\_SetFDSource()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-h#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()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-h#oh_avimagegenerator_fetchframebytime)，可以获取到一个OH\_PixelmapNative对象，该对象可用于图片显示。
    
    使用完成需要调用OH\_PixelmapNative\_Release释放OH\_PixelmapNative对象资源，详细使用方法请参阅[Image\_NativeModule](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-pixelmap-native-h#oh_pixelmapnative_release)。
    
    #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()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-avimage-generator-h#oh_avimagegenerator_release)销毁实例，释放资源。
    
    // 释放OH\_AVImageGenerator资源。
    OH\_AVImageGenerator\_Release(generator);
    

#### 运行示例工程

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

1.  新建工程，下载[完整示例工程](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/DocsSample/Media/AVImageGenerator/AVImageGeneratorNDK)，并将示例工程的资源复制到对应目录。
    
    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.  编译新建工程并运行。