gpt4 book ai didi

android - 使用 Jcodec 在 Android 上创建 mp4 文件

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:08:57 24 4
gpt4 key购买 nike

我在使用 MediaRecorder 和 Jcodec 在 Android 上编写 mp4 文件时遇到了一些麻烦,这是我的代码

public class SequenceEncoder {
private final static String CLASSTAG = SequenceEncoder.class.getSimpleName();

private SeekableByteChannel ch;

private byte[] yuv = null;

private ArrayList<ByteBuffer> spsList;
private ArrayList<ByteBuffer> ppsList;

private CompressedTrack outTrack;

private int frameNo;
private MP4Muxer muxer;

ArrayList<ByteBuffer> spsListTmp = new ArrayList<ByteBuffer>();
ArrayList<ByteBuffer> ppsListTmp = new ArrayList<ByteBuffer>();

// Encoder
private MediaCodec mediaCodec = null;

public SequenceEncoder(File out) throws IOException {
this.ch = NIOUtils.writableFileChannel(out);

// Muxer that will store the encoded frames
muxer = new MP4Muxer(ch, Brand.MP4);

// Add video track to muxer
outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25);

// Encoder extra data ( SPS, PPS ) to be stored in a special place of
// MP4
spsList = new ArrayList<ByteBuffer>();
ppsList = new ArrayList<ByteBuffer>();
}

@SuppressWarnings("unchecked")
public void encodeImage(ByteBuffer buffer, int width, int height) throws IOException {
if (yuv == null) {
int bufferSize = width * height * 3 / 2;

yuv = new byte[bufferSize];

int bitRate = bufferSize;
int frameRate = 25;
String mimeType = "video/avc";

// "video/avc"
mediaCodec = MediaCodec.createEncoderByType(mimeType);
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mimeType, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); // 125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);

mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}

byte[] rgba = buffer.array();

// Convert RGBA image to NV12 (YUV420SemiPlanar)
Rgba2Yuv420.convert(rgba, yuv, width, height);

synchronized (mediaCodec) {
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();

int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(yuv);
mediaCodec.queueInputBuffer(inputBufferIndex, 0,
yuv.length, 0, 0);
}

MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(
bufferInfo, 0);

while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);

ByteBuffer frameBuffer = ByteBuffer.wrap(outData);

spsListTmp.clear();
ppsListTmp.clear();

H264Utils.encodeMOVPacket(frameBuffer, spsListTmp, ppsListTmp);

if (!spsListTmp.isEmpty())
spsList = (ArrayList<ByteBuffer>) spsListTmp.clone();
if (!ppsListTmp.isEmpty())
ppsList = (ArrayList<ByteBuffer>) ppsListTmp.clone();

outTrack.addFrame(new MP4Packet(frameBuffer, frameNo, 25, 1,
frameNo, true, null, frameNo, 0));

frameNo++;

mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(
bufferInfo, 0);
}

if (outputBufferIndex < 0)
switch (outputBufferIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = mediaCodec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
break;
}
} catch (Exception e) {
}
}
}

public void finish() throws IOException {
if (!ch.isOpen())
return;

if (mediaCodec != null) {
mediaCodec.stop();
mediaCodec.release();
}

outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));

// Write MP4 header and finalize recording
muxer.writeHeader();
NIOUtils.closeQuietly(ch);

ch.close();
}
}

我们可以看到 Android MediaCodec 期望 YUV420SemiPlanar 作为输入图像,所以我给他正确的。结果我有一个带有无效颜色的损坏的 mp4 文件,当我从 AVCon 打开这个 mp4 文件时,我看到输出文件中的颜色格式是 yuv420p,所以这可能是问题所在?请建议如何解决此问题。

还有一个问题,如何将压缩后的音频流添加到muxer,没找到例子。

最佳答案

Android 4.3 (API 18) 有两个可能有用的新功能。

首先,MediaCodec 类接受来自 Surface 的输入,因此可以记录任何可以解码到 Surface 或使用 OpenGL ES 渲染的内容,而无需摆弄 YUV 颜色平面。

二、新MediaMuxer类提供了一种将音频和 H.264 视频合并到 .mp4 文件中的方法。

可以找到示例源代码(主要用于视频方面)here .

关于android - 使用 Jcodec 在 Android 上创建 mp4 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16789037/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com