近期小编正在做类似于朋友圈的功能,调用系统录像,华为机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录像相关推荐

  1. Android MediaRecorder录像插耳机无法录取声音, 依然用的设备麦克风而非耳机. 解决

    干货: MediaRecorder.AudioSource.CAMCORDER   -- 无论插不插耳机, 都用设备的话筒; MediaRecorder.AudioSource.MIC-- 有耳机就用 ...

  2. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 初始化

    MediaRecorder 用于录制音频和视频,录制控制基于一个简单的状态机.下面是典型的使用 camera2 API 录制,需要使用到的 MediaRecorder API. MediaRecord ...

  3. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 配置

    MediaRecorder 录像配置主要涉及输出文件路径.音频来源.视频来源.输出格式.音频编码格式.视频编码格式.比特率.帧率和视频尺寸等. 我们假设视频输入源来自 Camera,Camera2 A ...

  4. Android MediaRecorder架构详解

    1. 简介 在android中录制音频有两种方式,MediaRecorder和AudioRecord.两者的区别如下: (1) MediaRecorder 简单方便,不需要理会中间录制过程,结束录制后 ...

  5. Android MediaRecorder自定义分辨率

    Android MediaRecorder自定义分辨率 工作这么久了,确实积累了不少东西,但都是以文档的形式存在U盘里的,为什么不写博客呢?因为懒啊!!!总感觉博客太难写了(大概是上学时候写作文恐惧症 ...

  6. MediaRecorder录像怎么旋转呀?

    ============问题描述============ 最近做的项目摄像头是跟手机按90度安装的,用MediaRecorder录像还是按摄像头的方向而不是手机的方向,录出来的是90度旋转的,试了很多 ...

  7. Android拍照录像框架Camera2使用简介

    Android拍照录像框架Camera2使用简介 在Android 21时Google更新了以往的摄像头类库Camera,取而代之的是Camera2.作为更新版本,Camera2具有更强功能的同时也增 ...

  8. [Android][MediaRecorder] Android MediaRecorder框架简洁梳理

    Android MediaRecorder框架简洁梳理 一.MediaRecorder整体架构 1.1 MediaRecorder录制数据流框架 1.2 PersistentSurface及Graph ...

  9. Android后台录像

    最近因工作需求,要开发Android后台录像的功能,鉴于功能太邪恶,就不公开源码了,我们主要用于记录出租车行驶过程中的数据.提供开发思路: 1.  难点:后台一直运行(service或thread): ...

最新文章

  1. Centos7 yum安装Python3.6环境,超简单
  2. 1452.接水问题(思维)
  3. javascript理论篇(详情见地址)
  4. error code 0x80131022什么意思_page fault时发生了什么
  5. 电脑休眠跟睡眠的区别
  6. searchIndexer.exe占用过高CPU
  7. Java 自动装箱与拆箱(Autoboxing and unboxing)
  8. APACHE配置文件中文版 httpd.conf FOR Apache 2.2.4
  9. 卧槽!Intellij IDEA中竟然有这么多炫酷的插件,啪啪啪~
  10. 汉化风暴 python_手机端强大的汉化风暴工具 可汉化软件
  11. 路由器手机测试网速的软件,4个实用的无线路由器WiFi检测工具,让你网速又快又稳定...
  12. Python Numpy random.zipf() Zipf分布
  13. 大数据可视化平台Demo
  14. unity屏幕分辨率设置注意及代码
  15. mysql 查询优化实验报告_数据库优化查询实验报告.docx
  16. (附源码)小程序 酒店疫情系统 毕业设计 091931
  17. 在线客服系统|物流行业解决方案——助力企业构建物流行业新一体化模式
  18. 用python绘制熊猫图案_在python中绘制熊猫系列的CDF
  19. 源代码电影涉及的计算机思想,电影《源代码》你看懂了吗?
  20. PL2303输出的是TTL电平,为什么所有资料都说这个芯片是USB转RS232的??

热门文章

  1. 关于 Kotlin 静态代码检测工具 detekt 的说明
  2. C++装饰器模式的实现
  3. Android 绘制多个连续带数字圆圈。
  4. Continue 玩转像素点,Python 图像处理学习的第 3 天
  5. 3ds Max做的卡通狗教程
  6. sass教程之--sass变量
  7. 使用SQL将人员按性别分类并查询每种性别年纪最大的两个人
  8. Linux文本编辑常用命令
  9. 香港银行和科技公司竞争已经打响
  10. 阿里云十年再出发,边缘计算已启航