android - 设置 mediacodec 的呈现时间
android - setting presentation time of mediacodec
我使用下面的代码将原始数据编码为 h264 以创建视频,它的编码非常好,但视频播放速度太快。看来演示时间有问题。当记录开始时,我设置 "tstart" 的值并为每一帧计算当前时间与 tstart 的差异并将其传递给 queueinputbuffer 但没有任何改变。哪一部分有问题?我知道在 android 4.3 中我可以将表面传递给 mediacodec 但我想支持 android 4.1。提前致谢。
public void onPreviewFrame(final byte[] bytes, Camera camera) {
if (recording == true) {
long time = System.nanoTime();
time -= tstart;
if(mThread.isAlive()&&recording == true) {
encode(bytes, time );
}
}
}
private synchronized void encode(byte[] dataInput,long time)
{
byte[] data=new byte[dataInput.length];
NV21toYUV420Planar(dataInput,data,640,480);
inputBuffers = mMediaCodec.getInputBuffers();// here changes
outputBuffers = mMediaCodec.getOutputBuffers();
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(data);
time/=1000;
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, time, 0);
} else {
return;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
Log.i("tag", "outputBufferIndex-->" + outputBufferIndex);
do {
if (outputBufferIndex >= 0) {
ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outBuffer.get(outData);
try {
if (bufferInfo.offset != 0) {
fos.write(outData, bufferInfo.offset, outData.length
- bufferInfo.offset);
} else {
fos.write(outData, 0, outData.length);
}
fos.flush();
Log.i("camera", "out data -- > " + outData.length);
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,
0);
} catch (IOException e) {
e.printStackTrace();
}
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffers = mMediaCodec.getOutputBuffers();
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat format = mMediaCodec.getOutputFormat();
}
} while (outputBufferIndex >= 0);
}
您的问题是您没有将输出帧写入实际存储任何时间戳的容器中。您正在编写一个普通的 H264 文件,它只包含原始编码帧,没有索引,没有时间戳,没有音频,没有别的。
为了获得文件的正确时间戳,您需要使用MediaMuxer
(出现在4.3)或类似的第三方库(例如libavformat或类似的)将编码数据包写入文件.输出数据包的时间戳在 bufferInfo.presentationTime
中,而在 if (outputBufferIndex >= 0) {
子句中,您根本不使用它 - 您基本上是在丢弃时间戳。
我使用下面的代码将原始数据编码为 h264 以创建视频,它的编码非常好,但视频播放速度太快。看来演示时间有问题。当记录开始时,我设置 "tstart" 的值并为每一帧计算当前时间与 tstart 的差异并将其传递给 queueinputbuffer 但没有任何改变。哪一部分有问题?我知道在 android 4.3 中我可以将表面传递给 mediacodec 但我想支持 android 4.1。提前致谢。
public void onPreviewFrame(final byte[] bytes, Camera camera) {
if (recording == true) {
long time = System.nanoTime();
time -= tstart;
if(mThread.isAlive()&&recording == true) {
encode(bytes, time );
}
}
}
private synchronized void encode(byte[] dataInput,long time)
{
byte[] data=new byte[dataInput.length];
NV21toYUV420Planar(dataInput,data,640,480);
inputBuffers = mMediaCodec.getInputBuffers();// here changes
outputBuffers = mMediaCodec.getOutputBuffers();
int inputBufferIndex = mMediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(data);
time/=1000;
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, time, 0);
} else {
return;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0);
Log.i("tag", "outputBufferIndex-->" + outputBufferIndex);
do {
if (outputBufferIndex >= 0) {
ByteBuffer outBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outBuffer.get(outData);
try {
if (bufferInfo.offset != 0) {
fos.write(outData, bufferInfo.offset, outData.length
- bufferInfo.offset);
} else {
fos.write(outData, 0, outData.length);
}
fos.flush();
Log.i("camera", "out data -- > " + outData.length);
mMediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo,
0);
} catch (IOException e) {
e.printStackTrace();
}
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
outputBuffers = mMediaCodec.getOutputBuffers();
} else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat format = mMediaCodec.getOutputFormat();
}
} while (outputBufferIndex >= 0);
}
您的问题是您没有将输出帧写入实际存储任何时间戳的容器中。您正在编写一个普通的 H264 文件,它只包含原始编码帧,没有索引,没有时间戳,没有音频,没有别的。
为了获得文件的正确时间戳,您需要使用MediaMuxer
(出现在4.3)或类似的第三方库(例如libavformat或类似的)将编码数据包写入文件.输出数据包的时间戳在 bufferInfo.presentationTime
中,而在 if (outputBufferIndex >= 0) {
子句中,您根本不使用它 - 您基本上是在丢弃时间戳。