【问题标题】:Access crop bounds for decoded video using NDK MediaCodec使用 NDK MediaCodec 访问解码视频的裁剪范围
【发布时间】:2018-01-19 02:30:55
【问题描述】:

我正在尝试通过 NDK 的 MediaCodec API 读取裁剪范围。

我正在读取如下值:

AMediaFormat* fmt = initialized();
if (AMediaFormat_getInt32(fmt, "crop-left", &cropLeft)) {
    LOGI("crop-left: %d", cropLeft);
}

但是,我无法读取我尝试过的各种视频的cropLeft 值。我尝试在第一帧之后读取它,并且一旦检测到格式更改。

我看到vlc code base 中使用了类似的代码。

在这里寻找可能存在的问题。

【问题讨论】:

    标签: android-ndk android-mediacodec


    【解决方案1】:

    目前还无法读取裁剪值。 在引擎盖下,AMediaFormat 包含一个消息结构 (AMessage),它由 stagefright 发送,其中包含所有裁剪值。裁剪值是特殊类型的 Rect,除了 AMediaFormat 中已经定义的方法(int32、int64、字符串、缓冲区)之外,还需要一个新的读取方法。 不幸的是, Rect 类型甚至没有被 AMediaFormat_toString 方法处理。我们可以看到作物值的输出为“crop: unknown(9)”。

    更新:

    这是我在装有 Android 7.0 的 Galaxy S6 上使用的一个丑陋的 hack。 它不能用于生产代码。它仅用于测试和演示。它会在其他 Android 版本和供应商手机上崩溃。 预计结构会在其他 Android 版本中发生变化,因此需要修复偏移量、填充和其他值。 无论如何,AMediaFormat 是一个结构,它有一个指向 AMessage 的指针。预计这是在前 4 个字节中。 AMessage 是 RefBase 的子类,使用 mainoffset[24] 我们将一些字节向前步进到 AMessage 类中的 Items 数组。我们期望 Items 结构的大小为 32 字节,并且它有一个指向“crop”字符串的 char 指针。当我们找到裁剪项目时,我们可以读出裁剪值。

    AMediaFormat* format = AMediaCodec_getOutputFormat(_codec);
    
    typedef struct {
     char mainoffset[24];
     struct {
      char itemoffset[8];
      int32_t cropLeft;
      int32_t cropTop;
      int32_t cropRight;
      int32_t cropBottom;
      unsigned char* name;
      char padding[4];
     }items[64];
    }AMessage;
    
    AMessage* amessage = *((AMessage**)format);
    
    int n = 0;
    while ( amessage->items[n].name ) {
     if ( !strcmp((const char*)amessage->items[n].name, "crop") ) {
      int32_t width = amessage->items[n].cropRight - amessage->items[n].cropLeft + 1;
      int32_t height = amessage->items[n].cropBottom - amessage->items[n].cropTop + 1;
      __android_log_print(ANDROID_LOG_VERBOSE, "FORMAT", "width=%d height=%d", width, height);
      break;
     }    
     n++;
    }
    

    【讨论】:

    【解决方案2】:

    您没有在代码中说出initialized() 是什么。请记住,实际输出MediaFormat 不能立即获得,但是当您从解码器返回INFO_OUTPUT_FORMAT_CHANGED 时,您应该使用MediaCodec.getOutputFormat() 获得它。您无法事先获取MediaFormat 对象并在获得该返回值时从旧对象中读取,您需要再次调用getOutputFormat()

    【讨论】:

    • 抱歉不清楚。在获得格式更改后,我确实调用了解析裁剪值的函数。部分代码如下所示:.... else if (bufId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {... AMediaFormat* format = AMediaCodec_getOutputFormat(track.codec); getRawImageInfo(format, _rawImageInfo);..。但是,我使用原始格式进行编解码器配置,并在调用 getRawImageInfo 后实际上破坏了新格式。还应该做些什么吗?
    猜你喜欢
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    相关资源
    最近更新 更多