Android自定义录像(一)之录像功能实现(附demo源码)
来源:互联网 发布:下单软件 编辑:程序博客网 时间:2024/04/28 08:35
引言
最近在做一个项目,是有关用手机摄像头做图像实时识别的。所以里面需要自定义一个录像功能。该demo实现了录像和录像后文件的保存查看,录像会实时自动对焦(AutoFocus)。根据功能分两篇讲述。这第一篇讲述录像基本实现思路和需要注意的点。后面附有github的demo源码下载链接。
思路
*Android实现录像主要依靠MediaRecorder和SurfaceView这两个类。另外,因为需要对摄像头参数做一些设定,所以也需要Camera类。它们的作用分别是:MediaRecorder通过控制录像音视频源和输出编码等;surfaceview则是作为View的存在提供用户界面,在surfaceview的不同生命周期实现不同的操作;camera类则用于对摄像头参数做一些设定,再调用MediaRecorder的setCamera()
方法将camera对象带入。
代码
1.布局
<?xml version="1.0" encoding="utf-8"?> <FrameLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:baselineAligned="false" xmlns:android="http://schemas.android.com/apk/res/android"> <SurfaceView android:id="@+id/capture_surfaceview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:baselineAligned="false"> <RelativeLayout android:layout_gravity="left" android:layout_width="0.0dip" android:layout_height="fill_parent" android:layout_weight="5.0"> <TextView android:textSize="15.0sp" android:textColor="@color/red_overlay" android:id="@+id/capture_textview_information" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10.0dip" android:layout_alignParentRight="true" android:layout_alignParentBottom="true" /> </RelativeLayout> <RelativeLayout android:layout_gravity="right" android:background="@color/white_overlay" android:padding="20.0dip" android:layout_width="0.0dip" android:layout_height="fill_parent" android:layout_weight="1.0" android:alpha="0.3"> <ImageButton android:id="@+id/capture_imagebutton_setting" android:tag="setting" android:background="@drawable/settings" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:contentDescription="@string/imagedescription" /> <ImageButton android:id="@+id/ib_stop" android:tag="start" android:background="@drawable/rec_start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:contentDescription="@string/imagedescription" /> <ImageButton android:id="@+id/capture_imagebutton_showfiles" android:tag="showfiles" android:background="@drawable/folder" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:contentDescription="@string/imagedescription" /> </RelativeLayout> </LinearLayout> </FrameLayout>
2.布局截图:
3.核心代码及注释:
package com.alanjet.videorecordertest; import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.PixelFormat; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.ImageButton; import android.widget.Toast; import java.io.File; import java.util.Calendar; public class MainActivity extends Activity implements SurfaceHolder.Callback { private static final String TAG = "MainActivity"; private SurfaceView mSurfaceview; private ImageButton mBtnStartStop; private ImageButton mBtnSet; private ImageButton mBtnShowFile; private boolean mStartedFlg = false; private MediaRecorder mRecorder; private SurfaceHolder mSurfaceHolder; private Camera myCamera; private Camera.Parameters myParameters; private Camera.AutoFocusCallback mAutoFocusCallback=null; private boolean isView = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //重写AutoFocusCallback接口 mAutoFocusCallback=new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if(success){ Log.i(TAG, "AutoFocus: success..."); }else { Log.i(TAG, "AutoFocus: failure..."); } } }; initScreen(); setContentView(R.layout.activity_main); mSurfaceview = (SurfaceView)findViewById(R.id.capture_surfaceview); mBtnStartStop = (ImageButton) findViewById(R.id.ib_stop); mBtnSet= (ImageButton) findViewById(R.id.capture_imagebutton_setting); mBtnShowFile= (ImageButton) findViewById(R.id.capture_imagebutton_showfiles); mBtnShowFile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(MainActivity.this,ShowVideoActivity.class); startActivity(intent); finish(); } }); mBtnSet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"相机设置待开发~",Toast.LENGTH_SHORT).show(); } }); SurfaceHolder holder = mSurfaceview.getHolder();// 取得holder holder.addCallback(this); // holder加入回调接口 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } /** * 获取系统时间,保存文件以系统时间戳命名 */ public static String getDate(){ Calendar ca = Calendar.getInstance(); int year = ca.get(Calendar.YEAR); int month = ca.get(Calendar.MONTH); int day = ca.get(Calendar.DATE); int minute = ca.get(Calendar.MINUTE); int hour = ca.get(Calendar.HOUR); int second = ca.get(Calendar.SECOND); String date = "" + year + (month + 1 )+ day + hour + minute + second; Log.d(TAG, "date:" + date); return date; } /** * 获取SD path */ public String getSDPath(){ File sdDir = null; boolean sdCardExist = Environment.getExternalStorageState() .equals(android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在 if (sdCardExist) { sdDir = Environment.getExternalStorageDirectory();// 获取跟目录 return sdDir.toString(); } return null; } //初始化屏幕设置 public void initScreen(){ requestWindowFeature(Window.FEATURE_NO_TITLE);// 去掉标题栏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);// 设置全屏 // 设置横屏显示 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // 选择支持半透明模式,在有surfaceview的activity中使用。 getWindow().setFormat(PixelFormat.TRANSLUCENT); } //初始化Camera设置 public void initCamera() { if(myCamera == null && !isView) { myCamera = Camera.open(); Log.i(TAG, "camera.open"); } if(myCamera != null && !isView) { try { myParameters = myCamera.getParameters(); myParameters.setPreviewSize(1920, 1080); myParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); myCamera.setParameters(myParameters); myCamera.setPreviewDisplay(mSurfaceHolder); myCamera.startPreview(); isView = true; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); Toast.makeText(MainActivity.this, "初始化相机错误", Toast.LENGTH_SHORT).show(); } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub mSurfaceHolder = holder; } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub mSurfaceHolder = holder; initCamera(); mBtnStartStop.setOnClickListener(new View.OnClickListener() { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onClick(View v) { // TODO Auto-generated method stub if (!mStartedFlg) { // Start if (mRecorder == null) { mRecorder = new MediaRecorder(); // Create MediaRecorder } try { myCamera.unlock(); mRecorder.setCamera(myCamera); // Set audio and video source and encoder // 这两项需要放在setOutputFormat之前 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P)); mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); // Set output file path String path = getSDPath(); if (path != null) { File dir = new File(path + "/VideoRecorderTest"); if (!dir.exists()) { dir.mkdir(); } path = dir + "/" + getDate() + ".mp4"; mRecorder.setOutputFile(path); Log.d(TAG, "bf mRecorder.prepare()"); mRecorder.prepare(); Log.d(TAG, "af mRecorder.prepare()"); Log.d(TAG, "bf mRecorder.start()"); mRecorder.start(); // Recording is now started Log.d(TAG, "af mRecorder.start()"); mStartedFlg = true; mBtnStartStop.setBackground(getDrawable(R.drawable.rec_stop)); } } catch (Exception e) { e.printStackTrace(); } } else { // stop if (mStartedFlg) { try { mRecorder.stop(); mRecorder.reset(); mBtnStartStop.setBackground(getDrawable(R.drawable.rec_start)); } catch (Exception e) { e.printStackTrace(); } } mStartedFlg = false; } } }); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub // surfaceDestroyed的时候同时对象设置为null mSurfaceview = null; mSurfaceHolder = null; if (mRecorder != null) { mRecorder.release(); mRecorder = null; } } @Override protected void onRestart() { super.onRestart(); } @Override protected void onResume() { super.onResume(); } @Override protected void onStart() { super.onStart(); } }
4.manifest权限配置:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
5.注意点:
Surfaceview主要是通过
SurfaceHolder holder = mSurfaceview.getHolder();
中的SurfaceHolder来做控制的,SurfaceHolder加入回调接口holder.addCallback(this)
来重写接口中的三个生命周期方法:public void surfaceChanged(), public void surfaceCreated(), public void surfaceDestroyed().
实现自动对焦的关键在于重写
Camera.AutoFocusCallback()
接口。并且需要将camera的parameters设置对焦模式为myParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)
。
6.运行截图:
7.demo源代码下载链接:
https://github.com/alanjet/VideoRecorderTest.git
后言
还有一篇博客《Android自定义录像(二)之录像文件保存查看实现(附demo源码)》将在近期推出!
在实践中求真知,在技术中寻快乐。这是自己在做项目中的一点小积累,希望能帮到有需要的Android开发小伙伴。这也是自己第一次写csdn博客。可能表达得并不是很到位,一些地方写的也比较稚嫩,欢迎大家在评论中多指点多交流,在技术之路上不断前进。
- Android自定义录像(一)之录像功能实现(附demo源码)
- Android自定义录像(二)之录制文件存储与查看(附demo源码)
- EasyPlayer Android安卓流媒体播放器实现播放同步录像功能实现(附源码)
- Android - 实现拍照,录像功能
- Android--录像功能的实现
- EasyPusher实现安卓Android手机直播推送同步录像功能(源码解析)
- [转]EasyPusher实现安卓Android手机直播推送同步录像功能(源码解析)
- MediaRecorde实现录像自动录像功能
- Android调用MideaRecord实现简单录像功能
- android录像功能
- android录像预览功能
- Android自定义照相机实现 拍照 录像
- android 自定义拍照录像
- Android自定义拍照、录像
- Android的录像实现
- Android 实现拍照、录像
- 更改VLC源码 实现使用libVLC录像功能
- [置顶] 更改VLC源码 实现使用libVLC录像功能
- HDU 1542Atlantis
- 2016_NENU_SoftWare_Summer_ Training_3
- 函数值传递和引用传递
- eclipse怎么阅读Spring源码
- 互联网公司赚钱的3大类主要模式
- Android自定义录像(一)之录像功能实现(附demo源码)
- Android无需java代码,仅在xml中实现横向多个控件间隔分布
- C#入门6.12——字符串的复制
- 关于log4j.xml发送邮件
- VC++动态链接库(DLL)编程深入浅出
- 树状数组,模板 注意事项
- CPU阿甘之烦恼
- JAVA学习--扎金花
- vs2010 DirectShow(windows sdk v7.1)配置