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

时间:2017-12-04 06:18:08

标签: android video android-ndk mediacodec

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

<?php
$str='a=123&b=456&Signature=aaaa/bbb+i8=&Satus=bbbb';
$new_string = str_replace('+', '.', $str);
parse_str($new_string,$old_string);
$signature = str_replace('.', '+', $old_string['Signature']);
?>

在其他地方,下面是我如何设置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);
}

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

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

我遇到的问题是,如果我将ImageReader配置为RGBA格式,则回调中的 image 总是为NULL:

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
    ...
}    

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

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

1 个答案:

答案 0 :(得分:0)

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

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

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