我创建了一个队列来存储 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
你能告诉我我在这里做错了什么吗? 谢谢!
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);
您还需要发送流结束帧。
codec.queueInputBuffer(index, 0, frameData.length, presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);