11.3.1 将MediaRecorder用于视频
为了将MediaRecorder用于视频捕获,必须采用与音频捕获相同的步骤,同时加上一些视频特定的步骤。此外,MediaRecorder是一个状态机,因此必须遵循从实例化到录制的特定步骤序列。
首先将实例化MediaRecorder,然后依次进行其他的步骤。
1 MediaRecorder recorder=new MediaRecorder();
1.音频和视频源
在实例化之后,可以设置音频和视频源。可以使用setAudioSource方法来设置音频源,并传入一个常量以表示想要使用的源。
1 recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
音频源的可能值定义为MediaRecorder.AudioSource类中的常量:
CAMCORDER:如果设备有不同的麦克风用于不同的摄像头(向前、向后),那么使用此值将指定适当的麦克风(Android 2.1/API Level 7 或之后的版本)。
DEFAULT:这个值指定将使用设备上默认的麦克风。
MIC:这个值指定将使用用于录制视频的标准麦克风。
VOICE_CALL:这个值指定音频应该是来自一个正在进行中的通话。虽然可能不是所有的手机,但是目前大部分的手机都不支持这个常量。
VOICE_DOWNLINK:这个值指定音频应该是来自与一个电话,特别是指传入的音频(另一方)。虽然可能不是所有的手机,但是目前大部分的手机都不支持这个常量。
VOICE_UPLINK:这个值指定音频应该是来自与一个电话,特别是指传出的音频(手机发送的音频)。虽然可能不是所有的手机,但是目前大部分的手机都不支持这个常量。
VOICE_RECOGNITION:这个值指定音频应该来自一个设置为用于电话上语音识别功能的麦克风。如果没有指定这种麦克风,那么将使用默认的麦克风。
可能的视频源的值定义为在MediaRecorder.VideoSource类中的常量,其中只包含两个常量:
CAMERA
DEFAULT
两个常量表示同样的事情,即设备上的主摄像头应该用于录制视频。
为了设置视频源,可以使用setVideoSource方法:
1 recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
2.输出格式
在设置音频源和视频源之后,可以使用MediaRecorder的setOutputFormat方法设置输出格式,同时传入要使用的格式。
1 recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
可能的格式定义为在MediaRecorder.OutputFormat类中列出的常量。
DEFAULT:指定使用默认的输出格式。默认的输出格式可能会因为设备的不同而有所区别。在运行Android 2.2的Nexus 1上它是MPEG-4,因此与指定MPEG-4常量时使用相同的格式。
MPEG-4:指定音频和视频将被捕获到一个MPEG-4文件格式的文件中。这个文件将是一个.mp4文件。MPEG-4文件通常包含H.264、H.263和MPEG-4 Part 2 编码的视频,以及ACC或MP3编码的音频(尽管可以使用其他的编解码器)。MPEG-4文件被广泛用于iPod和Flash以及许多其他在线视频技术和消费电子设备。
RAW_AMR:此设置仅用于音频录制,而不用于视频。
THREE_GPP:指定音频和视频将被捕获到一个3GP文件格式的文件中。这个文件将是一个.3gp文件。3GPP文件通常包含使用H.264、MPEG-4 Part 2 或H.263编解码器编码的视频和使用AMR或AAC编解码器编码的音频。
3.音频和视频编码器
在设置输出格式之后,应该指定想要使用的音频和视频编码器。使用MediaRecorder的setVideoSource方法,可以指定将要使用的视频编解码器:
1 recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
可以传递给setVideoSource的可能值定义为在MediaRecorder.VideoEncoder中的常量:
DEFAULT:这是一个设备相关的设置,指定使用设备的默认编解码器。在大多数情况下是H.263,因为他是Android上唯一必须支持的编解码器。
H.263:这个值指定使用的编解码器是H.263。H.263是在1995年发布的编解码器,专门为低比特率视频传输而开发。他是许多早期Internet视频技术的基础,如Flash和RealPlayer早期所使用的技术。在Android上它必须支持的编码,因此能可靠的使用。
H.264:这个值指定使用的编解码器是H.264(它还被命名为MPEG-4 Part 10 或AVC(高级视频编码))。H.264是当前最先进的编解码器,广泛应用于各种技术——从BlueRay到Flash。它在2003年发布。大多数Android设备支持使用这种编解码器进行视频播放,为小部分设备使用它进行视频编码。
MPEG_4_SP:这个值指定使用的编解码器将是MPEG_4_SP(Simple Profile ,简单配置)编解码器。从技术上讲,MPEG_4_SP是MPEG-4 Part 2 Simple Profile。他在1999年发布,为需要低比特率视频且不需要大量处理器能力的技术而开发。
可以使用MediaRecorder的setAudioEncoder方法,指定将要使用的音频编解码器。
1 recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
可以传递给setAudioEncoder的可能值定义为MediaRecorder.AudioEncoder中的常量。
MediaRecorder.AudioEncoder仅包含两个常量:
AMR_NB:这个值指定将用于音频编码的音频编解码器是AMR-NB,其表示自适应多速率窄带。AMR_NB是针对话音优化的编解码器,广泛用于移动电话。
DEFAULT:由于AMR_NB是唯一其他的选择,DEFAULT常量指定将使用的音频编解码器是AMR_NB。
4.音频和视频比特率
可以使用MediaRecorder的setVideoEncodingBitRate方法设置视频编码的比特率,并传入请求的比特率,以位/秒为单位。视频的低比特率设置在256000位/秒(256kbps)范围内,而高比特率视频在3000000位/秒(3mbps)范围内。
1 recorder.setVideoEncodingBitRate(150000);
还可以指定用来编码音频数据的最大比特率。为此,可以将该值以位/秒为单位传入MediaRecorder上的setAudioEncodingBitRate方法。作为参考,8000位/秒(8kbps)是一个非常低的比特率,适合于需要在慢速网络上实时传输的音频;而196000位/秒(196kbps)和更高的比特率在MP3文件的音乐中很常见。目前大多数的Android设备只支持低端的比特率,以避免选择一个过高的比特率。
1 recorder.setAudioEncodingBitRate(8000);
5.音频采样率
与比特率一样,音频采样率对于确定要捕获和编码的音频质量也非常重要。MediaPlayer有一个setAudioSamplingRate方法,用于请求特定的采样率。传入的采样率以Hz(赫兹)为单位,其表示每秒钟采样的数量。采样率越高,则在捕获文件中可以表示的音频频率的范围越大。一个低端的采样率8000Hz适合于捕获低质量的声音;而高端的采样率48000Hz可用于DVD和许多其他高质量的视频格式。大多数Android设备只支持范围的采样率(8000Hz)
1 recorder.setAudioSamplingRate(8000);
6.音频通道
可以通过使用setAudioChannels方法并传入通道的数量来指定将要捕获的音频通道的数量。目前,传入的音频大都限制为大多数Android设备上的单一通道麦克风,因此使用一个以上的通道不会有益处。对于选择要使用的通道数量,一般是单声道为一个通道,而立体声为两个通道。
1 recorder.setAudioChannels(1);
7.视频帧速率
可以通过使用setVideoFrameRate并传入请求的帧速率来控制每秒钟捕获的视频帧数。每秒12~15帧之间的值通常足以表示运动。对于高端而言,电视是每秒30帧(实际上是29.97)。具体使用的实际帧速率将取决于设备的能力。
1 recorder.setVideoFrameRate(15);
8.视频大小
可以通过使用setVideoSize方法并传入表示宽度和高度像素的整数来控制捕获的视频的宽度和高度。标准大小的范围是176X144~640X480,许多设备甚至支持更高的分辨率。
1 recorder.setVideoSize(640, 480);
9.最大文件大小
通过以字节为单位将最大大小传递给setMaxFileSize方法,可以指定由MediaRecorder所捕获的文件的最大大小。
1 recorder.setMaxFileSize(10000000);//10MB
为了确定是否已达到最大文件大小,需要在活动中实现MediaRecorder.OnInfoListener,同时在MediaRecorder中注册它。然后将会调用onInfo方法,根据MediaRecorder.MEDIA_RECORDER_INFO_FILESIZE_REACHED常量检查其中的what参数。如果他们匹配,那么说明达到了最大文件大小。
根据文档说明MediaRecorder应该在达到最大文件大小时停止,但是再Android 2.2.1中这似乎不太可靠。但是,不存在可以检查它是否已经停止的方法。为了实际停止录制,必须显示的调用stop方法。
下面以一些非常简短的代码进行补充。
1 public class VideoCapture extends Activity implements OnInfoListener { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 recorder.setOnInfoListener(this); 7 } 8 @Override 9 public void onInfo(MediaRecorder mr, int what, int extra) { 10 if(what==MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED){ 11 12 } 13 } 14 }
10.最长持续时间
通过一毫秒为单位将最长持续时间传递给setMaxDuration方法,可以指定由MediaRecorder所捕获的文件的最长持续时间。
1 recorder.setMaxDuration(50000);
为了确定是否已经达到了最长持续的时间,需要在活动中实现MediaRecorder.OnInfoListener,同时在MediaRecorder中注册它。然而当已经达到最长时间时就会触发onInfo方法,同时将what整数设置为常量MediaRecorder.MEDIA_RECORDER_INFO_MAX_DYRATION_REACHED。
根据文档的说明,MediaRecorder应该在达到最长持续时间时停止,但是再Android 2.2.1中这似乎不太可靠。但是,不存在可以检查它是否已经停止的方法。为了实际停止录制,必须显示的调用stop方法。
下面是简短的示例说明。
1 public class VideoCapture extends Activity implements OnInfoListener {
2
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 recorder.setOnInfoListener(this);
7 }
8 @Override
9 public void onInfo(MediaRecorder mr, int what, int extra) {
10 if(what==MediaRecorder.MEDIA_RECORDER_INFO_MAX_DYRATION_REACHED){
11
12 }
13 }
14 }
11.概要
从android 2.2(API Level 8)开始,MediaRecorder有一个setProfile方法,其接受一个CamcorderProfile示例作为参数。CamcorderProfile有一个静态方法CamcorderProfile.get,它接受一个整数参数,其可能的值定义为常量CamcorderProfile.QUALITY_HIGH或CamcorderProfile.QUALITY_LOW。使用这个方法将允许根据预设值设置整个配置变量集合。当然,QUALITY_HIGH是指高质量视频捕获设置,而QUALITY_LOW是指低质量视频捕获设置。
QUALITY_HIGH包含下列设置:
音频比特率:12200位/秒
音频通道:1
音频编解码器:AMR-NB
音频采样率:8000Hz
持续时间:60秒
文件格式:MP4
视频比特率:3000000位/秒
视频编解码器:H.264
视频帧宽度:720像素
视频帧高度:480像素
视频帧速率:24帧/秒
需要注意的是,正如前面所描述的那样,虽然许多设置是最大值或请求的值,但是设备的能力将决定最终的结果。例如,在运行Android 2.2.1 的Nexus 1上,使用QUALITY_HIGH设置捕获的一个示例视频时每秒12.6帧,总的比特率是1617.34kb/秒。
以下是QUALITY_LOW设置:
音频比特率:12200位/秒
音频通道:1
音频编解码器:AMR-NB
音频采样率:8000Hz
持续时间:30秒
文件格式:3GPP
视频比特率:256000位/秒
视频编解码器:H.263
视频帧宽度:176像素
视频帧高度:144像素
视频帧速率:15帧/秒
与QUALITY_HIGH版本一样,这些设置同样会产生略有不同的结果。捕获的结果视频时每秒16.06帧,比特率是207.96kb/秒。
12.输出文件
紧随其后将设置输出的位置。可以传入一个FileDescriptor或一个表示文件路径的字符串。
1 recorder.setOutputFile(Environment.getExternalStorageDirectory()+"/test.mp4");
13.预览表面
在继续操作之前,需要为MediaRecorder指定一个表面(取景器)以预览要绘制的图像。可以采用在第2章定制摄像头示例中处理预览图像的类似的方法来处理该操作。
接下来看一个简短的示例。首先,在布局中创建一个表面。
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:orientation="vertical" 5 > 6 <SurfaceView 7 android:id="@+id/CameraView" 8 android:layout_width="640px" 9 android:layout_height="480px"/> 10 </LinearLayout>
在活动中需要实现SurfaceHolder.Callback,从而在创建、更改或销毁表面时获得通知。
1 ... 2 public class VideoCapture extends Activity implements SurfaceHolder.Callback{ 3 private MediaRecorder recorder; 4 private SurfaceHolder holder; 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 recorder=new MediaRecorder();
在代码的这个位置中,应该执行MediaRecorder对象的所有正常设置,如设置音频和视频源、输出文件的位置灯。我们先将这些设置放在一边,这个代码片段仅仅是演示如何使用表面。
1 setContentView(R.layout.videocapture);
在设置内容视图之后,可以获得一个指向SurfaceView的引用和一个指向其SurfaceHolder的引用。
1 SurfaceView cameraView=(SurfaceView) findViewById(R.id.CameraView); 2 holder=cameraView.getHolder();
我们将添加活动作为其SurfaceHolder.Callback实现器。
1 holder.addCallback(this);
如同第2章的摄像头示例一样,预览表面的缓冲区将由Camera对象在外部管理,该对象时MediaRecorder的基础;因此,需要设置其类型为SURFACE_TYPE_PUSH_BUFFERS。
1 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 2 }
因为活动已经实现并注册为SurfaceHolder.Callback,所以当实际创建表面时将调用surfaceCreated方法。当发生这个事情时,可以通过setPreviewDisplay方法将表面设置为MediaRecorder对象的预览显示。但是,不能在创建表面之前这么做。
1 @Override 2 public void surfaceCreated(SurfaceHolder holder) { 3 recorder.setPreviewDisplay(holder.getSurface()); 4 }
由于实现了SurfaceHolder.Callback,因此还必须有surfaceChanged和surfaceDestroyed方法,他们根据调用的时间而得名:当表面发生更改时调用surfaceChanged,例如它的高度和宽度发生了变化;当表明不再使用时调用surfaceDestroyed,例如当活动不再可见时。
当调用surfaceDestroyed时应该停止录制视频,因为只有当表面可用来在其上绘制预览图像时,录制才能正常工作。
1 @Override 2 public void surfaceChanged(SurfaceHolder holder, int format, int width, 3 int height) { 4 5 } 6 @Override 7 public void surfaceDestroyed(SurfaceHolder holder) { 8 recorder.stop(); 9 } 10 }
14.准备录制
一旦设置了所有的MediaRecorder设置,就准备好使用prepare方法。该方法是必须的,其执行所有的内部函数,使得MediaRecorder准备好录制。
1 recorder.prepare();
15.开始录制
在MediaRecorder已经“准备好”之后就准备开始录制。start方法就完成该工作——它开始录制。
1 recorder.start();
16.停止录制
在录制已经开始之后,可以通过调用stop方法来停止它。
1 recorder.stop();
17.释放资源
最后,一旦完成了MediaRecorder的使用,就应该调用release方法来释放它的资源。这是非常重要的工作,因为每次只有一个应用程序可以使用很多底层资源。例如硬件摄像头和麦克风等。
1 recorder.release();
18.状态机
正如刚才所描述的那样,与MediaPlayer对象一样,MediaRecorder有不同的状态。同时只有在处于适当的状态时才会调用特定的方法。
19.权限
为了使用MediaRecorder捕获音频和视频,并将其保存到SD卡上的文件中,需要在AndroidManifest.xml文件中设置下列权限。
1 <uses-permission android:name="android.permission.CAMERA"/> 2 <uses-permission android:name="android.permission.RECORD_AUDIO"/> 3 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
posted on 2014-09-06 11:48 宁静致远,一览众山小 阅读(654) 评论(0) 编辑 收藏 举报