Android 使用c++中的MediaCodec解码的完整代码,注意不要使用NdkMediaCodec
时间: 2024-04-02 20:34:25 浏览: 280
以下是使用C++中的MediaCodec解码的Android完整代码示例:
```c++
#include <jni.h>
#include <android/log.h>
#include <android/native_window_jni.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaExtractor.h>
#define LOG_TAG "MediaCodec"
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__))
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediadecoder_MainActivity_playMedia(JNIEnv* env, jobject obj, jstring path, jobject surface)
{
const char* filePath = env->GetStringUTFChars(path, nullptr);
ANativeWindow* window = ANativeWindow_fromSurface(env, surface);
AMediaExtractor* extractor = AMediaExtractor_new();
media_status_t status = AMediaExtractor_setDataSource(extractor, filePath);
if (status != AMEDIA_OK) {
LOGW("Failed to set data source: %d", status);
return;
}
int32_t trackCount = AMediaExtractor_getTrackCount(extractor);
AMediaCodec* codec = nullptr;
AMediaFormat* format = nullptr;
ssize_t trackIndex = -1;
for (int32_t i = 0; i < trackCount; ++i) {
AMediaFormat* trackFormat = AMediaExtractor_getTrackFormat(extractor, i);
const char* mime = nullptr;
AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
if (strncmp(mime, "video/", 6) == 0) {
trackIndex = i;
format = trackFormat;
break;
}
AMediaFormat_delete(trackFormat);
}
if (trackIndex != -1) {
AMediaExtractor_selectTrack(extractor, trackIndex);
codec = AMediaCodec_createDecoderByType(format);
AMediaCodec_configure(codec, format, window, nullptr, 0);
AMediaCodec_start(codec);
int64_t timeoutUs = 10000;
AMediaCodecBufferInfo bufferInfo = {0};
ssize_t sampleSize = 0;
while ((sampleSize = AMediaExtractor_readSampleData(extractor, AMediaCodec_getInputBuffer(codec, 0), 0)) >= 0) {
uint8_t* data = nullptr;
size_t size = 0;
AMediaCodecBufferInfo info = {0};
ssize_t index = AMediaCodec_dequeueInputBuffer(codec, timeoutUs);
if (index >= 0) {
auto inputBuffer = AMediaCodec_getInputBuffer(codec, index);
if (inputBuffer != nullptr) {
data = AMediaExtractor_getBuffer(extractor);
size = AMediaExtractor_getSampleSize(extractor);
info.offset = 0;
info.size = size;
info.presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
info.flags = AMediaExtractor_getSampleFlags(extractor);
memcpy(data, inputBuffer, size);
AMediaCodec_queueInputBuffer(codec, index, 0, size, info.presentationTimeUs, info.flags);
AMediaExtractor_advance(extractor);
}
}
ssize_t outIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, timeoutUs);
if (outIndex >= 0) {
auto outputBuffer = AMediaCodec_getOutputBuffer(codec, outIndex);
if (outputBuffer != nullptr) {
AMediaCodec_releaseOutputBuffer(codec, outIndex, true);
}
}
}
AMediaCodec_stop(codec);
AMediaCodec_delete(codec);
}
AMediaExtractor_delete(extractor);
ANativeWindow_release(window);
env->ReleaseStringUTFChars(path, filePath);
}
```
这段代码通过使用Android NDK的MediaCodec和MediaExtractor类来读取视频文件并将其渲染到给定的Surface上。在代码中,先使用AMediaExtractor_setDataSource()函数来设置数据源,然后扫描所有的轨道,找到视频轨道并选择它。接下来,使用AMediaCodec_createDecoderByType()函数创建解码器,然后使用AMediaCodec_configure()函数配置解码器并启动它。之后,使用AMediaCodec_getInputBuffer()函数获取解码器的输入缓冲区,并使用AMediaExtractor_readSampleData()函数从媒体文件中读取样本数据并将其复制到解码器的输入缓冲区中。最后,使用AMediaCodec_dequeueOutputBuffer()函数获取解码器的输出缓冲区,并使用ANativeWindow_lock()函数将视频帧渲染到给定的Surface上。
注意:以上代码仅为示例代码,并未在实际项目中测试过,可能存在bug和不足之处。
阅读全文