GITHUB:
https://github.com/chezi008/mp4muxer
如果数据由本机摄像头直接采集,建议使用MediaMuxer类去实现mp4的合成。如果是服务端传输过来的视频流可以使用mp4v2的方法实现mp4的合成。
####官方文档介绍:http://www.loverobots.cn/android-api/reference/android/media/MediaMuxer.html
MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);
// More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat()
// or MediaExtractor.getTrackFormat().
MediaFormat audioFormat = new MediaFormat(...);
MediaFormat videoFormat = new MediaFormat(...);
int audioTrackIndex = muxer.addTrack(audioFormat);
int videoTrackIndex = muxer.addTrack(videoFormat);
ByteBuffer inputBuffer = ByteBuffer.allocate(bufferSize);
boolean finished = false;
BufferInfo bufferInfo = new BufferInfo();
muxer.start();
while(!finished) {
// getInputBuffer() will fill the inputBuffer with one frame of encoded
// sample from either MediaCodec or MediaExtractor, set isAudioSample to
// true when the sample is audio data, set up all the fields of bufferInfo,
// and return true if there are no more samples.
finished = getInputBuffer(inputBuffer, isAudioSample, bufferInfo);
if (!finished) {
int currentTrackIndex = isAudioSample ? audioTrackIndex : videoTrackIndex;
muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);
}
};
muxer.stop();
muxer.release();
mMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
mVideoTrackIndex = mMuxer.addTrack(mediaFormat);
mAudioTrackIndex = mMuxer.addTrack(mediaFormat);
outputBuffer.position(bufferInfo.offset);
outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
mMuxer.writeSampleData(track, outputBuffer, bufferInfo);
mMuxer.stop();
mMuxer.release();
在结束的时候你可能会遇到几种异常:
//设置sps和pps 如果设置不正确会导致合成的mp4视频作为文件预览的时候,预览图片是黑色的
//视频进度条拖拽画面会出现绿色,以及块状现象
mediaformat.setByteBuffer("csd-0", mCSD0);
mediaformat.setByteBuffer("csd-1", mCSD1);
AAC参数:PCM在用编码器编码成AAC格式音频的时候,编码器会在自动设置参数。
当outIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED
我们可以获取到,MediaFormat format = mEnc.getOutputFormat(),
format就包含了CODEC_CONFIG。此时的format可直接作为addTrack()的参数使用。
switch (nalType & 0x1f) {
case H264Decoder.NAL_TYPE_I:
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
break;
}
long pts = System.nanoTime() / 1000;
直接使用当前时间戳会有问题,录制成的MP4总时间会很大。我使用一个相对时间,当前时间相对于开始的时间差。
bufferInfo.presentationTimeUs = System.nanoTime()/1000-startPts;
1. MediaFormat 可以在初始化编码器的时候获取
mediaformat = MediaFormat.createVideoFormat("video/avc", VIDEO_WIDTH, VIDEO_HEIGHT);
2. 写入数据时候的inputBuffer 和 bufferInfo 需要自己构造
Android在MediaMuxer和MediaCodec用例:https://www.cnblogs.com/hrhguanli/p/5043610.html
Grafika: https://github.com/google/grafika
HWEncoderExperiments:https://github.com/OnlyInAmerica/HWEncoderExperiments/tree/audioonly/HWEncoderExperiments/src/main/java/net/openwatch/hwencoderexperiments