1 视频播放
1.1 支持的视频格式
3GP(.3gp)和MPEG-4(.mp4),其中3GP是源自MPEG-4的视频标准,专门用于移动设备。Android支持H.263编解码器,这时一种旨在用于低延迟和低比特率视频会议应用程序的编解码器,MPEG-4和3GP文件都支持H.263视频,MPEG-4还支持H.264编解码器。
1.2 视频播放的基本使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- MediaController设置播放使用 -->
<LinearLayout
android:id="@+id/media_root_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="300dp" />
</LinearLayout>
<Button
android:id="@+id/btn_record_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="录制视频" />
<Button
android:id="@+id/btn_stop_record_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="停止录制视频" />
<Button
android:id="@+id/btn_play_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="播放视频" />
</LinearLayout>
package com.example.media.video;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.Toast;
import com.example.media.R;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* 简单录像功能
*/
public class SimpleRecordActivity extends AppCompatActivity implements SurfaceHolder.Callback,
MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener,
MediaPlayer.OnSeekCompleteListener, MediaPlayer.OnVideoSizeChangedListener, MediaPlayer.OnInfoListener,
MediaController.MediaPlayerControl {
private static final String TAG = SimpleRecordActivity.class.getSimpleName();
private Button mBtnRecordVideo;
private Button mBtnStopRecordVideo;
private Button mBtnPlayVideo;
private SurfaceHolder mSurfaceHolder;
private MediaRecorder mMediaRecorder;
private Camera mCamera;
private MediaPlayer mMediaPlayer;
private MediaController mMediaController;
private String mRecordFilePath;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_record);
SurfaceView surfaceView = findViewById(R.id.surface_view);
mSurfaceHolder = surfaceView.getHolder();
mSurfaceHolder.addCallback(this);
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 必须设置
surfaceView.setFocusable(true);
surfaceView.setClickable(true);
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mMediaController != null) {
if (mMediaController.isShowing()) {
mMediaController.hide();
} else {
mMediaController.show();
}
}
}
});
mMediaController = new MediaController(this);
mBtnRecordVideo = findViewById(R.id.btn_record_video);
mBtnStopRecordVideo = findViewById(R.id.btn_stop_record_video);
mBtnPlayVideo = findViewById(R.id.btn_play_video);
// 开始录像
mBtnRecordVideo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!isSupportCamera()) {
Toast.makeText(SimpleRecordActivity.this, "不支持录像功能", Toast.LENGTH_SHORT).show();
return;
}
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(SimpleRecordActivity.this, "请插入sd卡", Toast.LENGTH_SHORT).show();
return;
}
mBtnRecordVideo.setEnabled(false);
mBtnStopRecordVideo.setEnabled(true);
try {
mMediaRecorder = new MediaRecorder();
// 设置录像源(在setOutputFormat()之前设置)
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); // 音频源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 视频源
// 设置录制视频格式
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 设置录像编码(在setOutputFormat()之后设置)
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
// 设置录像参数(视频质量相关)
mMediaRecorder.setVideoSize(640, 480); // 设置视频分辨率
mMediaRecorder.setVideoFrameRate(30); // 设置视频帧率,1秒30帧
mMediaRecorder.setVideoEncodingBitRate(3 * 1024 * 1024); // 设置视频编码流,值越大,视频越清晰,当然视频越大
mMediaRecorder.setOrientationHint(90);
mMediaRecorder.setMaxDuration(30 * 1000); // 设置录制最大时长为30秒
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mRecordFilePath = getRecordFilePath();
if (mRecordFilePath != null) {
mMediaRecorder.setOutputFile(mRecordFilePath);
mMediaRecorder.prepare();
mMediaRecorder.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
// 停止录像
mBtnStopRecordVideo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBtnRecordVideo.setEnabled(true);
mBtnStopRecordVideo.setEnabled(false);
mBtnPlayVideo.setEnabled(true);
releaseMediaRecorder();
}
});
// 播放
mBtnPlayVideo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
if (mRecordFilePath == null) {
return;
}
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(mRecordFilePath);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDisplay(mSurfaceHolder); // 在SurfaceView播放录制的视频
mMediaPlayer.setOnCompletionListener(SimpleRecordActivity.this);
mMediaPlayer.setOnErrorListener(SimpleRecordActivity.this);
mMediaPlayer.setOnVideoSizeChangedListener(SimpleRecordActivity.this);
mMediaPlayer.setOnInfoListener(SimpleRecordActivity.this);
mMediaPlayer.setOnSeekCompleteListener(SimpleRecordActivity.this);
mMediaPlayer.setOnVideoSizeChangedListener(SimpleRecordActivity.this);
mMediaPlayer.prepare();
// 在MediaPlayer准备完毕后设置MediaController控制
mMediaController.setMediaPlayer(SimpleRecordActivity.this);
mMediaController.setAnchorView(findViewById(R.id.media_root_view));
mMediaController.setEnabled(true);
mMediaController.show();
mMediaPlayer.start();
mBtnRecordVideo.setEnabled(false);
mBtnStopRecordVideo.setEnabled(false);
mBtnPlayVideo.setEnabled(false);
} catch (Exception e) {
e.printStackTrace();
}
}
});
mBtnRecordVideo.setEnabled(true);
mBtnStopRecordVideo.setEnabled(false);
mBtnPlayVideo.setEnabled(false);
}
private boolean isSupportCamera() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
@Override
protected void onDestroy() {
releaseMediaRecorder();
releaseMediaPlayer();
releaseCamera();
removeRecordFile();
super.onDestroy();
}
private String getRecordFilePath() {
// Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
// 保存应用程序相关联的图片和视频的标准位置,如果应用程序卸载,保存在此位置的媒体文件会被删除
// 保存图片和视频标准、共享和推荐位置,可以让其他程序轻松发现、读取、更改、删除保存在此的文件
// 用户卸载了应用程序,不会删除保存到此位置的媒体文件
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return null;
}
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"record");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.i(TAG, "failed to create directory");
return null;
}
}
String recordPath = mediaStorageDir.getPath() + File.separator + "record"
+ new SimpleDateFormat("yyyyMMddhhmmss", Locale.CHINA).format(new Date()) + ".mp4";
Log.i(TAG, "record path = " + recordPath);
return recordPath;
}
// SurfaceView创建时回调
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
Log.i(TAG, "surfaceCreated");
// 目前录制时摄像头会自动变为横屏,播放时是正常的竖屏播放
try {
mCamera = Camera.open();
mCamera.setDisplayOrientation(90); // 竖屏录制 仅支持0 90 180 270四个角度
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
// SurfaceView的底层宽高或参数发生改变时回调
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
Log.i(TAG, "surfaceChanged");
if (mCamera != null) {
try {
mCamera.stopPreview();
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
}
// SurfaceView销毁时回调
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
Log.i(TAG, "surfaceDestroyed");
removeRecordFile();
finish();
}
// MediaPlayer播放完毕时回调
@Override
public void onCompletion(MediaPlayer mp) {
Log.i(TAG, "onCompletion");
releaseMediaPlayer();
mBtnRecordVideo.setEnabled(true);
mBtnPlayVideo.setEnabled(true);
}
// MediaPlayer播放错误时回调,如果同时实现了OnCompletionListener也会回调,此时调用reset()进行重置处理
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.i(TAG, "onError");
if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
Log.v(TAG, "media error server died " + extra);
} else if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN) {
Log.v(TAG, "media error unknown = " + extra);
}
mBtnPlayVideo.setEnabled(true);
mBtnPlayVideo.setEnabled(true);
return false; // 返回false不处理错误
}
// MediaPlayer准备完毕时回调
@Override
public void onPrepared(MediaPlayer mp) {
Log.i(TAG, "onPrepared");
}
// MediaPlayer播放进度完毕时回调
@Override
public void onSeekComplete(MediaPlayer mp) {
Log.i(TAG, "onSeekComplete");
}
// MediaPlayer大小发生改变时回调;同时,当指定数据源和读取视频的元数据后将至少调用它一次
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
Log.i(TAG, "onVideoSizeChanged");
}
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
Log.i(TAG, "onInfo");
// 当出现关于播放媒体的特定信息或者需要发出警告时
if (what == MediaPlayer.MEDIA_INFO_BAD_INTERLEAVING) {
Log.v(TAG, "media info bad interleaving " + extra);
}
// 当媒体不能正确地定位时
else if (what == MediaPlayer.MEDIA_INFO_NOT_SEEKABLE) {
Log.v(TAG, "media info not seekable " + extra);
}
// 未知错误
else if (what == MediaPlayer.MEDIA_INFO_UNKNOWN) {
Log.v(TAG, "media info unknown " + extra);
}
// 当设备无法播放视频时将触发如下操作。这可能是将要播放视频,但是该视频太复杂或者码率过高
else if (what == MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING) {
Log.v(TAG, "media info video track lagging " + extra);
}
// 当新的元数据可用时
else if (what == MediaPlayer.MEDIA_INFO_METADATA_UPDATE) {
Log.v(TAG, "media info metadata update " + extra);
}
return false;
}
// MediaController点击开始时回调
@Override
public void start() {
if (mMediaPlayer != null) {
mMediaPlayer.start();
}
}
// MediaController点击暂停时回调
@Override
public void pause() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
}
}
// MediaController获取视频时长
@Override
public int getDuration() {
return mMediaPlayer != null ? mMediaPlayer.getDuration() : 0;
}
// MediaController获取当前视频播放位置
@Override
public int getCurrentPosition() {
return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0;
}
// MediaController进度条滑动时回调
@Override
public void seekTo(int pos) {
if (mMediaPlayer != null) {
mMediaPlayer.seekTo(pos);
}
}
// MediaController判断是否在播放
@Override
public boolean isPlaying() {
return mMediaPlayer != null && mMediaPlayer.isPlaying();
}
// MediaController获取缓冲百分比
@Override
public int getBufferPercentage() {
return 0;
}
// MediaController是否可暂停
@Override
public boolean canPause() {
return true;
}
// MediaController进度条回放
@Override
public boolean canSeekBackward() {
return true;
}
// MediaController进度条快进
@Override
public boolean canSeekForward() {
return true;
}
// MediaController获取音频SessionId
@Override
public int getAudioSessionId() {
return 0;
}
private void releaseMediaRecorder() {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
}
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.lock(); // 锁定摄像头给其他应用使用
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
private void releaseMediaPlayer() {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
private void removeRecordFile() {
if (mRecordFilePath != null) {
if (new File(mRecordFilePath).delete()) {
Log.v(TAG, "record file is deleted");
}
}
}
}
2 网络视频
2.1 支持的网络视频类型
- HTTP
由于HTTP在网络上得到了广泛的支持,通常不会遭遇与其他流式协议一样的防火墙问题,因此大量的媒体以这种方式可用。通过HTTP传输的媒体通常以称为累进式的方式下载。Android支持MPEG-4和3GP文件中的点播媒体,这些文件通过HTTP从标准Web服务器上传输。
当准备通过累进式下载传输视频时,需要铭记几件事情:
必须使用编解码器及Android支持的格式对媒体进行编码。
视频的比特率应在携带视频的网络所能够传输的范围之内。
例如,GPRS的带宽可能会低到20kbps,因此在编码音频和视频时应该考虑到这一点。一般而言,当通过HTTP传输时,媒体将在设备上缓冲,当已经下载了足够的内容时才开始播放,此时应该能够播放到文件结束,而不用停顿下来等待下载更多的媒体。如果媒体的传输只有20kbps,而媒体以400kbps的比特率编码,那么这意味着对于每秒钟的视频,用户必须持续下载20秒。这可能不会很理想。
然而,如果用户在WiFi上传输,那么400kbps可能会比较好,与编码成20kbps的视频相比,它将提供效果更佳的视频。一般而言,待使用的网络速度必须根据视频的质量进行权衡。使用HTTP累进式下载的优势在于:媒体不必与RTSP一样实时传输。
为了在视频正在下载时播放它,必须以允许这么做的方式对它进行编码。具体而言,这意味着结果文件应该在文件的开头包含称为“moov原子”的内容。“moov原子”包含一个关于文件内容及组织方式的索引。为了使视频播放软件能够开始播放该视频,它需要知道这个信息。如果“moov原子”位于文件的末尾,那么播放软件只有在下载整个文件之后才能启动播放,因此此时它才可以得到“moov原子”。
- RTSP
RTSP是指实时流协议(Real Time Streaming Protocol),从技术上讲,它不是一个媒体传输协议,相反,它是一个用于支持媒体传输的控制协议。在Android中通过RTSP支持的媒体传输形式是RTP(实时传输协议,Real Time Transport Protocol),但是它只有在与RTSP一起使用时才有效。换句话说,Android上的RTP不能独立于RTSP工作。
RTSP和RTP是特定于实时数据流的。这完全不同于HTTP累进式下载,因为它可以在通过网络接收媒体时对其进行播放。
当准备用RTSP传输媒体时,需要铭记几件事情:
-
需要使用编解码器及Android支持的格式对媒体进行编码,并且其可以通过RTSP服务器流媒体化。虽然支持其他的编解码器(H.264)和容器(MP4),但是一般会将移动设备的流媒体编码为在3GP容器中的MP4视频和AAC音频。
-
媒体的比特率必须可以实时传输给最终用户,这取决于用户的网络连接。根据网络类型,这些速度会有很大的不同。第二代网络(GPRS)提供的数据速度最高在50~100kbps的范围之内。为了将视频编码成可在这种类型的网络上实时地传输,需要将视频编码在30kbps的范围以内,以考虑额外系统开销和不同的连接质量。向上升级到EDGE网络将允许在50kbps的范围内可靠地传输视频,当前3G网络的保守比特率将在100kbps的范围内,而许多网络能够支持显著较高的比特率。
2.2 在加载网络视频时获取缓冲信息
MediaPlayer.OnBufferingUpdateListener接口在处理网络传输的媒体时特别有用,onBufferingUpdate(MediaPlayer mp, int
bufferedPercent),当缓冲媒体时会重复调用该方法,从而能够跟踪缓冲区的填充程度。
2.3 视频捕获(MediaRecorder,设置音频相关的请查看音频文档)
使用MediaRecorder捕获视频步骤如下(每步调用的执行顺序不同对结果影响非常大):
-
创建MediaRecorder实例
-
设置音频源和视频源
MediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT)
- 设置输出格式
MediaRecorder.setOutputFormat(MediaRecorder.OutputFormat. DEFAULT)
- 设置音频和视频编码器
MediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
- 设置输出文件
MediaRecorder.setOutputFile(filePath)
- 准备录制
MediaRecorder.prepare()
- 开始录制
MediaRecorder.start()
- 重置/停止
MediaRecorder.reset()/MediaRecorder.stop()
- 释放资源
MediaRecorder.release()
视频源:
-
CAMERA:使用摄像头录制视频
-
DEFAULT:使用摄像头录制视频
输出格式:
-
DEFAULT:指定使用默认的输出格式。默认的输出格式可能会根据设备的不同而有所区别。
-
MPEG-4:指定音频和视频将捕获到一个MPEG-4文件格式的文件中。这个文件是一个.mp4文件。MPEG-4文件通常包含H.264、H.263或MPEG-4 Part 2编码的视频,以及AAC或MP3编码的音频。
-
RAW_AMR:此设置仅用于音频录制,而不用于视频。
-
THREE_GPP:指定音频和视频将被捕获到一个3GP文件格式的文件中。这个文件将是一个.3gp文件。3GP文件通常包含使用H.264、MPEG-4 Part 2或H.263编解码器编码的视频和使用AMR或AAC编解码器编码的音频。
视频编解码器:
-
DEFAULT:这时一个设备相关的设置,指定使用设备的默认编解码器。在大多数情况下是H.263,因为它是Android上唯一必须
支持的编解码器。 -
H263:这个值指定使用的编解码器是H.263。H.263是在1995年发布的编解码器,专门为低比特率视频传输而开发。
-
H264:这个值指定使用的编解码器是H.264(它还被命名为MPEG-4 Part 10或AVC(高级视频编码))。H.264是当前最先进的编解码器,它在2003年发布。大多数Android设备支持使用这种编解码器进行视频播放,而小部分设备使用它进行视频编码。
-
MPEG_4_SP:这个值指定使用的编解码器是MPEG-4 SP(Simple Profile,简单配置)编解码器。从技术上讲,MPEG-4 SP是MPEG-4 Part 2 Simple Profile。它在1999年发布,为需要低比特率视频且不需要大量处理器能力的技术而开发。
音频和视频比特率:
MediaRecorder.setVideoEncodingBitRate(150000);
MediaRecorder.setAudioEncodingBitRate(8000);
比特率以位/秒为单位。视频的低比特率设置在256000位/秒(256kbps)范围之内,而高比特率视频在3000000位/秒(3mbps)范围之内。
8000位/秒(8kbps)是一个非常低的比特率,适合于需要在慢速网络上实时传输的音频;196000位/秒(196kbps)和更高的比特率在MP3文件的音乐中很常见。目前大多数Android设备只支持低端的比特率。
音频采样率:
MediaRecorder.setAudioSampleRate(8000);
传入的采样率以Hz为单位,其标识每秒采样的数量。采样率越高,则在捕获文件中可以表示的音频频率的范围越大。一个低端
的采样率8000Hz适合于捕获低质量的声音;而高端的采样率48000Hz可用于DVD和许多其他高质量的视频格式。大多数Android
设备只支持低范围的采样率(8000Hz)。
音频通道:
MediaRecorder.setAudioChannels(1);
传入通道数量指定捕获的音频通道数量,传入的音频大多数限制为单一通道麦克风,因此使用一个以上的通道不会有益处。对
于选择要使用的通道数量,一般是单声道为一个通道,而立体声为两个通道。
视频帧速率:
MediaRecorder.setVideoFrameRate(15);
传入请求的帧速率来控制每秒钟捕获的视频帧数。每秒12~15帧之间的值通常足以表示运动。对于高端而言,电视是每秒30帧。
具体使用的实际帧速率将取决于设备的能力。
视频大小:
MediaRecorder.setVideoSize(640, 480);
传入标识宽度和高度像素的整数来控制捕获的视频宽度和高度。标准大小的范围是176 x 144 ~ 640 x 480,许多设备甚至支持更
高的分辨率。
最大文件大小:
MediaRecorder.setMaxFileSize(10000000);//10MB
以字节为单位将设置最大文件大小。可以通过实现MediaRecorder.OnInfoListener的OnInfo(MediaRecorder mr, int what, int extra)判断标志what == MediaRecorder.RECORDER_INFO_FILESIZE_REACHED检查,达到最大文件大小时应该显示调用
MediaRecorder.stop()停止录制。
最长持续时间:
MediaRecorder.setMaxDuration(10 * 1000); // 10秒
以毫秒为单位设置最长持续时间。可以通过MediaRecorder.OnInfoListener的OnInfo(MediaRecorder mr, int what, int extra)判断标志what == MediaRecorder.MEDIA_RECORDER_INFO_DURATION_REACHED检查,达到最长持续时间应该显示调用
MediaRecoder.stop()停止录制。
概要
MediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
从Android.2.2开始,MediaRecorder有一个setProfile()方法,其接受一个CamcorderProfile实例作为参数。CamcorderProfile有一个静态方法CamcorderProfile.get(),它接受一个整数参数。使用该方法将允许根据预设值设置整个配置变量集合。
CamcorderProfile.QUALITY_HIGH:高质量视频捕获设置。相关配置如下:
-
音频比特率:12200位/秒
-
音频通道:1
-
音频编解码器:AMR-NB
-
音频采样率:8000Hz
-
持续时间:60秒
-
文件格式:MP4
-
视频比特率:3 000 000 位/秒
-
视频帧宽度:720像素
-
视频帧高度:480像素
-
视频帧速率:24帧/秒
CamcorderProfile.QUALITY_LOW:低质量视频捕获设置。相关配置如下:
-
音频比特率:12200位/秒
-
音频通道:1
-
音频编解码器:AMR-NB
-
音频采样率:8000Hz
-
持续时间:30秒
-
文件格式:3GPP
-
视频比特率:256 000 位/秒
-
视频帧宽度:176像素
-
视频帧高度:144像素
-
视频帧速率:15帧/秒