android - 获取 MediaCodec 解码器以 RGBA 格式提供视频帧

标签 android video android-ndk android-mediacodec

我正在尝试使用 MediaCodec 解码器(通过 NDK API)从 .mp4 文件中获取视频帧(用于进一步处理)。以下是设置解码器以呈现到表面(由 ImageReader 拥有)的示例代码:

// Omitting most error handling for clarity

AMediaExtractor* ex = AMediaExtractor_new();
media_status_t err = AMediaExtractor_setDataSourceFd(ex, fd /*opened previously*/, outStart, outLen);
close(fd);

int numtracks = AMediaExtractor_getTrackCount(ex);
AMediaCodec* decoder = NULL;

for (int i = 0; i < numtracks; i++) {
    AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
    const char *s = AMediaFormat_toString(format);
    LOGV("track %d format: %s", i, s);
    const char *mime;
    if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
        LOGV("no mime type");
        return JNI_FALSE;
    } else if (!strncmp(mime, "video/", 6)) {
        AMediaExtractor_selectTrack(ex, i);
        decoder = AMediaCodec_createDecoderByType(mime);

        AImageReader* imageReader;
        ANativeWindow* surface;

        // This setting doesn’t works
        media_status_t status = AImageReader_new(480, 360, AIMAGE_FORMAT_RGBA_8888, 1, &imageReader);

        // This setting works
        //media_status_t status = AImageReader_new(480, 360, AIMAGE_FORMAT_YUV_420_888, 1, &imageReader);

        status = AImageReader_getWindow(imageReader, &surface);

        // Configure the decoder to render to a surface
        AMediaCodec_configure(codec, format, surface, NULL, 0);

        AMediaCodec_start(codec);
    }

    AMediaFormat_delete(format);
}

在其他地方,下面是我如何为 ImageReader 设置回调:

AImageReader_ImageListener* imageListener = new AImageReader_ImageListener();
imageListener->onImageAvailable = &imageCallback;
AImageReader_setImageListener(imageReader, imageListener);

最后,下面是回调的样子:

void imageCallback(void *context, AImageReader *reader) {

    int32_t format;
    media_status_t status = AImageReader_getFormat (reader, &format);

    AImage* image;
    status = AImageReader_acquireLatestImage(reader, &image);

    status = AImage_getFormat(image, &format);

    // further processing to follow
    ...
}    

我一直面临的问题是,如果我用 RGBA 格式配置 ImageReader,回调中的 image 总是出现 NULL:

// Always NULL for ImageReader configured with RGBA
// OK for ImageReader configured with YUV_420_888
AImage* image;
status = AImageReader_acquireLatestImage(reader, &image);

我在这里正确使用了 NDK API 吗?我想提及的一件事是 RGBA 没有出现在通过以下 API 获取的解码器功能列表中(不是通过 NDK 提供,在 Java 层中尝试过):

 getCodecInfo().getCapabilitiesForType(…).colorFormats

最佳答案

视频解码器通常不支持以 RGB 格式输出(正如您在颜色格式编解码器信息中注意到的那样),所以这就是它不起作用的原因。

如果您使用表面纹理作为解码器的输出,则视频解码器输出可以透明地转换为 RGB - 然后解码后的视频数据可在 OpenGL 上下文中使用。如果您随后只是对表面纹理进行简单的 1:1 复制/渲染,并将 OpenGL 上下文设置为渲染到 ImageReader,我希望您能获得所需的 RGB 数据。

这有点迂回(而且我不确定在 native 代码上下文中访问所有 API 有多容易),但据我所知应该是可行的。

关于android - 获取 MediaCodec 解码器以 RGBA 格式提供视频帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47627544/

相关文章:

java - 如何将文本设置为来自另一个类的 Google map 当前位置

api - 如何通过 Facebook 的 Connect API 将视频发布到我的 Facebook 个人资料页面?

video - FFmpeg:合并具有不同开始时间的视频文件

video - ffmpeg 确定要使用的正确编解码器

android - 是否可以在 Android Studio 中调试 C/C++?

android-ndk - Android 原生代码在拇指模式下崩溃,但在 ARM 模式下不崩溃

android - Talkback - 为查看寻呼机滑动自定义辅助功能文本

Android-全屏视频查看

android - 从 ListView android 中删除重复项

android-ndk - 使用 FFMpeg 在 Android 客户端上进行 RTSP 流式传输