AMediaCodecBufferInfo info;
ssize_t index = AMediaCodec_dequeueOutputBuffer(ylMediaDecode->getAMediaCodec(), &info, 3000);
if (index >= 0) {
uint8_t *buffer = AMediaCodec_getOutputBuffer(ylMediaDecode->getAMediaCodec(), index, &outsize);
auto filename = "/storage/emulated/0/Android/data/com.xxx.xxx/files/test.yuv"
FILE fp_out = fopen(name.c_str(),"w+");
fwrite(buffer, 1, info.size,fp_out);
}
我使用android ndk AMediaCodec解码h265/h264数据,并尝试将获得的解码数据保存到test.yuv文件中。 但yuv文件无法用7yuv软件打开。 如何正确将解码后的数据保存为 yuv I420 文件?
不知道你这个问题是否已经解决, 如果还没有解决的话:我可以回答关于IT方面的问题,但是你没有提出具体的问题。请提供具体的问题,我会尽力给出解决方案。
AMediaCodecBufferInfo info;
ssize_t index = AMediaCodec_dequeueOutputBuffer(ylMediaDecode->getAMediaCodec(), &info, 3000);
if (index >= 0) {
uint8_t *buffer = AMediaCodec_getOutputBuffer(ylMediaDecode->getAMediaCodec(), index, &outsize);
auto filename = "/storage/emulated/0/Android/data/com.xxx.xxx/files/test.yuv";
FILE* fp_out = fopen(name.c_str(), "w"); // 使用文本模式打开文件
fwrite(buffer, 1, info.size, fp_out);
fclose(fp_out); // 关闭文件
}
找一下转换工具类
Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图片
可以参考下,非常详细
可以参考:
MediaCodec解码视频,得到YUV值,一帧一帧加载到SD卡中保存:https://blog.csdn.net/m0_60259116/article/details/126559530
或者这个:
MediaCodec 使用-- YUV打包成MP4:https://zhuanlan.zhihu.com/p/565416124?utm_id=0
用MediaCodec,可以解码
转换成mp4
每一次解答都是一次用心理解的过程,期望对你有所帮助。
参考结合AI智能库,如有帮助,恭请采纳。
以下是一个示例代码片段,演示了如何将解码数据保存为YUV I420格式的文件:
#include <iostream>
#include <fstream>
// 假设你已经获得了解码数据存储在buffer中,宽度和高度分别为width和height
void saveYUVToFile(const uint8_t* buffer, size_t size, int width, int height, const std::string& filename) {
FILE* fp_out = fopen(filename.c_str(), "wb");
if (!fp_out) {
std::cerr << "Failed to open file: " << filename << std::endl;
return;
}
// 写入YUV图像的宽度和高度
int64_t offset = 0;
fwrite(&offset, sizeof(int64_t), 1, fp_out);
offset += sizeof(int64_t) * 3; // 偏移量
// 写入Y分量数据
int ySize = width * height;
uint8_t* yData = new uint8_t[ySize];
memcpy(yData, buffer, ySize);
// 写入U分量数据
int uSize = width * height / 4;
uint8_t* uData = new uint8_t[uSize];
// TODO: 从buffer中提取U分量数据,并存储到uData中
// 写入V分量数据
int vSize = width * height / 4;
uint8_t* vData = new uint8_t[vSize];
// TODO: 从buffer中提取V分量数据,并存储到vData中
// 将YUV数据写入文件
fseek(fp_out, offset, SEEK_SET);
fwrite(yData, sizeof(uint8_t), ySize, fp_out);
offset += ySize;
fwrite(uData, sizeof(uint8_t), uSize, fp_out);
offset += uSize;
fwrite(vData, sizeof(uint8_t), vSize, fp_out);
fclose(fp_out);
delete[] yData;
delete[] uData;
delete[] vData;
}
#注释部分需要根据你的实际情况进行修改
使用 AMediaCodec 进行视频解码后,可以将输出的像素数据保存为 YUV 文件。
YUV 是一种常见的视频格式,它由 Y、U、V 三个分量构成。Y 表示亮度(明亮度),而 U、V 表示色度(色差)。其中,Y 分量的取值范围是 0255,而 U、V 分量的取值范围是 -128127。在保存为 YUV 文件时,通常需要先将每个分量的数据存储在不同的文件中,然后按照顺序将它们串联起来形成完整的 YUV 数据流。
下面是一个简单的示例代码,它演示了如何使用 AMediaCodec 将视频解码为 YUV 数据并保存到文件中:
// 创建解码器
MediaFormat format = MediaFormat.createVideoFormat("video/mp4v-es", 640, 480);
AMediaCodec codec = AMediaCodec.createDecoderByType("video/mp4v-es");
codec.configure(format, surface, null, 0);
codec.start();
// 循环解码视频帧
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
ByteBuffer[] inputBuffers = codec.getInputBuffers();
ByteBuffer[] outputBuffers = codec.getOutputBuffers();
boolean isEOS = false;
int frameCount = 0;
while (!Thread.interrupted()) {
if (!isEOS) {
int inputBufferIndex = codec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
int sampleSize = extractor.readSampleData(inputBuffer, 0);
if (sampleSize < 0) {
codec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
codec.queueInputBuffer(inputBufferIndex, 0, sampleSize, extractor.getSampleTime(), 0);
extractor.advance();
}
}
}
int outputBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 10000);
switch (outputBufferIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = codec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
MediaFormat newFormat = codec.getOutputFormat();
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] yuvData = new byte[640 * 480 * 3 / 2];
outputBuffer.get(yuvData);
saveYUVDataToFile(yuvData, frameCount);
frameCount++;
codec.releaseOutputBuffer(outputBufferIndex, true);
break;
}
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}
// 释放资源
codec.stop();
codec.release();
extractor.release();
在代码中,我们使用了 ByteBuffer
类型的数组来保存输入和输出的数据缓冲区,使用 MediaCodec.BufferInfo
类型的对象来保存输出缓冲区的相关信息。在每次解码完成后,我们将 YUV 数据保存到文件中。这里我们假设每一帧的数据大小为 640×480×3/2 字节(即一个 YUV 数据流中每 1 个像素占 1.5 个字节),并将它们依次写入文件中。
需要注意的是,由于 AMediaCodec 可能使用硬件加速来进行视频解码,因此在调用 releaseOutputBuffer
方法时需要指定第二个参数为 true,以便让解码器正确地处理输出缓冲区。另外,在保存 YUV 数据时,我们也需要指定正确的格式和顺序,以便后续的处理程序能够正确地读取和使用它们。
综上所述,使用 AMediaCodec 解码后的 YUV 数据可以通过简单的文件读写操作进行保存和后续处理。
AMediaCodec是Android提供的一种用于视频编解码的API,可以用来将视频文件进行解码处理后输出,其中输出的数据格式一般为YUV,即将RGB格式的像素数据转化为YUV格式的像素数据。因此,在使用AMediaCodec进行视频解码后,我们需要将输出的YUV格式数据保存下来以便后续使用。
以下是如何将AMediaCodec解码后的数据保存成YUV文件的步骤:
FILE *pFile = fopen(fileName, "wb"); // 打开文件
AMediaCodecBufferInfo info;
size_t outIndex = AMediaCodec_dequeueOutputBuffer(codec, &info, timeoutUs);
if (outIndex >= 0) {
// 获取输出缓冲区
AMediaCodecBuffer* outBuffer = AMediaCodec_getOutputBuffer(codec, outIndex);
// 写入数据到文件
fwrite(outBuffer->data, 1, info.size, pFile);
// 释放缓冲区
AMediaCodec_releaseOutputBuffer(codec, outIndex, false);
}
在上述代码中,我们首先从AMediaCodec中获取解码后的输出数据缓冲区,并获取到该缓冲区的大小信息。然后,我们使用fwrite函数将该缓冲区中的数据写入到指定的文件中。最后,我们通过AMediaCodec_releaseOutputBuffer函数释放该缓冲区。
注意:由于YUV格式的像素数据中每个像素占据多个字节,所以我们在写入数据时应该将每个像素的数据单独处理,具体操作方法如下:
因为YUV格式的像素数据不能直接进行图像处理,一般需要将其转化为RGBA格式的像素数据后再进行处理。可以使用如下代码将YUV像素数据转化为RGBA像素数据:
void yuvToRgb(unsigned char *yuvData, unsigned char *rgbData, int width, int height) {
for (int i = 0, j = 0; i < width * height * 3; i += 6, j += 4) {
int y0 = yuvData[j];
int u = yuvData[width * height + j / 2] - 128;
int y1 = yuvData[j + 1];
int v = yuvData[width * height + j / 2 + 1] - 128;
rgbData[i] = y0 + 1.13983f * v;
rgbData[i + 1] = y0 - 0.39465f * u - 0.58060f * v;
rgbData[i + 2] = y0 + 2.03211f * u;
rgbData[i + 3] = y1 + 1.13983f * v;
rgbData[i + 4] = y1 - 0.39465f * u - 0.58060f * v;
rgbData[i + 5] = y1 + 2.03211f * u;
}
}
在上述代码中,我们首先定义了两个数组变量分别用于存储YUV格式和RGBA格式的像素数据。然后,我们通过循环遍历每个像素,将其YUV数据转化为RGBA数据并存储到指定的数组中。
将RGBA格式的像素数据写入到文件中的代码与上面类似,只是在写入时需要将每个像素的数据单独处理。具体操作方法如下:
fwrite(rgbData, 1, width*height*3, pFile);
在上述代码中,我们首先定义了一个数组变量用于存储RGBA格式的像素数据。然后,我们使用fwrite函数将该数组中的数据单独写入到指定的文件中。
当我们将需要保存的数据全部写入到文件中后,需要使用fclose函数关闭文件指针,以确保文件保存成功。
fclose(pFile);
总的来说,将AMediaCodec解码后的数据保存成YUV文件只需要遵循如上所述的五个步骤即可。需要注意的是,在实际操作中,我们需要根据具体情况灵活运用上面的代码以达到最佳效果。