MediaCodec通过C++将YUV格式编码成MP4视频代码例子
时间: 2024-03-17 15:41:06 浏览: 158
Android平台流媒体基础知识
以下是一个简单的例子,演示如何使用MediaCodec将YUV格式的视频编码为MP4格式:
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormat.h>
#define MAX_BUFFER_SIZE 1024 * 1024
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("Usage: %s <input.yuv> <output.mp4> <fps>\n", argv[0]);
return 0;
}
const char *input_file = argv[1];
const char *output_file = argv[2];
const int fps = atoi(argv[3]);
// 打开输入文件
int input_fd = open(input_file, O_RDONLY);
if (input_fd < 0) {
printf("Failed to open input file: %s\n", input_file);
return -1;
}
// 获取输入文件大小
struct stat input_stat;
if (fstat(input_fd, &input_stat) < 0) {
printf("Failed to get input file size.\n");
close(input_fd);
return -1;
}
// 映射输入文件
uint8_t *input_data = (uint8_t *)mmap(NULL, input_stat.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
if (input_data == MAP_FAILED) {
printf("Failed to mmap input file.\n");
close(input_fd);
return -1;
}
// 初始化输出文件
int output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (output_fd < 0) {
printf("Failed to open output file: %s\n", output_file);
munmap(input_data, input_stat.st_size);
close(input_fd);
return -1;
}
// 初始化编码器
AMediaCodec *codec = AMediaCodec_createEncoderByType("video/avc");
AMediaFormat *format = AMediaFormat_new();
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/avc");
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, 1920);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, 1080);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, fps);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, OMX_COLOR_FormatYUV420SemiPlanar);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 8000000);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1);
AMediaCodec_configure(codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
AMediaCodec_start(codec);
// 编码循环
uint8_t *input_buffer = NULL;
uint8_t *output_buffer = NULL;
size_t input_buffer_size = 0;
size_t output_buffer_size = 0;
AMediaCodecBufferInfo buffer_info;
ssize_t input_buffer_index = -1;
ssize_t output_buffer_index = -1;
size_t frame_size = input_stat.st_size / (fps * 10); // 每帧大小
size_t frame_index = 0;
size_t pos = 0;
while (true) {
// 获取输入缓冲区
input_buffer_index = AMediaCodec_dequeueInputBuffer(codec, 2000);
if (input_buffer_index >= 0) {
input_buffer = AMediaCodec_getInputBuffer(codec, input_buffer_index, &input_buffer_size);
if (input_buffer_size >= frame_size) {
memcpy(input_buffer, input_data + pos, frame_size);
AMediaCodec_queueInputBuffer(codec, input_buffer_index, 0, frame_size, frame_index * 1000000 / fps, 0);
pos += frame_size;
frame_index++;
}
}
// 获取输出缓冲区
output_buffer_index = AMediaCodec_dequeueOutputBuffer(codec, &buffer_info, 2000);
if (output_buffer_index >= 0) {
output_buffer = AMediaCodec_getOutputBuffer(codec, output_buffer_index, &output_buffer_size);
write(output_fd, output_buffer, buffer_info.size);
AMediaCodec_releaseOutputBuffer(codec, output_buffer_index, false);
}
// 结束条件
if (pos >= input_stat.st_size) {
break;
}
}
// 停止编码器
AMediaCodec_stop(codec);
AMediaCodec_delete(codec);
AMediaFormat_delete(format);
// 关闭文件
munmap(input_data, input_stat.st_size);
close(input_fd);
close(output_fd);
return 0;
}
```
在这个例子中,我们使用了以下的步骤:
1. 打开输入文件并获取文件大小。
2. 将输入文件映射到内存中。
3. 初始化输出文件。
4. 初始化编码器,并设置编码器的格式。
5. 进行编码循环,将YUV数据送给编码器。
6. 将编码输出写入到输出文件中。
7. 停止编码器并关闭文件。
需要注意的是,这个例子中的编码器设置了固定的宽度、高度、帧率、颜色格式、比特率和关键帧间隔。在实际应用中,这些参数可能需要根据具体的视频进行调整。
阅读全文