Android中MediaRecorder类实现视频的录制

来源:互联网 发布:ido软件下载 编辑:程序博客网 时间:2024/04/29 20:10

Android Camera中视频录制时要使用到MediaRecorder,在网上查阅相关资料时,发现这篇文章不错,就转载了过来,

源地址是:http://express.ruanko.com/ruanko-express_73/tech-overnight5.html

一、MediaRecorder类概述

Android的MediaRecorder包含了Audio和video的记录功能,在Android的界面上,Music和Video两个应用程序都是调用MediaRecorder实现的。MediaRecorder在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaRecorder程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。

1、MediaRecorder方法说明:

方法说明setAudioChannels(int numChannels)设置录制的音频通道数setAudioEncoder(int audio_encoder)设置audio的编码格式setAudioEncodingBitRate(int bitRate)设置录制的音频编码比特率setAudioSamplingRate(int samplingRate)设置录制的音频采样率setAudioSource(int audio_source)设置用于录制的音源setAuxiliaryOutputFile(String path)辅助时间的推移视频文件的路径传递setAuxiliaryOutputFile(FileDescriptor fd)在文件描述符传递的辅助时间的推移视频setCamera(Camera c)设置一个recording的摄像头setCaptureRate(double fps)设置视频帧的捕获率setMaxDuration(int max_duration_ms)设置记录会话的最大持续时间(毫秒)setMaxFileSize(long max_filesize_bytes)设置记录会话的最大大小(以字节为单位)setOutputFile(FileDescriptor fd)传递要写入的文件的文件描述符setOutputFile(String path)设置输出文件的路径setOutputFormat(int output_format)设置在录制过程中产生的输出文件的格式setPreviewDisplay(Surface sv)表面设置显示记录媒体(视频)的预览setVideoEncoder(int video_encoder)设置视频编码器,用于录制setVideoEncodingBitRate(int bitRate)设置录制的视频编码比特率setVideoFrameRate(int rate)设置要捕获的视频帧速率setVideoSize(int width, int height)设置要捕获的视频的宽度和高度setVideoSource(int video_source)开始捕捉和编码数据到setOutputFile(指定的文件)

2、MediaRecorder中音视频编码格式和资源说明:

  • 视频编码格式:default,H263,H264,MPEG_4_SP
  • 获得视频资源:default,CAMERA
  • 音频编码格式:default,AAC,AMR_NB,AMR_WB
  • 获得音频资源:defalut,camcorder,mic,voice_call,voice_communication,voice_downlink,voice_recognition, voice_uplink
  • 输出方式:amr_nb,amr_wb,default,mpeg_4,raw_amr,three_gpp

例如:

recorder.setAudioSource(MediaRecorder.AudioSource.MIC);  //设置音频源为麦克风recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//设置声音格式为3gprecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); //设置编码为AMRrecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);   //设置视频源为Camerarecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //设置视频输出格式为MP4recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);//设置视频编码recorder.setOutputFile(filePath);  //设置视频输出路径

以上代码在android 2.3.3及以下版本可以运行,但是在更高版本的android系统中不能运行,所以更改后的代码为:

recorder.setCamera(camera); recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//视频源 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 录音源为麦克风recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)); // 默认视频格式

二、Android 中MediaRecorder和Camera的关系

从功能的角度MediaRecorder一般包含音频,视频记录,视频预览的功能,Camera包含了取景区预览,静态图像捕获的功能。在Android中,应用程序自上而下分成JAVA应用,JAVA框架,JNI,C框架,具体实现几个部分。多媒体方面的程序尤其是这样。MediaRecorder 和Camera在Android中都有自上而下的架构,它们在顶层JAVA应用层,共用一个应用程序Camera(其中的程序也是独立的),在JAVA框 架和JNI层是独立的,主要的联系在于Camer的C框架以下的内容被MediaRecorder实现(也就是PVAuthor)所调用,作为 MediaRecorder实现的视频输入设备,它的作用是负责传输视频数据和提供显示预览。本身Camera C框架以下的代码基本提供了取景器预览(Preview)、视频数据流获取、静止图像获取三方面的功能,MediaRecorder实现使用其取景器预览和视频数据流获取的功能,而Camera的JNI使用其取景器预览和静止图像获取两方面的功能。

三、示例讲解

1、首先,我们需要在AndroidManifest.xml文件中声明录制视频要用到的权限:

<!—摄像头--><uses-permission android:name="android.permission.CAMERA" /><!—硬件支持--><uses-feature android:name="android.hardware.camera"/><uses-feature android:name="android.hardware.camera.autofocus"/><!—音频即声音--><uses-permission android:name="android.permission.RECORD_AUDIO" /><!—sd卡写入权限--><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_SETTINGS" />

2、其次,页面布局文件中要知道我们录制的是什么,必须要有SurfaceView提供界面预览:

<SurfaceView     android:id="@+id/videoView"     android:layout_below="@id/head_video"     android:layout_width="fill_parent"     android:layout_height="fill_parent"     android:visibility="visible" ></SurfaceView>

3、录制视频的Java代码主要实现代码:

开始录制视频:

try {// 关闭预览并释放资源if(camera!=null){camera.stopPreview();camera.release();camera = null;}recorder = new MediaRecorder();// 声明视频文件对象myRecVideoFile = new File(fileName);if(!myRecVideoFile.exists()){myRecVideoFile.getParentFile().mkdirs();myRecVideoFile.createNewFile();}recorder.reset();// 判断是否有前置摄像头,若有则打开,否则打开后置摄像头int CammeraIndex=FindFrontCamera();  if(CammeraIndex==-1){  ToastUtil.TextToast(getApplicationContext(), "您的手机不支持前置摄像头", ToastUtil.LENGTH_SHORT);CammeraIndex=FindBackCamera();  }camera = Camera.open(CammeraIndex);// 设置摄像头预览顺时针旋转90度,才能使预览图像显示为正确的,而不是逆时针旋转90度的。camera.setDisplayOrientation(90);camera.unlock();recorder.setCamera(camera); //设置摄像头为相机recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//视频源 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 录音源为麦克风recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW)); //设置视频和声音的编码为系统自带的格式recorder.setOutputFile(myRecVideoFile.getAbsolutePath());recorder.setPreviewDisplay(mSurfaceHolder.getSurface()); // 预览recorder.setMaxFileSize(10*1024*1024); //设置视频文件的最大值为10M,单位B//recorder.setMaxDuration(3*1000);//设置视频的最大时长,单位毫秒//recorder.setOrientationHint(90);//视频旋转90度,没有用recorder.prepare(); // 准备录像recorder.start(); // 开始录像handler.post(timeRun); // 调用Runablerecording = true; // 改变录制状态为正在录制} catch (IOException e1) {releaseMediaRecorder();handler.removeCallbacks(timeRun);minute = 0;second = 0;recording = false;btnStart.setEnabled(true);} catch (IllegalStateException e) {releaseMediaRecorder();handler.removeCallbacks(timeRun);minute = 0;second = 0;recording = false;btnStart.setEnabled(true);}


停止录制视频:

if(recorder!=null){<span style="white-space:pre"></span>recorder.stop();recorder.release();recorder = null;minute = 0;second = 0;handler.removeCallbacks(timeRun);recording = false;}

4、效果图:

5、完整示例代码:

JAVA代码:

public class VideoActivity extends BaseActivity implements SurfaceHolder.Callback {private File myRecVideoFile;private SurfaceView mSurfaceView;private SurfaceHolder mSurfaceHolder;private TextView tvTime;private TextView tvSize;private Button btnStart;private Button btnStop;private Button btnCancel;private MediaRecorder recorder;private Handler handler;private Camera camera;private boolean recording; // 记录是否正在录像,fasle为未录像, true 为正在录像private int minute = 0;private int second = 0;private String time="";private String size="";private String fileName;private String name="";/** * 录制过程中,时间变化,大小变化 */private Runnable timeRun = new Runnable() {@Overridepublic void run() {long fileLength=myRecVideoFile.length();if(fileLength<1024 && fileLength>0){size=String.format("%dB/10M", fileLength);}else if(fileLength>=1024 && fileLength<(1024*1024)){fileLength=fileLength/1024;size=String.format("%dK/10M", fileLength);}else if(fileLength>(1024*1024*1024)){fileLength=(fileLength/1024)/1024;size=String.format("%dM/10M", fileLength);}second++;if (second == 60) {minute++;second = 0;}time = String.format("%02d:%02d", minute, second);tvSize.setText(size);tvTime.setText(time);handler.postDelayed(timeRun, 1000);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.recorded_video);setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);mSurfaceView = (SurfaceView) findViewById(R.id.videoView);mSurfaceHolder = mSurfaceView.getHolder();mSurfaceHolder.addCallback(this);mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);mSurfaceHolder.setKeepScreenOn(true);handler = new Handler();tvTime = (TextView) findViewById(R.id.tv_video_time);tvSize=(TextView)findViewById(R.id.tv_video_size);btnStop = (Button) findViewById(R.id.btn_video_stop);btnStart = (Button) findViewById(R.id.btn_video_start);btnCancel = (Button) findViewById(R.id.btn_video_cancel);btnCancel.setOnClickListener(listener);btnStart.setOnClickListener(listener);btnStop.setOnClickListener(listener);// 设置sdcard的路径fileName = Environment.getExternalStorageDirectory().getAbsolutePath();name="video_" +System.currentTimeMillis() + ".mp4";fileName += File.separator + File.separator+"Ruanko_Jobseeker"+File.separator+name;}@Overridepublic void surfaceCreated(SurfaceHolder holder) {// 开启相机if (camera == null) {int CammeraIndex=FindFrontCamera();          if(CammeraIndex==-1){          ToastUtil.TextToast(getApplicationContext(), "您的手机不支持前置摄像头", ToastUtil.LENGTH_SHORT);            CammeraIndex=FindBackCamera();          }        camera = Camera.open(CammeraIndex); try {camera.setPreviewDisplay(mSurfaceHolder);camera.setDisplayOrientation(90);} catch (IOException e) {e.printStackTrace();camera.release();}}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// 开始预览camera.startPreview();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 关闭预览并释放资源if (camera != null) {camera.stopPreview();camera.release();camera = null;}}private OnClickListener listener = new OnClickListener() {@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_video_stop:if(recorder!=null){releaseMediaRecorder();minute = 0;second = 0;handler.removeCallbacks(timeRun);recording = false;}btnStart.setEnabled(true);break;case R.id.btn_video_start:if(recorder!=null){releaseMediaRecorder();minute = 0;second = 0;handler.removeCallbacks(timeRun);recording = false;}recorder();btnStart.setEnabled(false);break;case R.id.btn_video_cancel:releaseMediaRecorder();handler.removeCallbacks(timeRun);minute=0;second=0;recording = false;VideoActivity.this.finish();break;}}};//判断前置摄像头是否存在 private int FindFrontCamera(){          int cameraCount = 0;          Camera.CameraInfo cameraInfo = new Camera.CameraInfo();          cameraCount = Camera.getNumberOfCameras(); // get cameras number                          for ( int camIdx = 0; camIdx < cameraCount;camIdx++ ) {              Camera.getCameraInfo( camIdx, cameraInfo ); // get camerainfo              if ( cameraInfo.facing ==Camera.CameraInfo.CAMERA_FACING_FRONT ) {                   // 代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置                 return camIdx;              }          }          return -1;      }  //判断后置摄像头是否存在    private int FindBackCamera(){          int cameraCount = 0;          Camera.CameraInfo cameraInfo = new Camera.CameraInfo();          cameraCount = Camera.getNumberOfCameras(); // get cameras number                          for ( int camIdx = 0; camIdx < cameraCount;camIdx++ ) {              Camera.getCameraInfo( camIdx, cameraInfo ); // get camerainfo              if ( cameraInfo.facing ==Camera.CameraInfo.CAMERA_FACING_BACK ) {                   // 代表摄像头的方位,目前有定义值两个分别为CAMERA_FACING_FRONT前置和CAMERA_FACING_BACK后置                 return camIdx;              }          }          return -1;      }      //释放recorder资源     private void releaseMediaRecorder(){    if (recorder != null) {            recorder.stop();            recorder.release();            recorder = null;        }    }//开始录像public void recorder() {if (!recording) {try {// 关闭预览并释放资源if(camera!=null){camera.stopPreview();camera.release();camera = null;}recorder = new MediaRecorder();// 声明视频文件对象myRecVideoFile = new File(fileName);if(!myRecVideoFile.exists()){myRecVideoFile.getParentFile().mkdirs();myRecVideoFile.createNewFile();}recorder.reset();// 判断是否有前置摄像头,若有则打开,否则打开后置摄像头int CammeraIndex=FindFrontCamera();          if(CammeraIndex==-1){          ToastUtil.TextToast(getApplicationContext(), "您的手机不支持前置摄像头", ToastUtil.LENGTH_SHORT);            CammeraIndex=FindBackCamera();          }        camera = Camera.open(CammeraIndex); // 设置摄像头预览顺时针旋转90度,才能使预览图像显示为正确的,而不是逆时针旋转90度的。        camera.setDisplayOrientation(90);        camera.unlock();recorder.setCamera(camera); //设置摄像头为相机recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//视频源 recorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 录音源为麦克风recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));//设置视频和声音的编码为系统自带的格式recorder.setOutputFile(myRecVideoFile.getAbsolutePath());recorder.setPreviewDisplay(mSurfaceHolder.getSurface()); // 预览recorder.setMaxFileSize(10*1024*1024); //设置视频文件的最大值为10M,单位B//recorder.setMaxDuration(3*1000);//设置视频的最大时长,单位毫秒//recorder.setOrientationHint(90);//视频旋转90度,没有用recorder.prepare(); // 准备录像recorder.start(); // 开始录像handler.post(timeRun); // 调用Runablerecording = true; // 改变录制状态为正在录制} catch (IOException e1) {releaseMediaRecorder();handler.removeCallbacks(timeRun);minute = 0;second = 0;recording = false;btnStart.setEnabled(true);} catch (IllegalStateException e) {releaseMediaRecorder();handler.removeCallbacks(timeRun);minute = 0;second = 0;recording = false;btnStart.setEnabled(true);}} elseToastUtil.TextToast(getApplicationContext(), "视频录制中...", ToastUtil.LENGTH_SHORT);}}

XML布局文件:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >        <SurfaceView        android:id="@+id/videoView"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:visibility="visible" >    </SurfaceView>        <TextView         android:id="@+id/tv_video_size"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:textColor="@color/orange"        android:layout_centerHorizontal="true"        android:layout_marginTop="10dp"        android:layout_marginLeft="10dp"        android:textSize="18sp"/>    <TextView         android:id="@+id/tv_video_time"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="@color/orange"        android:text="00:00"        android:layout_alignParentRight="true"        android:layout_centerHorizontal="true"        android:layout_marginTop="10dp"        android:layout_marginRight="10dp"        android:textSize="18sp"/><View         android:layout_width="fill_parent"        android:layout_height="60dp"        android:background="@drawable/btn_alpha"        android:alpha="0.5"        android:layout_alignParentBottom="true"/>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="60dp"        android:layout_alignParentBottom="true"        android:gravity="center"        android:orientation="horizontal"        android:paddingBottom="10dp"        android:paddingTop="10dp">        <Button            android:id="@+id/btn_video_stop"            android:layout_width="wrap_content"            android:layout_height="40dp"            android:layout_marginLeft="10dp"            android:layout_marginRight="5dp"            android:background="@drawable/btn_position_selector"            android:text="结束"            android:textColor="@color/white"             android:layout_weight="1"            android:textSize="18sp"/>        <Button            android:id="@+id/btn_video_start"            android:layout_width="wrap_content"            android:layout_height="40dp"            android:layout_marginRight="5dp"            android:background="@drawable/btn_position_selector"            android:text="开始"            android:textColor="@color/white"            android:layout_weight="1"            android:textSize="18sp" />        <Button            android:id="@+id/btn_video_cancel"            android:layout_width="wrap_content"            android:layout_height="40dp"            android:layout_marginRight="10dp"            android:background="@drawable/btn_position_selector"            android:text="取消"            android:textColor="@color/white"             android:layout_weight="1"            android:textSize="18sp"/>    </LinearLayout></RelativeLayout>


0 0
原创粉丝点击