前言

大家好,在前几篇中,我们通过2种方式实现了仿抖音的翻页切换视频,仿抖音列表播放视频功能;这一篇,我们来说说视频的录制。

主流的视频录制,一般都采用的是FFmpeg 例如 腾讯短视频,由于FFmpeg的学习成本较大,这里我们就说说系统自带的MediaRecorder。

如何使用

首先,需要实现摄像头的预览,这里我们就用SurfaceView。

1.在布局中引入

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".activity.RecordActivity">

android:id="@+id/sv_record"

android:layout_width="match_parent"

android:layout_height="match_parent" />

android:id="@+id/btn_start"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="start"

app:layout_constraintBottom_toBottomOf="parent" />

android:id="@+id/btn_switch"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_marginTop="10dp"

android:text="switch"

app:layout_constraintRight_toRightOf="parent"

app:layout_constraintTop_toTopOf="parent" />

android:id="@+id/btn_end"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="end"

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintRight_toRightOf="parent" />

实现SurfaceHolder.Callback,重写surfaceCreated、surfaceChanged、surfaceDestroyed3个方法

其中surfaceCreated是SurfaceView创建成功时回调,可以在这里开始预览;surfaceChanged是SurfaceView变化时回调,这里不做处理;surfaceDestroyed是SurfaceView销毁时回调,可以在这里释放资源

surfaceHolder = svRecord.getHolder();

surfaceHolder.addCallback(this);

//设置一些参数方便后面绘图

svRecord.setFocusable(true);

svRecord.setKeepScreenOn(true);

svRecord.setFocusableInTouchMode(true);

@Override

public void surfaceCreated(SurfaceHolder holder) {

surfaceHolder = holder;

requestPermision();

}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

surfaceHolder = holder;

}

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

//停止预览并释放摄像头资源

stopPreview();

//停止录制

startRecord();

}

开始预览,首先是请求权限,这里使用的是自己封装的 CPermission,也可以使用其他的封装库

String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,

Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO};

CPermission.with(this)

.permiss()

.permission(perms)

.listener(new PermissListener() {

@Override

public void onGranted(List granted) {

showtoast("权限申请成功");

startPreview();

}

@Override

public void onDenied(List granted) {

showtoast("权限被拒绝");

}

}).start();

开始预览

/**

* 开始预览

*/

private void startPreview() {

if (svRecord == null || surfaceHolder == null) {

return;

}

if (camera == null) {

camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);

currentCameraType = 1;

btnSwitch.setText("后");

}

try {

camera.setPreviewDisplay(surfaceHolder);

Camera.Parameters parameters = camera.getParameters();

camera.setDisplayOrientation(90);

//实现Camera自动对焦

List focusModes = parameters.getSupportedFocusModes();

if (focusModes != null) {

for (String mode : focusModes) {

mode.contains("continuous-video");

parameters.setFocusMode("continuous-video");

}

}

List sizes = parameters.getSupportedVideoSizes();

if (sizes.size() > 0) {

size = sizes.get(sizes.size() - 1);

}

camera.setParameters(parameters);

camera.startPreview();

} catch (IOException e) {

e.printStackTrace();

}

}

其中,Camera.CameraInfo.CAMERA_FACING_BACK 代表后置摄像头,保险起见,应该检查设备是否有后置摄像头,这里就不检查了;还需要注意,当是后置时,应该旋转摄像头90度,否则预览是斜的

切换摄像头,这里如上代码所见,使用了一个int 型变量currentCameraType来记录前后摄像头;

stopPreview();

if (currentCameraType == 1) {

camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);

currentCameraType = 2;

btnSwitch.setText("前");

} else {

camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);

currentCameraType = 1;

btnSwitch.setText("后");

}

startPreview();

/**

* 停止预览

*/

private void stopPreview() {

//停止预览并释放摄像头资源

if (camera == null) {

return;

}

camera.setPreviewCallback(null);

camera.stopPreview();

camera.release();

camera = null;

}

需要注意,需要先停止预览,切换摄像头之后,再开始预览;

到这里已经实现了摄像头预览。

开始录制视频

/**

* 开始录制

*/

private void startRecord() {

if (mediaRecorder == null) {

mediaRecorder = new MediaRecorder();

}

temFile = getTemFile();

try {

camera.unlock();

mediaRecorder.setCamera(camera);

//从相机采集视频

mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

// 从麦克采集音频信息

mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

//编码格式

mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

mediaRecorder.setVideoSize(size.width, size.height);

//每秒的帧数

mediaRecorder.setVideoFrameRate(24);

// 设置帧频率,然后就清晰了

mediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024 * 100);

mediaRecorder.setOutputFile(temFile.getAbsolutePath());

mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());

//解决录制视频, 播放器横向问题

if (currentCameraType == 1) {

//后置

mediaRecorder.setOrientationHint(90);

} else {

//前置

mediaRecorder.setOrientationHint(270);

}

mediaRecorder.prepare();

//正式录制

mediaRecorder.start();

isRecording = true;

showtoast("开始录制");

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 获取临时文件目录

*

* @return

*/

private File getTemFile() {

String basePath = Environment.getExternalStorageDirectory().getPath() + "/doudemo/";

File baseFile = new File(basePath);

if (!baseFile.exists()) {

baseFile.mkdirs();

}

File temp = new File(basePath + System.currentTimeMillis() + ".mp4");

return temp;

}

这里的坑还是比较多的

1.首先需要解锁相机,调用camera.unlock();

2.关于视频的size ,应该通过parameters.getSupportedVideoSizes(); 获取该手机支持的宽高,如果设置手机不支持,会报错;

3.注意各个方法调用顺序,否则会报一些奇怪的错,无奈..................

4.摄像机角度问题,后置时,旋转90度,前置时,旋转270度

停止录制

需要锁定相机,需要预览时,跳到预览(播放)界面

/**

* 停止录制

*/

private void stopRecord(boolean delete) {

if (mediaRecorder == null) {

return;

}

if (myTimer != null) {

myTimer.cancel();

}

try {

mediaRecorder.stop();

} catch (Exception e) {

e.printStackTrace();

}

mediaRecorder.reset();

mediaRecorder.release();

mediaRecorder = null;

if (camera != null) {

camera.lock();

}

isRecording = false;

if (delete) {

if (temFile != null && temFile.exists()) {

temFile.delete();

}

} else {

//停止预览

stopPreview();

Intent intent = new Intent(RecordActivity.this, PrepareActivity.class);

intent.putExtra(PrepareActivity.VIDEO_PATH, temFile.getPath());

startActivity(intent);

}

showtoast("停止录制");

}

最后,献上完整代码。Github

android抖音切换实现,【Android 进阶】仿抖音系列之视频预览和录制(五)相关推荐

  1. android ffmpeg 仿剪映播放器 剪辑视频 预览条 快速精准抽帧

    android ffmpeg 仿剪映播放器 剪辑视频 预览条 快速精准抽帧 由于本人想学习音视频相关的东西,所以找了剪映作为借鉴,通过仿照剪映的功能学习音视频相关的东西,所以有了这个项目 暂时这个项目 ...

  2. Android 使用CameraX实现预览/拍照/录制视频/图片分析/对焦/缩放/切换摄像头等操作

    1. CameraX架构 看官方文档 CameraX架构 有如下这一段话 使用CameraX,借助名为"用例"的抽象概念与设备的相机进行交互. 预览 : 接受用于显示预览的Surf ...

  3. android横竖屏切换函数,Android横竖屏切换小结.PDF

    Android横竖屏切换小结 Android横竖屏切换小结 Android手机或平板都会存在横竖屏切换的功能,通常是由物理重力感应触发的,但是 有时候也不尽然,通常在设置里面我们可以对手机的横竖屏切换 ...

  4. Android视频编辑器(一)通过OpenGL预览、录制视频以及断点续录等

    前言 如今的视频类app可谓是如日中天,火的不行.比如美拍.快手.VUE.火山小视频.抖音小视频等等.而这类视频的最基础和核心的功能就是视频录制和视频编辑功能.包括了手机视频录制.美白.加滤镜.加水印 ...

  5. Android视频编辑器(二)预览、录制视频加上水印和美白磨皮效果

    前言      这是视频编辑器系列的第二篇文章,在上篇文章中,我们讲解了利用OpenGl和SurfaceView进行视频预览,MediaCodec和MeidaMuxer进行视频录制和断点续录.而这篇主 ...

  6. android显示视频预览

    android 11 kotlin显示视频预览 权限 读sd卡中的mp4文件的权限 <uses-permission android:name="android.permission. ...

  7. android surface清空,Android:如何在surfaceDestroyed()之后重启视频预览?

    我通过以下方式创建了一个CapturePreview类和CameraManager类: CapturePreview: public class CaptureView extends Surface ...

  8. android byte[] 转string 好多问号_Android 仿抖音实现动态壁纸

    code小生,一个专注 Android 领域的技术平台 公众号回复 Android 加入我的安卓技术群 作者:7_px 链接:https://www.jianshu.com/p/fc5cf284abb ...

  9. appium android数字字母切换键,Android自定义键盘:数字键盘和字母键盘

    在项目中,产品对于输入方式会有特殊的要求,需要对输入方式增加特定的限制,这就需要采用自定义键盘.本文主要讲述数字键盘和字母键盘的自定义实现. 自定义键盘的实现步骤如下: 自定义CustomKeyboa ...

最新文章

  1. 计算机网络应用和计算机应用有什么区别,什么是计算机网络技术?和计算机应用技术区别...
  2. JavaWeb学习总结(十七):JSP中的九个内置对象
  3. 《SpringBoot揭秘:快速构建微服务体系》—第3章3.5节本章小结
  4. JAM - get self detail information
  5. 当退出python时是否释放全部内存_python如何释放内存
  6. 90后女科学家,四年完成清华大学硕博连读,解决多个世界级难题
  7. 【数据库】第四章 JDBC、MyBatis
  8. 数字图像恢复matlab结论,matlab模糊图像恢复数字图像处理
  9. 软件项目经理新手上路10 - 要的是计划,还是?
  10. Clojure 学习入门(7)- 连接mysql
  11. UITextView(文本视图) 学习之初体验
  12. 使用面向 iOS 的本机插件扩展
  13. Flink:No operators defined in streaming topology. Cannot execute.
  14. 早餐吃菠萝好吗 早上可以吃菠萝吗
  15. (71)--爬取拉勾网招聘信息
  16. 礼金记账本安卓_份子钱记账本-全民都爱用的随礼管理手账神器
  17. Android Pitfall - 扒一扒RadioGroup 和 RadioButton
  18. 最大值最小值计算机一级,Excel2019中突出数据最大值和最小值的方法详解
  19. HTC VIVE TouchPad简单方向控制
  20. python爬虫爬取新浪网站新闻内容

热门文章

  1. 专家引领计算机网络感悟,科研团队自我评价
  2. 跟马保国老师闪电五连鞭视频通话网站源码
  3. 【博客话题】入门恩师——900%压缩比的Linux老师,马哥
  4. python destroy函数_Python Tkinter,destroy top-level after函数
  5. Css3动画 - 小圆围绕大圆的自转公转
  6. 进化论:找到了生物之间的联系,人们开始采用动态的眼光看待生命的发展。
  7. STM32F4_通过RS232实现和PC端通讯
  8. 从买啤酒的案例中谈测试思维的重要性
  9. 巴西总统Telegram账号被入侵背后,攻击关键点竟是手机语音信箱
  10. Linux系统服务详解