- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在使用 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/
我很难在 Jcodec 中获得正确的持续时间和准确的帧率。 我的情况是我有一个显示位图数组的应用程序,其中用户可以更改其帧速率,如 1fps、5fps、32fps,我所做的只是 1000/fps。所以
我正在尝试使用 jcodec 将缓冲图像编码为 h264 电影。只是我无法在任何地方找到示例代码。 过去有人用过这个库吗?我没有看到任何文档,甚至库附带的 javadoc 也没有包含任何使用信息。如果
我是 JCodec 的新手,但我正在尝试将 JCodec 图片转换为 BufferedImage。不幸的是,在 JCodec 中这样做的方法已被弃用,除了那些将图片转换为 Picture8Bit 的方
我正在尝试使用 JCodec 将一系列图像转换为 Java SE 桌面应用程序内的视频。我尝试过的几种方法都导致了 Windows Media Player 无法播放的视频。 我不清楚这是编解码器问题
我需要将多个图像(其中我有完整的路径)编码成android上某个FPS的视频。 试验: How to create a video from an array of images in Android
我需要从图像创建视频,我看过 jcodec,我认为这就是我需要的: http://jcodec.org/ 如何将 jcodec 添加到我的项目中?我看到有一个适用于android的版本。如果我错了请纠
过去 2 天我一直在尝试解决这个问题,但没有成功。我是 android 编程的初学者,我在我的项目中需要将一些图像转换为视频。我发现我可以为此使用 jcodec,但我无法安装它。如果有人可以告诉我如何
当我尝试使用 JCodec 将单个位图转换为 10 秒长的视频时 - 有时我会得到一个奇怪的结果,通常是颜色失真 - 或者在结果视频上绘制一条黑色对角线。这是我使用的代码(我调试了它,问题出现在那里)
我有一组图像,我想将幻灯片生成为视频文件。我正在使用 jcodec。当我对帧进行编码时,是否可以指定该帧必须显示一定时间(例如 1 秒)? 最佳答案 是的,可以指定帧的时间。在 https://git
我正在使用 JCODEC创建我的屏幕 Activity 的视频。我不想使用 android NDK,因为我想在 JAVA 中使用它。我正在运行一个 for 循环来使用 SequenceEncoder
我有一个使用 jcodec 生成的 MP4 文件。 然后我就有了一个使用 Android 的 MediaCodec 生成的 AAC 文件。 我想将它们混合到一个文件中,并且由于我不想将我的 Andro
我正在研究如何使用 Java 从图像创建 mp4 视频。经过几天的研究,我知道 JCodec 可以做到(http://jcodec.org/)。这是我在 Android make animated v
我在使用 MediaRecorder 和 Jcodec 在 Android 上编写 mp4 文件时遇到了一些麻烦,这是我的代码 public class SequenceEncoder { p
我正在尝试能够从 MPEG、MPEG-TS 和 MPEG-PS 文件以及实时流(网络/UDP/RTP 流)中挑选出帧(视频和元数据)。我正在研究使用 JCODEC 来执行此操作,我开始尝试使用 Fra
我想知道如何使用 jCodec 从 UDP 实时流中获取和解码 H.264 帧。我看到了如何从文件中获取它的示例,但我需要从实时流中获取它。我有接收直播流数据包的应用程序,但我需要知道如何解码数据包并
有没有人设法使用 Jcodec 保存 rtsp 视频流 (h264 mpeg) ? 你能举个例子吗? 在 Android 设备上保存 rtsp 流的任何其他方法也会有很大帮助。 请不要包含任何需要特定
我是一名优秀的程序员,十分优秀!