录制音频和视频

标准的支持录制的类是MediaRecorder。和Media Player类似,MediaRecorder在其生命周期内也会传递各种状态。这些状态如下所示(关于这些状态的更多详细信息,可以查看开发者网站中给出的状态图,http://developer.android.com/reference/android/media/MediaRecorder.html):

Initial

MediaRecorder类执行实例化。

Initialized

MediaRecorder执行了初始化,可以使用了。

DataSource Configured

对媒体资源(指定在哪里输出)进行配置。

Prepared

准备好MediaRecorder,用于记录。

Recording

正在执行记录。

Released

释放所有的资源。

要使用MediaRecorder,在清单文件中要设置某些许可:

·要支持视频记录,选择RECORD_VIDEO和CAMERA:


      <uses-permission android:name=\"android.permission.RECORD_VIDEO\"/>
      <uses-permission android:name=\"android.permission.CAMERA\"/>
  

·要记录音频,选择:


      <uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>
  

录制音频

有3种录制音频的方式。标准方式是使用MediaRecorder;最简单的方式是使用Intent;AudioRecorder可以直接从硬件缓冲区中录制。

MediaRecorder音频录制

首先,初始化MediaRecorder。然后设置数据源信息(音频输入源、输出格式、编码类型,在哪里录制文件等)。从版本8开始,还可以设置比特率和样本比率。完成这些后,调用prepare方法。


// initialize the MediaRecorder
MediaRecorder mediarecorder = new MediaRecorder;
// configure the data source
    // the source of the audio input
    mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    // output format
    mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    // encoding
    mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    // use absolute path to file where output is stored
    mediarecorder.setOutputFile(\"/sdcard/audiorecordexample.3gpp\");
    // prepare to record
    mediarecorder.prepare;
  

然后,当需要启动录制时,执行start方法:


mediarecorder.start;
  

要停止录制,可以调用stop方法。如果后来又想继续录制,则可以调用reset方法强制MediaRecorder回到空闲状态。然后重新配置数据源,再次准备MediaRecorder:


mediarecorder.stop;
...
mediarecorder.reset;
  

一旦不再需要MediaRecorder,要记得释放它:


mediarecorder.release;
  

下面是一个简单的应用示例,它为用户提供record按钮。单击该按钮,record方法会在已经指向的文件路径下录制。然后,会显示stop按钮,record按钮会变得不可见。当单击stop按钮时,会调用stopRecord方法,又重新显示record按钮。


public class AudioRecorder extends Activity {
    private MediaRecorder mediarecorder;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.audiorecorderlayout);
        ImageButton recordbutton = (ImageButton) findViewById(R.id.record);
        recordbutton.setOnClickListener(new OnClickListener {
            public void onClick(View v) {
                record(\"/sdcard/audiorecordexample.3gpp\");
            }
        });
        ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
        stopbutton.setOnClickListener(new OnClickListener {
            public void onClick(View v) {
                stopRecord;
            }
        });
    }
    private void record(String filePath) {
            try {
                File mediafile = new File(filePath);
                if(mediafile.exists) {
                    mediafile.delete;
                }
                mediafile = null;
                // record button goes away
                ImageButton button = (ImageButton) findViewById(R.id.record);
                button.setVisibility(View.GONE);
                    // stop button shows up
                ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
                stopbutton.setVisibility(View.VISIBLE);
                    // set up media recorder
                if(mediarecorder == null) mediarecorder = new MediaRecorder;
                mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                mediarecorder.setOutputFile(filePath);
                    // prepare media recorder
                mediarecorder.prepare;
                    // start media recorder
                mediarecorder.start;
            } catch (Exception e) {
                e.printStackTrace;
            }
        }
    }
    private void stopRecord {
                    // stop media recorder
                mediarecorder.stop;
                    // reset media recorder
                mediarecorder.reset;
                // record button shows up
                ImageButton button = (ImageButton) findViewById(R.id.record);
                button.setVisibility(View.VISIBLE);
                // stop button goes away
                ImageButton stopbutton = (ImageButton) findViewById(R.id.stop);
                stopbutton.setVisibility(View.GONE);
    }
}
 

使用Intent录制音频

通过Intent录制是最简单的方式。只需要构建Media Store.Audio.Media.RECORD_SOUND_ACTION intent,然后在Activity内调用startActivityForResult方法启动它,它会启动在大多数Android设备中都会提供的默认音频录制程序,继续录制一些音频:


Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
startActivityForResult(intent, 1); // intent and requestCode of 1
  

录制完成后,音频录制程序结束,启动调用startActivityForResult方法的Activity会到前端执行。当发生这种情况时,会触发Activity的onActivityResult方法,其中包括了我们提供的requestCode代码(在这个例子中,即1),结果代码(OK或error),以及包含指向记录的音频文件的intent:


protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    // is it our requestCode?
    if (requestCode == 1) {
        // is the resultCode OK?
      if (resultCode == RESULT_OK) {
                // lets get the uri
              Uri audioUri = intent.getData;
                // lets play the uri or do something with it.
              playAudio(audioUri);
         }
    }
}
  

AudioRecorder音频录制

和AudioTrack类似,AudioRecorder提供了更直接的录制体验:


short buffer = new short[10000];
recorder = new AudioRecord( // source to record from
                    MediaRecorder.AudioSource.MIC,
                            // frequency
                    11025,
                            // channel config
—mono, stereo, etc.
                    AudioFormat.CHANNEL_CONFIGURATION_MONO,
                            // audio encoding
                    AudioFormat.ENCODING_PCM_16BIT,
                            // buffer size
                    buffer.length
                );
  

AudioRecord方法提供了需要录制的音频资源类型(话筒、摄像机话筒、或语音呼叫)、以Hz表示的采样比率(44100、22050或11025)、音频配置(单声道或立体声)、音频格式/编码、以字节数表示的缓冲区长度。注意,缓冲区的大小决定了AudioRecord在读取运行数据之前能够录制的时间。数据应该从音频硬件中读取,以小于总录制缓冲区的大小读取。Android的AudioRecord一旦配置完成,会自动知道如何使用设备上的硬件接口,从而提供愉快的用户体验。

为开始录制,设置AudioRecord的Record状态,重复从硬件缓冲区中读取数据:


recorder.startRecording;
while(recordablestate) {
    try {
        // read in up to buffer size
        int readBytes = recorder.read(buffer, 0, buffer.length);
        // do something with the bytes that are read
        } catch (Exception t) {
          recordablestate = false;
        }
}
  

要停止录制,将AudioRecord的状态置为Stop。如果不想录制,则不要忘记释放和录制相关的所有资源。如果还想继续录制,可以调用startRecording方法再开始录制:


// stop recording
recorder.stop;
// release recording resources
recorder.release;
  

视频录制

可以通过两种方式录制视频:通过使用MediaRecorder或通过使用Intent。不支持类似音频那样的原始录制。

MediaRecorder视频录制

通过MediaRecorder录制视频的过程和录制音频的过程非常相似:初始化MediaRecorder,准备数据源,启动MediaRecorder。可以给用户提供预览窗口,这样他可以预览捕捉到的视频,通过提供之前提到的surface来播放视频。一般来说,会使用VideoView:


// initialize
MediaRecorder mediarecorder = new MediaRecorder;
// set data source
mediarecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediarecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mediarecorder.setOutputFile(\"/sdcard/someexamplevideo.mp4\");
// provide a surface to show the preview in. in this case a VideoView is used
videoview = (VideoView) findViewById(R.id.videosurface);
SurfaceHolder holder = videoview.getHolder;
mediarecorder.setPreviewDisplay(holder.getSurface);
// prepare
mediarecorder.prepare;
// start recording
mediarecorder.start;
  

intent视频录制

基于intent的视频录制和使用intent录制音频类似。要使用的intent是MediaStore.ACTION_VIDEO_CAPTURE,结果数据是视频文件的URI。

《Android程序设计:第2版》