在前面咱们学习和使用了AudioRecord、AudioTrack、Camera、 MediaExtractor、MediaMuxer API、MediaCodec。 学习和使用了上述的API以后,相信对Android系统的音视频处理有必定的经验和心得了。本文及后面的几篇文章作的事情就是将这些知识串联起来,作一些稍微复杂的事情。git
1、流程分析
1.1 需求说明
咱们须要作的事情就是:串联整个音视频录制流程,完成音视频的采集、编码、封包成 mp4 输出。github
1.2 实现方式
Android音视频采集的方法:预览用SurfaceView,视频采集用Camera类,音频采集用AudioRecord。网络
1.3 数据处理思路
使用MediaCodec 类进行编码压缩,视频压缩为H.264,音频压缩为aac,使用MediaMuxer 将音视频合成为MP4。ide
2、 实现过程
2.1 收集Camera数据,并转码为H264存储到文件
在收集数据以前,对Camera设置一些参数,方便收集后进行数据处理:学习
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setPreviewSize(1280, 720);
而后设置PreviewCallback:ui
camera.setPreviewCallback(this);
就能够获取到Camera的原始NV21数据:this
onPreviewFrame(byte[] bytes, Camera camera)
在建立一个H264Encoder类,在里面进行编码操做,并将编码后的数据存储到文件:编码
复制代码
new Thread(new Runnable() {code
@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();
复制代码
当结束编码的时候,须要将相关的资源释放掉:orm
复制代码
// 中止编解码器并释放资源
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
下面咱们在当前的的基础上继续完善,即将音视频采集并混合为音视频。
2.2 音视频采集+混合,存储到文件
基本完成思路已经在2.1的结尾处坐了说明,下面贴一下demo的连接:
示例代码:https://github.com/renhui/AndroidRecorder/releases/tag/h264_video_audio
本文转载自网络,感谢原做者的分享,转载仅为分享干货知识,若有侵权欢迎联系做者进行删除处理。