使用MediaCodec API通过C++将MP4文件解码为YUV格式完整例子
时间: 2024-04-05 09:35:47 浏览: 116
好的,以下是一个使用MediaCodec API通过C++将MP4文件解码为YUV格式的完整例子:
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <android/log.h>
#include <jni.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaExtractor.h>
#include <media/NdkMediaFormat.h>
#define LOG_TAG "MediaCodecDecode"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define TIMEOUT_US 1000
#define MAX_BUFFER_SIZE 1024 * 1024
extern "C" JNIEXPORT void JNICALL Java_com_example_mediacodecdecode_MainActivity_decode(JNIEnv *env, jobject obj, jstring path, jobject surface) {
// 将Java字符串转换为C字符串
const char *mp4_path = env->GetStringUTFChars(path, NULL);
// 打开媒体文件
int fd = open(mp4_path, O_RDONLY);
if (fd < 0) {
LOGE("open file failed, error:%s", strerror(errno));
return;
}
// 获取文件信息
struct stat file_info;
fstat(fd, &file_info);
// 分配文件缓冲区
uint8_t *file_buffer = (uint8_t *) malloc(file_info.st_size);
if (file_buffer == NULL) {
LOGE("malloc buffer failed");
return;
}
// 读取文件内容
int read_size = read(fd, file_buffer, file_info.st_size);
if (read_size < 0) {
LOGE("read file failed, error:%s", strerror(errno));
return;
}
// 初始化Extractor
AMediaExtractor *extractor = AMediaExtractor_new();
if (extractor == NULL) {
LOGE("create extractor failed");
return;
}
// 设置数据源
AMediaExtractor_setDataSource(
extractor, file_buffer, file_info.st_size);
// 获取媒体文件信息
int track_count = AMediaExtractor_getTrackCount(extractor);
LOGD("track count:%d", track_count);
int video_track_index = -1;
for (int i = 0; i < track_count; i++) {
AMediaFormat *media_format = AMediaExtractor_getTrackFormat(extractor, i);
const char *mime;
AMediaFormat_getString(media_format, AMEDIAFORMAT_KEY_MIME, &mime);
if (strncmp(mime, "video/", 6)) {
continue;
}
AMediaExtractor_selectTrack(extractor, i);
video_track_index = i;
break;
}
if (video_track_index == -1) {
LOGE("no video track found");
return;
}
// 创建解码器
AMediaCodec *codec = AMediaCodec_createDecoderByType("video/avc");
if (codec == NULL) {
LOGE("create codec failed");
return;
}
// 配置解码器
AMediaFormat *input_format = AMediaExtractor_getTrackFormat(extractor, video_track_index);
AMediaCodec_configure(codec, input_format, ANativeWindow_fromSurface(env, surface), NULL, 0);
// 启动解码器
AMediaCodec_start(codec);
// 循环读取数据
int output_buffer_index = -1;
while (true) {
ssize_t input_buffer_index = AMediaCodec_dequeueInputBuffer(codec, TIMEOUT_US);
if (input_buffer_index >= 0) {
size_t input_buffer_size;
uint8_t *input_buffer = AMediaCodec_getInputBuffer(codec, input_buffer_index, &input_buffer_size);
ssize_t sample_size = AMediaExtractor_readSampleData(extractor, input_buffer, input_buffer_size);
if (sample_size < 0) {
AMediaCodec_queueInputBuffer(codec, input_buffer_index, 0, 0, 0);
break;
}
AMediaCodec_queueInputBuffer(codec, input_buffer_index, 0, sample_size, AMediaExtractor_getSampleTime(extractor), 0);
AMediaExtractor_advance(extractor);
}
AMediaCodecBufferInfo buffer_info;
output_buffer_index = AMediaCodec_dequeueOutputBuffer(codec, &buffer_info, TIMEOUT_US);
if (output_buffer_index >= 0) {
AMediaCodec_releaseOutputBuffer(codec, output_buffer_index, true);
} else if (output_buffer_index == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
AMediaFormat *output_format = NULL;
output_format = AMediaCodec_getOutputFormat(codec);
LOGD("output format changed: %s", AMediaFormat_toString(output_format));
} else if (output_buffer_index == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
LOGD("no output buffer right now");
}
}
// 停止解码器
AMediaCodec_stop(codec);
AMediaCodec_delete(codec);
codec = NULL;
// 释放Extractor
AMediaExtractor_delete(extractor);
extractor = NULL;
// 释放文件缓冲区
free(file_buffer);
// 关闭文件
close(fd);
// 释放Java字符串
env->ReleaseStringUTFChars(path, mp4_path);
}
```
需要注意的是,这个例子只能解码视频文件中的第一个视频轨道,并且只能解码H.264格式的视频。在实际开发中,需要根据需求进行修改。
阅读全文