Android MediaRecorder录像
近期小编正在做类似于朋友圈的功能,调用系统录像,华为机10s中就录出来41M,上传就要30-40s,测试提出BUG,产品提出需优化,小编在风中凌乱,没做过啊,,,近期终于完成需求,梳理一下,方便以后看。
一. 软编码和硬编码如何区分
软编码:使用CPU进行编码
硬编码:使用非CPU进行编码,如显卡GPU、专用的DSP、FPGA、ASIC芯片等
二. 软编码和硬编码比较
软编码:实现直接、简单,参数调整方便,升级容易,但CPU负载重,性能较硬编码低,低码率下质量通常比硬编码要好一点
硬编码:性能高,低码率下通常质量低于硬编码器,但部分产品在GPU硬件平台移植了优秀的软编码算(如X264)等,质量基于等同于软编码
三. 目前主流GPU加速平台
Intel、AMD、NVIDIA
四. 目前主流GPU平台开发框架
CUDA: NVIDIA的封闭编程框架,通过框架可以调用GPU计算资源
AMD APP: AMD为自己的GPU提出的一套通用并行编程框架,标准放开,通过在CPU、GPU同事支持OpenCL框架,进行计算力融合
OpenCL:开放计算语言,为异构平台编写程序的该框架,异构平台可包含CPU、GPU以及其他计算处理器,木匾是使用相同的计算能支持不同平台硬件加速。
Intel QuickSync: 集成Intel显卡中的专用视频编解码模块。
五. Android实现视频编码——H.264硬编码 硬编码 软编码
硬编码:通过调用Android系统自带的Camera录制视频,实际上是调用了底层的高清编码硬件模块,也即显卡,不适用CPU,速度快
软编码:使用CPU进行编码,如常见C/C++代码,一般编译生成的二进制都是的,速度相对较慢。例如使用AndroidNDK编译H264生成so库,编写jni接口,再使用java调用so库。
软编流程:camera采集YUV数据==>滤镜==>x264编码器机型编码==>MP4打包合成
硬编流程:采用手机提供的硬板接口,利用硬件芯片直接进行编码合成。
优点:速度快、效率高、CPU占用极少,及时长时间高清录制也不会发烫,同事由于使用系统API,库相对较少。
缺点:某些奇葩记性需要处理兼容性问题,同事Android上的硬编跟Surface以及OpenGL关系比较密切,网上相关知识较少,需要自己摸索采坑。
硬编的主要流程如下图所示,可以看到所有的数据,聪采集、编码、显示以及合成都在GPU里面进行流转。
软编:FFmpeg
硬编:MediaCodec、MediaMuxer
六. 录制方案:
1. 使用系统自带的MediaRecorder
坑:
1) Android不同机型,屏幕尺寸不同,支持显示视频的分辨率也不同,在设置MediaRecorder的VideoSize和Profile时,如果手机不支持,就会崩溃,在SurfaceView显示,Camera设置PreviewSize设置不正确时,会出现变形。
2)前置摄像头,录像VideoSize和系统的屏幕比例基本不一致,会导致我们录出来的视频会有变形,另外就是左右镜像问题,其实也能理解,前置摄像头就和后置摄像头一样是对着录制的,而朋友圈录像估计是做了镜像处理,类似直播的API,貌似现在小视频都有做翻转的
2. Google grafika
3. FFmpeg
七. 代码
https://github.com/CarGuo/VideoRecord
录像不太清楚,因为分辨率写死了是640*480的,手机VideoSize都支持,但是由于现在屏幕分辨率较高,导致拍完之后都不太清楚,另外就是一些变形的状况
https://github.com/chenzhihui28/VideoRecorderAndCompressor
1. 切换摄像头的时候,CameraPreview类会执行refreshCamera方法,期间会调用optimizeCameraDimens方法,这个时候获取到的mCamera.getParameters().getSupportedPreviewSizes()明显发生了变化,
2. 另外就是横屏的处理,每次拿着手机横屏录像,录像完了之后旋转了90度,需要改动代码:设置屏幕方向为portrait,变换屏幕方向不进行重绘,在CameraActivity中preprareMediaRecorder方法,之前的判断屏幕方向就不需要了,判断rotationRecord,竖着放,mediaRecorder设置OrientationHint,前置摄像头270,后置90,横着放,前后设置为0,横倒着放设置180
if (rotationRecord == 90) {
mediaRecorder.setOrientationHint(cameraFront ? 270 : 90);
} else if (rotationRecord == 0) {
mediaRecorder.setOrientationHint(cameraFront ? 0 : 0);
} else if (rotationRecord == 180) {
mediaRecorder.setOrientationHint(cameraFront ? 180 : 180);
}
/**
* 旋转前置摄像头为正
*/
private void frontCameraRotate() {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
int degrees = getDisplayRotation(this);
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
frontOri = info.orientation;
frontRotate = result;
}
/**
* 获取旋转角度
*
* @param activity
* @return
*/
private int getDisplayRotation(Activity activity) {
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
/**
* 旋转界面UI
*/
private void rotationUIListener() {
orientationEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int rotation) {
if (!recording) {
if (((rotation >= 0) && (rotation <= 30)) || (rotation >= 330)) {
// 竖屏拍摄
if (rotationFlag != 0) {
//旋转logo
rotationAnimation(rotationFlag, 0);
//这是竖屏视频需要的角度
rotationRecord = 90;
//这是记录当前角度的flag
rotationFlag = 0;
}
} else if (((rotation >= 230) && (rotation <= 310))) {
// 横屏拍摄
if (rotationFlag != 90) {
//旋转logo
rotationAnimation(rotationFlag, 90);
//这是正横屏视频需要的角度
rotationRecord = 0;
//这是记录当前角度的flag
rotationFlag = 90;
}
} else if (rotation > 30 && rotation < 95) {
// 反横屏拍摄
if (rotationFlag != 270) {
//旋转logo
rotationAnimation(rotationFlag, 270);
//这是反横屏视频需要的角度
rotationRecord = 180;
//这是记录当前角度的flag
rotationFlag = 270;
}
}
}
}
};
orientationEventListener.enable();
}
private void rotationAnimation(int from, int to) {
ValueAnimator progressAnimator = ValueAnimator.ofInt(from, to);
progressAnimator.setDuration(300);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentAngle = (int) animation.getAnimatedValue();
buttonFlash.setRotation(currentAngle);
textChrono.setRotation(currentAngle);
buttonChangeCamera.setRotation(currentAngle);
}
});
progressAnimator.start();
}
3. 后置摄像头,我们可以采用最接近手机屏幕比例的,这样拍出来不会产生变形,CameraPreivew获取到ratio之后,获取摄像头参数的getSupportedVideoSizes(),选择最接近比例的,保存起来,在CameraActivity中获取,MediaRecorder参数设置:
Camera.Size videoSize = mPreview.getVideoSize();
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setVideoFrameRate(15);
mediaRecorder.setVideoSize(videoSize.width, videoSize.height);
mediaRecorder.setVideoEncodingBitRate(3 * videoSize.width / 2 * videoSize.height / 2);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setMaxDuration(10 * 1000);
注意:设置编码setAudioEncorder和setVideoEncoder方法需放置在其他设置之后,比如放在设置帧率之前,会报错
4. 前置摄像头暂时没有找到好的解决方案,因为屏幕比例获取到之后,在获取摄像头getSupportedVideoList()时,能得到的一些尺寸设置会出问题,只能选择demo中720P和480P,但是依旧有变形和镜像问题,还需好好研究。
Android MediaRecorder录像相关推荐
- Android MediaRecorder录像插耳机无法录取声音, 依然用的设备麦克风而非耳机. 解决
干货: MediaRecorder.AudioSource.CAMCORDER -- 无论插不插耳机, 都用设备的话筒; MediaRecorder.AudioSource.MIC-- 有耳机就用 ...
- 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 初始化
MediaRecorder 用于录制音频和视频,录制控制基于一个简单的状态机.下面是典型的使用 camera2 API 录制,需要使用到的 MediaRecorder API. MediaRecord ...
- 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 配置
MediaRecorder 录像配置主要涉及输出文件路径.音频来源.视频来源.输出格式.音频编码格式.视频编码格式.比特率.帧率和视频尺寸等. 我们假设视频输入源来自 Camera,Camera2 A ...
- Android MediaRecorder架构详解
1. 简介 在android中录制音频有两种方式,MediaRecorder和AudioRecord.两者的区别如下: (1) MediaRecorder 简单方便,不需要理会中间录制过程,结束录制后 ...
- Android MediaRecorder自定义分辨率
Android MediaRecorder自定义分辨率 工作这么久了,确实积累了不少东西,但都是以文档的形式存在U盘里的,为什么不写博客呢?因为懒啊!!!总感觉博客太难写了(大概是上学时候写作文恐惧症 ...
- MediaRecorder录像怎么旋转呀?
============问题描述============ 最近做的项目摄像头是跟手机按90度安装的,用MediaRecorder录像还是按摄像头的方向而不是手机的方向,录出来的是90度旋转的,试了很多 ...
- Android拍照录像框架Camera2使用简介
Android拍照录像框架Camera2使用简介 在Android 21时Google更新了以往的摄像头类库Camera,取而代之的是Camera2.作为更新版本,Camera2具有更强功能的同时也增 ...
- [Android][MediaRecorder] Android MediaRecorder框架简洁梳理
Android MediaRecorder框架简洁梳理 一.MediaRecorder整体架构 1.1 MediaRecorder录制数据流框架 1.2 PersistentSurface及Graph ...
- Android后台录像
最近因工作需求,要开发Android后台录像的功能,鉴于功能太邪恶,就不公开源码了,我们主要用于记录出租车行驶过程中的数据.提供开发思路: 1. 难点:后台一直运行(service或thread): ...
最新文章
- Centos7 yum安装Python3.6环境,超简单
- 1452.接水问题(思维)
- javascript理论篇(详情见地址)
- error code 0x80131022什么意思_page fault时发生了什么
- 电脑休眠跟睡眠的区别
- searchIndexer.exe占用过高CPU
- Java 自动装箱与拆箱(Autoboxing and unboxing)
- APACHE配置文件中文版 httpd.conf FOR Apache 2.2.4
- 卧槽!Intellij IDEA中竟然有这么多炫酷的插件,啪啪啪~
- 汉化风暴 python_手机端强大的汉化风暴工具 可汉化软件
- 路由器手机测试网速的软件,4个实用的无线路由器WiFi检测工具,让你网速又快又稳定...
- Python Numpy random.zipf() Zipf分布
- 大数据可视化平台Demo
- unity屏幕分辨率设置注意及代码
- mysql 查询优化实验报告_数据库优化查询实验报告.docx
- (附源码)小程序 酒店疫情系统 毕业设计 091931
- 在线客服系统|物流行业解决方案——助力企业构建物流行业新一体化模式
- 用python绘制熊猫图案_在python中绘制熊猫系列的CDF
- 源代码电影涉及的计算机思想,电影《源代码》你看懂了吗?
- PL2303输出的是TTL电平,为什么所有资料都说这个芯片是USB转RS232的??