无法从本机 C++ 代码在 Android MediaCodec Image 对象上设置时间戳

问题描述 投票:0回答:1

我创建了一个队列来存储 cpp 中 ImageReader 中的图像。 在从 MediaCodec.getInputImage(index) 方法将排队项目复制到 Image 对象时,我面临着字节缓冲区已成功复制但未设置时间戳的问题。 没有抛出任何错误,所以我很困惑。

队列保存以下类的对象。

class YUV420 {
public:
    int width;
    int height;
    **long long timestampUs;**
    std::vector<YUVImagePlane> planes;

    YUV420(int width, int height, long long timestampUs)
            : width(width), height(height), timestampUs(timestampUs) {
        // Pre-allocate planes for Y, U, and V
        planes.emplace_back(width * height, 1, width);  // Y plane
        planes.emplace_back(width * height / 2, 2, width);  // U plane
        planes.emplace_back(width * height / 2, 2, width);  // V plane
    }

....

复制功能相关代码为:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_YuvUtils_copyToImage2(
        JNIEnv *env,
        jobject /* this */,
        jobject image  // The MediaCodec Image object from Kotlin)
) {
...
 YUV420 &yuvFrame = yuvQueue.dequeue();
 jclass imageClass = env->GetObjectClass(image);

 // Get the setTimestamp method ID
    jmethodID setTimestampMethodID = env->GetMethodID(imageClass, "setTimestamp", "(J)V");
    if (setTimestampMethodID == nullptr) {
        LOGE("setTimestamp method not found in Image class.");
        env->DeleteLocalRef(imageClass);
        return;
    }

    // Call the setTimestamp method
    env->CallVoidMethod(image, setTimestampMethodID, static_cast<jlong>(yuvFrame.timestampUs));

    // Check for exceptions
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();  // Print the exception to the log
        env->ExceptionClear();      // Clear the exception so the JNI call can proceed
        LOGE("Exception occurred while setting timestamp.");
    } else {
        LOGI("Timestamp set to %lld", yuvFrame.timestampUs);
    }

    // Verify the value by getting the current timestamp from the Image object
    jmethodID getTimestampMethodID = env->GetMethodID(imageClass, "getTimestamp", "()J");
    if (getTimestampMethodID == nullptr) {
        LOGE("getTimestamp method not found in Image class.");
    } else {
        jlong retrievedTimestamp = env->CallLongMethod(image, getTimestampMethodID);
        if (retrievedTimestamp == static_cast<jlong>(yuvFrame.timestampUs)) {
            LOGI("Timestamp verification succeeded.");
        } else {
            LOGE("Timestamp verification failed. Expected: %lld, but got: %lld",
                 yuvFrame.timestampUs, retrievedTimestamp);
        }
    }

//  planes will be copied below.... that part is working 

}

此代码日志的示例输出如下:

Timestamp set to 608659736453232

Timestamp verification failed. Expected: 608659736453232, but got: 0

你能告诉我我在这里做错了什么吗? 谢谢!

android c++ java-native-interface android-camera2 android-mediacodec
1个回答
0
投票

getInputBuffer(index)
返回一个可写缓冲区,我们用它来写入帧数据。

准备好后,我们需要将其排队到编码器

MediaCodec
,以便使用
queueInputBuffer
进行编码,这需要缓冲区元数据、时间戳和帧标志。

这是供您参考的完整(Java)版本:

获取输入缓冲区:

调用 getInputBuffer(index) 从编解码器获取可写缓冲区。您将原始帧数据(例如 YUV 数据)写入此缓冲区进行编码。

ByteBuffer inputBuffer = codec.getInputBuffer(index);
if (inputBuffer != null) {
    // Clear the buffer
    inputBuffer.clear();
    // Write frame data into the input buffer
    inputBuffer.put(frameData);
}

对输入缓冲区进行排队:

写入帧数据后,需要使用queueInputBuffer对缓冲区进行排队。您还将提供元数据,例如缓冲区索引、偏移量、帧数据的大小、时间戳和标志。

codec.queueInputBuffer(index, 0, frameData.length, presentationTimeUs, flags);
  • index:输入缓冲区的索引
  • 0:缓冲区中的偏移量,其中 数据开始(通常为 0)。
  • frameData.length:帧数据的大小 缓冲区。
  • presentationTimeUs:演示时间戳 微秒。它有助于在播放期间对帧进行排序。
  • flags:特定于帧的标志,例如 BUFFER_FLAG_END_OF_STREAM 或 BUFFER_FLAG_KEY_FRAME

您还需要发送流结束帧。

codec.queueInputBuffer(index, 0, frameData.length, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
© www.soinside.com 2019 - 2024. All rights reserved.