在native层,通过AMediaCodec 和AMediaMuxer 使yuv420的数据编码成mp4文件demo
时间: 2024-03-09 19:49:33 浏览: 89
以下是使用 `AMediaCodec` 和 `AMediaMuxer` 将 YUV420 数据编码成 MP4 文件的示例代码:
```c++
#include <android/log.h>
#include <android/native_window_jni.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormat.h>
#include <media/NdkMediaMuxer.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define LOG_TAG "MediaCodecDemo"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define MIME_TYPE "video/avc"
#define BIT_RATE 2000000
#define FRAME_RATE 30
#define I_FRAME_INTERVAL 1
#define TIMEOUT_US 10000
void *encode_thread(void *arg);
bool is_encoding = false;
int main() {
pthread_t tid;
pthread_create(&tid, NULL, encode_thread, NULL);
sleep(10);
is_encoding = false;
pthread_join(tid, NULL);
return 0;
}
void *encode_thread(void *arg) {
// 初始化编码器
AMediaCodec *codec = AMediaCodec_createEncoderByType(MIME_TYPE);
AMediaFormat *format = AMediaFormat_new();
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, MIME_TYPE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, BIT_RATE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, FRAME_RATE);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, OMX_COLOR_FormatYUV420SemiPlanar);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, 640);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, 480);
AMediaCodec_configure(codec, format, NULL, NULL, AMEDIACODEC_CONFIGURE_FLAG_ENCODE);
AMediaCodec_start(codec);
// 初始化混合器
AMediaMuxer *muxer = AMediaMuxer_new("/sdcard/test.mp4", AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
AMediaCodecBufferInfo bufferInfo;
int32_t trackIndex = -1;
bool muxerStarted = false;
// YUV 数据
uint8_t *yuvData = (uint8_t *) malloc(640 * 480 * 3 / 2);
int64_t pts = 0;
is_encoding = true;
while (is_encoding) {
// 生成 YUV 数据
memset(yuvData, 0, 640 * 480 * 3 / 2);
// ...
// 获取输入缓冲区
ssize_t inputBufferIndex = AMediaCodec_dequeueInputBuffer(codec, TIMEOUT_US);
if (inputBufferIndex >= 0) {
// 填充输入缓冲区
size_t inputBufferSize;
uint8_t *inputBuffer = AMediaCodec_getInputBuffer(codec, inputBufferIndex, &inputBufferSize);
memcpy(inputBuffer, yuvData, 640 * 480 * 3 / 2);
AMediaCodec_queueInputBuffer(codec, inputBufferIndex, 0, 640 * 480 * 3 / 2, pts, 0);
pts += 1.0 / FRAME_RATE * 1000000;
// 获取输出缓冲区
ssize_t outputBufferIndex = AMediaCodec_dequeueOutputBuffer(codec, &bufferInfo, TIMEOUT_US);
if (outputBufferIndex >= 0) {
// 将输出缓冲区写入混合器
if (!muxerStarted) {
AMediaFormat *outputFormat = AMediaCodec_getOutputFormat(codec);
trackIndex = AMediaMuxer_addTrack(muxer, outputFormat);
AMediaMuxer_start(muxer);
muxerStarted = true;
}
size_t outputBufferSize;
uint8_t *outputBuffer = AMediaCodec_getOutputBuffer(codec, outputBufferIndex, &outputBufferSize);
AMediaMuxer_writeSampleData(muxer, trackIndex, outputBuffer, &bufferInfo);
AMediaCodec_releaseOutputBuffer(codec, outputBufferIndex, false);
} else if (outputBufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
// 输出格式变化
if (!muxerStarted) {
AMediaFormat *outputFormat = AMediaCodec_getOutputFormat(codec);
trackIndex = AMediaMuxer_addTrack(muxer, outputFormat);
AMediaMuxer_start(muxer);
muxerStarted = true;
}
}
}
}
// 释放资源
free(yuvData);
AMediaMuxer_stop(muxer);
AMediaMuxer_delete(muxer);
AMediaCodec_stop(codec);
AMediaCodec_delete(codec);
return NULL;
}
```
这段代码通过创建一个线程,在其中不断生成 YUV 数据,并将 YUV 数据传递给 `AMediaCodec` 进行编码。编码后的数据通过 `AMediaMuxer` 写入 MP4 文件中。在主线程中,控制编码的时间。在使用时,需要根据实际情况进行修改。
阅读全文