在前面我们学习和使用了AudioRecord、AudioTrack、Camera、 MediaExtractor、MediaMuxer API、MediaCodec。 学习和使用了上述的API之后,相信对Android系统的音视频处理有一定的经验和心得了。本文及后面的几篇文章做的事情就是将这些知识串联起来,做一些稍微复杂的事情。
我们需要做的事情就是:串联整个音视频录制流程,完成音视频的采集、编码、封包成 mp4 输出。
Android音视频采集的方法:预览用SurfaceView,视频采集用Camera类,音频采集用AudioRecord。
使用MediaCodec 类进行编码压缩,视频压缩为H.264,音频压缩为aac,使用MediaMuxer 将音视频合成为MP4。
在收集数据之前,对Camera设置一些参数,方便收集后进行数据处理:
Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewFormat(ImageFormat.NV21); parameters.setPreviewSize(1280, 720);
然后设置PreviewCallback:
camera.setPreviewCallback(this);
就可以获取到Camera的原始NV21数据:
onPreviewFrame(byte[] bytes, Camera camera)
在创建一个H264Encoder类,在里面进行编码操作,并将编码后的数据存储到文件:
new Thread(new Runnable() {
@Override public void run() {
isRuning = true; byte[] input = null; long pts = 0; long generateIndex = 0; while (isRuning) { if (yuv420Queue.size() > 0) {
input = yuv420Queue.poll(); byte[] yuv420sp = new byte[width * height * 3 / 2]; // 必须要转格式,否则录制的内容播放出来为绿屏 NV21ToNV12(input, yuv420sp, width, height);
input = yuv420sp;
} if (input != null) { try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers(); int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1); if (inputBufferIndex >= 0) {
pts = computePresentationTime(generateIndex);
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, System.currentTimeMillis(), 0);
generateIndex += 1;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC); while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData); if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_CODEC_CONFIG) {
configbyte = new byte[bufferInfo.size];
configbyte = outData;
} else if (bufferInfo.flags == MediaCodec.BUFFER_FLAG_SYNC_FRAME) { byte[] keyframe = new byte[bufferInfo.size + configbyte.length];
System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length);
System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length);
outputStream.write(keyframe, 0, keyframe.length);
} else {
outputStream.write(outData, 0, outData.length);
}
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);
}
} catch (Throwable t) {
t.printStackTrace();
}
} else { try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} // 停止编解码器并释放资源
try {
mediaCodec.stop();
mediaCodec.release();
} catch (Exception e) {
e.printStackTrace();
} // 关闭数据流
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
当结束编码的时候,需要将相关的资源释放掉:
// 停止编解码器并释放资源try {
mediaCodec.stop();
mediaCodec.release();
} catch (Exception e) {
e.printStackTrace();
}// 关闭数据流try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
此时,我们做到了将视频内容采集-->编码-->存储文件。但这个仅仅是对Android 音视频开发(四):使用 Camera API 采集视频数据的延伸,但是很有必要。因为在前面学习了如何采集音频,如何使用MediaCodec去处理音视频,如何使用MediaMuxer去混合音视频。
示例代码:https://github.com/renhui/AndroidRecorder/releases/tag/only_h264_video
下面我们在当前的的基础上继续完善,即将音视频采集并混合为音视频。
本文转载自网络,感谢原作者的分享,转载仅为分享干货知识,如有侵权欢迎联系作者进行删除处理。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/625/viewspace-2826175/ ,如需转载,请注明出处,否则将追究法律责任。