Android 音视频深入 四 录视频MP4(附源码下载)
本篇项目地址,名字是《录音视频(有的播放器不能放,而且没有时长显示)》,求star
https://github.com/979451341/Audio-and-video-learning-materials
1.MediaMuser说明
MediaMuser:将封装编码后的视频流和音频流到mp4容器中,说白了能够将音视频整合成一个MP4文件,MediaMuxer最多仅支持一个视频track和一个音频track,所以如果有多个音频track可以先把它们混合成为一个音频track然后再使用MediaMuxer封装到mp4容器中。
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();
2.录视频过程
我先贴个图,因为我觉得我后面会把自己绕晕,整理一下
先将Camera收集的数据显示在SurfaceView
surfaceHolder = surfaceView.getHolder();surfaceHolder.addCallback(this);@Overridepublic void surfaceCreated(SurfaceHolder surfaceHolder) {Log.w("MainActivity", "enter surfaceCreated method");// 目前设定的是,当surface创建后,就打开摄像头开始预览camera = Camera.open();try {camera.setPreviewDisplay(surfaceHolder);camera.startPreview();} catch (IOException e) {e.printStackTrace();}}
然后开始录视频,开启两个线程分别处理音视频数据
private void initMuxer() {muxerDatas = new Vector<>();fileSwapHelper = new FileUtils();audioThread = new AudioEncoderThread((new WeakReference<MediaMuxerThread>(this)));videoThread = new VideoEncoderThread(1920, 1080, new WeakReference<MediaMuxerThread>(this));audioThread.start();videoThread.start();try {readyStart();} catch (IOException e) {Log.e(TAG, "initMuxer 异常:" + e.toString());}}
将两个track加入MediaMuxer
mediaMuxer.writeSampleData(track, data.byteBuf, data.bufferInfo);
我们再来看看视频数据如何处理的
MediaCodec初始化和配置
mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE, this.mWidth, this.mHeight);mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);开启MediaCodecmMediaCodec = MediaCodec.createByCodecName(mCodecInfo.getName());mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);mMediaCodec.start();
然后SurfaceView传入视频数据数据导入
@Overridepublic void onPreviewFrame(byte[] bytes, Camera camera) {MediaMuxerThread.addVideoFrameData(bytes);}这个数据MediaMuxerThread又传给MediaThreadpublic void add(byte[] data) {if (frameBytes != null && isMuxerReady) {frameBytes.add(data);}}
然后循环从frameBytes里取数据
if (!frameBytes.isEmpty()) {byte[] bytes = this.frameBytes.remove(0);Log.e("ang-->", "解码视频数据:" + bytes.length);try {encodeFrame(bytes);} catch (Exception e) {Log.e(TAG, "解码视频(Video)数据 失败");e.printStackTrace();}
取出的数据哪去转换,也就是说mFrameData这个数据才是最后编码出视频
// 将原始的N21数据转为I420NV21toI420SemiPlanar(input, mFrameData, this.mWidth, this.mHeight);private static void NV21toI420SemiPlanar(byte[] nv21bytes, byte[] i420bytes, int width, int height) {System.arraycopy(nv21bytes, 0, i420bytes, 0, width * height);for (int i = width * height; i < nv21bytes.length; i += 2) {i420bytes[i] = nv21bytes[i + 1];i420bytes[i + 1] = nv21bytes[i];}}
MediaCodec获取数据从mFrameData
mMediaCodec.queueInputBuffer(inputBufferIndex, 0, mFrameData.length, System.nanoTime() / 1000, 0);
然后又拿出数据给muxer
mediaMuxer.addMuxerData(new MediaMuxerThread.MuxerData(MediaMuxerThread.TRACK_VIDEO, outputBuffer, mBufferInfo));
啊啊啊啊啊啊啊,疯了,代码可能看起来很糊,很多,但是绝大多数代码是为了协调为了判断当前还在录视频,但是真正的在录视频的代码的运行情况就是两条线,MediaCodec使用queueInputBuffer获取数据,然后进行编码dequeueOutputBuffer给MediaMuxer,AudioCodec也是一样的套路
源码地址在文章首部,各位多多研究,对了这个代码有问题,没有显示时长,有一些播放器不能用,手机自带应该没问题
转载于:https://www.cnblogs.com/jianpanwuzhe/p/8409064.html
Android 音视频深入 四 录视频MP4(附源码下载)相关推荐
- Android可滑动画板,Android实现画板、写字板功能(附源码下载)
前言 本文给大家分享一个使用Android开发写字板功能Dem.简单操作内存中的图像.对图像进行简单的处理.绘制直线.以达到写字板的效果 效果图如下 XML布局代码 xmlns:tools=" ...
- php写字板代码,Android实现画板、写字板功能(附源码下载)
前言 本文给大家分享一个使用Android开发写字板功能Dem.简单操作内存中的图像.对图像进行简单的处理.绘制直线.以达到写字板的效果 效果图如下 XML布局代码 xmlns:tools=" ...
- Android中Canvas绘图基础详解(附源码下载)
看到了一篇比较详细的Canvas文章,转过来方便自己查看. 源地址:http://blog.csdn.net/iispring/article/details/49770651 Android中,如果 ...
- android flv 编码器,Android 音视频深入 十七 FFmpeg 获取 RTMP 流保存为 flv (附源码下载)...
Android 音视频深入 十七 FFmpeg 获取 RTMP 流保存为 flv (附源码下载) 项目地址 https://github.com/979451341/RtmpSave 这个项目主要代码 ...
- 苹果CMSv10自适应视频高权重好看的简约模板源码下载
苹果CMSv10自适应视频高权重好看的简约模板源码下载 原创CSS框架样式库针对视频网站专做,无沉余代码大小仅几十kb,页面精简有序强化SEO,几十种页面可扩展,百余款模块组件任意搭配,可独立应用风格 ...
- Android悬浮窗开启 适配所有机型(附源码)
Android悬浮窗开启 适配所有机型(附源码) 1.开启悬浮窗权限 清单文件中添加: <uses-permission android:name="android.permissio ...
- wpf 模拟抖音很火的罗盘时钟,附源码,解压就能跑
wpf 模拟抖音很火的罗盘时钟,附源码,解压就能跑 前端时间突然发现,抖音火了个壁纸,就是黑底蕾丝~~~ 错错错,黑底白字的罗盘时钟! 作为程序员的我,也觉得很新颖,所以想空了研究下,这不,空下来了 ...
- wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑
wpf 模拟抖音很火的罗盘时钟,附源码 前端时间突然发现,抖音火了个壁纸,就是黑底蕾丝~~~ 错错错,黑底白字的罗盘时钟! 作为程序员的我,也觉得很新颖,所以想空了研究下,这不,空下来了就用wpf, ...
- 自带多平台解析接口短视频去水印图集水印微信小程序源码下载支持多流量主
这是一款支持多种平台去水印的一款微信小程序源码 支持短视频去水印,还有图集去水印等 内含多平台去水印接口,响应的速度也是非常的快 这是一款非常值得推荐的一款小程序源码 另外还支持多种流量主模式收益,大 ...
- Android 统一打包框架(附源码下载)
唠叨: 把手给我,我带你去吃云浮吃石磨肠粉.云吞面,木瓜渣. 那里的肠粉和广州的不一样,皮很薄很滑,肉馅没广州的那么花里胡哨,只有肉碎和香葱.但吃起来就很香滑,再配上它的甜辣酱.那味道好极了. 云吞面 ...
最新文章
- redis的分布式解决方式--codis (转)
- 一个html文档所需要的最基本的标记对是,川大《WEB技术》19秋在线作业1题目【标准答案】...
- 6月28日 cf总结
- 免安装版Tomcat6.0启动方法
- tableau必知必会之用 Fixed 函数实现客户回购分析
- c windows控制台输出颜色文字
- 实现EventHandler的监测
- REMarkerClusterer
- python开源考试_可能是 Python 中最火的第三方开源测试框架 pytest
- 超越MobileNet v3!华为诺亚、北大提出GhostNet​,使用线性变换生成特征图
- java 注解(annotation)基础学习
- SAP License:SAP复制和默认快捷小贴士
- vue父子组件间传值(props)
- 一图区分1.85mm/2.4mm/2.92mm/3.5mm/SMA射频接头
- 3GP转换器 Pro 3.5
- 亚马逊云科技-游戏孵化营第一课学习心得
- Unable to load DLL 'xxx.dll': 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)
- 【AICG】动漫女主AI绘图的学习笔记
- 大数据、Java、Python、区块链、人工智能前景简单对比
- WIN XP 开机正常,过了进度条之后黑屏