最近的项目中遇到一个非常头痛的需求,在android端录制视频的时候动态添加像监控画面一样的精确到秒的时间信息,关键是,并不是说只在播放器的界面显示时间就可以了,而是录制到视频里面去,这个MP4在电脑上播放也能看到每个画面的时间。
最后想到的办法是在录制完成以后去处理这个视频。期间参考了很多资料,比较有用的大概是ffmpeg和比较新的Api
mediaCodec系列了。介于ffmpeg都是C实现,和一大堆NDK相关,本人不是太懂,就重点关注了MediaCodec系列。
参考逻辑流程图一目了然的这篇博文
http://blog.csdn.net/xipiaoyouzi/article/details/37599759
MediaCodec进行编解码的大体逻辑是这样的(转载):
主要函数的调用逻辑如下:
MediaExtractor,MediaCodec,MediaMuxer这三个Api已经可以很多多媒体处理工作了,比如用MediaExtractor+MediaMuxer就可以做音视频剪辑,MediaCodec+MediaMuxer就可以做自定义的录像机,一起用就可以做特效编辑,滤镜之类的了。
添加时间水印效果
关键在于取到的数据帧,是YUV格式的,根据拍摄时选取的不同还不一样,我用到的NV21格式,也就是YUV420sp,拿到NV21格式的帧以后,转成RGB渲染,然后又转回NV21交给encoder,看起来好笨重,也非常地耗时,但我还没找到更好的办法。
private Bitmap first;
private void handleFrameData(byte[] data, MediaCodec.BufferInfo info) {
//YUV420sp转RGB数据 5-60ms
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, srcWidth, srcHeight, null);
yuvImage.compressToJpeg(new Rect(0, 0, srcWidth, srcHeight), 100, out);
byte[] imageBytes = out.toByteArray();
//旋转图像,顺便解决电脑上播放被旋转90度的问题 20-50ms
Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
Bitmap bitmap = rotaingImageView(videoRotation, image);
image.recycle();
//渲染文字 0-1ms
Canvas canvas = new Canvas(bitmap);
canvas.drawText(videoTimeFormat.format(videoFirstTime + info.presentationTimeUs / 1000), 10, 30, paint);
//预览处理帧 0-5ms
first = bitmap;
handler.sendEmptyMessage((int) (info.presentationTimeUs / 1000));
synchronized (MediaCodec.class) {
//记得加锁
timeDataContainer.add(