android MediaRecorder录制音视频实现直播的基础
工作这么久,一直都很忙,好不容易闲下来就不习惯了。突然觉得应该做点有意义的事情,这几天研究了一下视屏直播方面的知识,使用camara,surfaceview,MediaRecorder录制音视频,surfaceview提供camara的预览。好了废话不多说了首先了解api吧。
1.使用camara录制视频有两种方式:一是借助Intent和MediaStroe调用系统Camera App程序来实现拍照和摄像功能,二是根据Camera API自写Camera程序。
第一种使用系统录制视频的方法:
对mediaStore有兴趣的同学可以看一篇文章 http://www.xuebuyuan.com/2038576.html;
- Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
- //在这里的QUALITY参数,值为两个,一个是0,一个是1,代表录制视频的清晰程度,0最不清楚,1最清楚
- //没有0-1的中间值,另外,使用1也是比较占内存的,测试了一下,录制1分钟,大概内存是43M多
- //使用0,录制1分钟大概内存是几兆
- intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);
- // 限制时长 ,参数61代表61秒,可以根据需求自己调,最高应该是2个小时。
- //当在这里设置时长之后,录制到达时间,系统会自动保存视频,停止录制
- intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 61);
- // 限制大小 限制视频的大小,这里是100兆。当大小到达的时候,系统会自动停止录制
- intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 1024 * 1024 * 100);
- //在这里有录制完成之后的操作,系统会默认把视频放到照片的文件夹中
- startActivityForResult(intent, 11);
- 第二种调用camara的api的方法 本文中使用的是第二种方法
一。首先初始化camara
camara主要的几个api
open():通过open方法获取Camera实例。 CameraInfo.CAMERA_FACING_BACK//后置摄像头,CameraInfo.CAMERA_FACING_FRONT前置摄像头
setPreviewDisplay(SurfaceHolder):设置预览拍照mCamera.setPreviewCallback(null)//预览回调 停止预览
startPreview():开始预览
stopPreview():停止预览mCamera.lock();// 默认Camera都是锁定的
mCamera.unlock();解锁摄像头 camara默认是lock状态所以在camara初始化的时候一定要调用mCamera.lock();
release():释放Camera实例 记住,在应用程序使用完Camera对象后,一定要调用Camera.release()方法来释放Camera对象。mCamera.setParameters(params); 传入的是paramas对象 这里可以设置一些camara参数 // 设置旋转代码
params.setRotation(90); params.set("orientation", "portrait");//设置屏幕方向 params.setJpegQuality()//设置图像输出质量 params.setPictureFormat//设置图片输出格式 params.setPictureSize设置图片大小 params.setPreviewFormat设置图像预览格式 params.setPreviewSize设置预览画面大小上面调用系统Camera App,我们压根不需要任何权限,但是这里用Camera API,就必须在manifest内声明使用权限,通常由以下三项
<uses-permission android:name = "android.permission.CAMERA" />
<uses-feature android:name = "android.hardware.camera" />
<uses-feature android:name = "android.hardware.camera.autofocus" />
一般拍照和摄像的时候需要写到sd卡上,所以还有一向权限声明如下
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
真做摄像功能时,需要音频录制和视频录制功能,所以又需要下面两项权限声明
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
另外使用Camera API拍照或摄像,都需要用到预览,预览就要用到SurfaceView,为此Activity的布局中必须有SurfaceView。
二。接下来是surfaceview作为camara提供预览 这里介绍一下surfaceview的几个重要的API
SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,你可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制位置。surface是纵深排序(Z-ordered)的,说明它总在自己所在窗口的后面。SurfaceView提供了一个可见区域,只有在这个可见区域内的surface内容才可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么每次surface变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
SurfaceView默认使用双缓冲技术的,它支持在子线程中绘制图像,这样就不会阻塞主线程了,所以它更适合于游戏的开发。2. SurfaceView的使用
首先继承SurfaceView,并实现SurfaceHolder.Callback接口,实现它的三个方法:surfaceCreated,surfaceChanged,surfaceDestroyed。SurfaceView.getHolder();//获取surfaceholder对象为访问surface提供访问的接口 surface控制器,用来操纵surface
surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
还需要获得SurfaceHolder,并添加回调函数,这样这三个方法才会执行。- 三,mediarecoder
说明:
与MediaPlayer类非常相似MediaRecorder也有它自己的状态图。下面是关于MediaRecorder的各个状态的介绍:
Initial:初始状态,当使用new()方法创建一个MediaRecorder对象或者调用了reset()方法时,该MediaRecorder对象处于Initial状态。在设定视频源或者音频源之后将转换为Initialized状态。另外,在除Released状态外的其它状态通过调用reset()方法都可以使MediaRecorder进入该状态。
Initialized:已初始化状态,可以通过在Initial状态调用setAudioSource()或setVideoSource()方法进入该状态。在这个状态可以通过setOutputFormat()方法设置输出格式,此时MediaRecorder转换为DataSourceConfigured状态。另外,通过reset()方法进入Initial状态。
DataSourceConfigured:数据源配置状态,这期间可以设定编码方式、输出文件、屏幕旋转、预览显示等等。可以在Initialized状态通过setOutputFormat()方法进入该状态。另外,可以通过reset()方法回到Initial状态,或者通过prepare()方法到达Prepared状态。
Prepared:就绪状态,在DataSourceConfigured状态通过prepare()方法进入该状态。在这个状态可以通过start()进入录制状态。另外,可以通过reset()方法回到Initialized状态。
Recording:录制状态,可以在Prepared状态通过调用start()方法进入该状态。另外,它可以通过stop()方法或reset()方法回到Initial状态。
Released:释放状态(官方文档给出的词叫做Idle state 空闲状态),可以通过在Initial状态调用release()方法来进入这个状态,这时将会释放所有和MediaRecorder对象绑定的资源。
Error:错误状态,当错误发生的时候进入这个状态,它可以通过reset()方法进入Initial状态。
提示:与MediaPlayer相似使用MediaRecorder录音录像时需要严格遵守状态图说明中的函数调用先后顺序,在不同的状态调用不同的函数,否则会出现异常。
final static int
getAudioSourceMax()
获取音频源的最大值。
int
getMaxAmplitude()
获取在前一次调用此方法之后录音中出现的最大振幅。
void
prepare()
准备录制。
void
release()
释放资源。
void
reset()
将MediaRecorder设为空闲状态,即Initial状态。
void
setAudioChannels(int numChannels)
设置录制的音频通道数。
void
setAudioEncoder(int audio_encoder)
设置所录制的声音的编码格式。
void
setAudioEncodingBitRate(int bitRate)
设置所录制的声音的编码位率。
void
setAudioSamplingRate(int samplingRate)
设置所录制的声音的采样率。
void
setAudioSource(int audio_source)
设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。
void
setCamera(Camera c)
设置一个摄像头用于录制。
void
setCaptureRate(double fps)
设置视频帧捕获率。
void
setLocation(float latitude, float longitude)
设置并存储在输出文件中的地理数据(经度和纬度)。
void
setMaxDuration(int max_duration_ms)
设置录制会话的最长持续时间(以ms为单位)。
void
setMaxFileSize(long max_filesize_bytes)
设置录制文件的最大文件大小。
void
setOnErrorListener(MediaRecorder.OnErrorListener l)
注册一个用于记录录制时出现的错误的监听器。
void
setOnInfoListener(MediaRecorder.OnInfoListener listener)
注册一个用于记录录制时出现的信息事件。
void
setOrientationHint(int degrees)
设置输出的视频播放的方向提示。
void
setOutputFile(FileDescriptor fd)
设置录制的音频文件的保存位置。
void
setOutputFile(String path)
设置录制的音频文件的保存位置。
void
setOutputFormat(int output_format)
设置所录制的音视频文件的格式。
void
setPreviewDisplay(Surface sv)
设置使用哪个SurfaceView来显示视频预览。
void
setProfile(CamcorderProfile profile)
指定CamcorderProfile对象。
void
setVideoEncoder(int video_encoder)
设置所录制视频的编码格式。
void
setVideoEncodingBitRate(int bitRate)
设置所录制视频的编码位率。
void
setVideoFrameRate(int rate)
设置录制视频的捕获帧速率。
void
setVideoSize(int width, int height)
设置要拍摄的宽度和视频的高度。
void
setVideoSource(int video_source)
设置用于录制的视频来源。
void
start()
开始录制。
void
stop()
停止录制。
final static int
getAudioSourceMax()
获取音频源的最大值。
int
getMaxAmplitude()
获取在前一次调用此方法之后录音中出现的最大振幅。
void
prepare()
准备录制。
void
release()
释放资源。
void
reset()
将MediaRecorder设为空闲状态,即Initial状态。
void
setAudioChannels(int numChannels)
设置录制的音频通道数。
void
setAudioEncoder(int audio_encoder)
设置所录制的声音的编码格式。
void
setAudioEncodingBitRate(int bitRate)
设置所录制的声音的编码位率。
void
setAudioSamplingRate(int samplingRate)
设置所录制的声音的采样率。
void
setAudioSource(int audio_source)
设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。
void
setCamera(Camera c)
设置一个摄像头用于录制。
void
setCaptureRate(double fps)
设置视频帧捕获率。
void
setLocation(float latitude, float longitude)
设置并存储在输出文件中的地理数据(经度和纬度)。
void
setMaxDuration(int max_duration_ms)
设置录制会话的最长持续时间(以ms为单位)。
void
setMaxFileSize(long max_filesize_bytes)
设置录制文件的最大文件大小。
void
setOnErrorListener(MediaRecorder.OnErrorListener l)
注册一个用于记录录制时出现的错误的监听器。
void
setOnInfoListener(MediaRecorder.OnInfoListener listener)
注册一个用于记录录制时出现的信息事件。
void
setOrientationHint(int degrees)
设置输出的视频播放的方向提示。
void
setOutputFile(FileDescriptor fd)
设置录制的音频文件的保存位置。
void
setOutputFile(String path)
设置录制的音频文件的保存位置。
void
setOutputFormat(int output_format)
设置所录制的音视频文件的格式。
void
setPreviewDisplay(Surface sv)
设置使用哪个SurfaceView来显示视频预览。
void
setProfile(CamcorderProfile profile)
指定CamcorderProfile对象。
void
setVideoEncoder(int video_encoder)
设置所录制视频的编码格式。
void
setVideoEncodingBitRate(int bitRate)
设置所录制视频的编码位率。
void
setVideoFrameRate(int rate)
设置录制视频的捕获帧速率。
void
setVideoSize(int width, int height)
设置要拍摄的宽度和视频的高度。
void
setVideoSource(int video_source)
设置用于录制的视频来源。
void
start()
开始录制。
void
stop()
停止录制。
private int camaraBack=1;//1后置摄像头 0前置摄像头
private Camara camara;
public void initCamara(){
try {
if(camara!=null){//初始化释放摄像头资源
freeCameraResource();//
}
if (camaraBack=1) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 打开后置摄像头} else {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 打开前置摄像头}
} catch (Exception e) {
e.printStackTrace();
freeCameraResource();}
if (mCamera == null)
return;//设置摄像头参数
}
/**
* 设置摄像头为竖屏
*
* @author lip
* @date 2015-3-16
*/
private void setCameraParams() {
if (mCamera != null) {
Parameters params = mCamera.getParameters();
// 设置旋转代码
params.setRotation(90);
params.set("orientation", "portrait");mCamera.setParameters(params);
}
}/**
* 释放摄像头资源
*
* @author liuyinjun
* @date 2015-2-5
*/
private void freeCameraResource() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.lock();
mCamera.release();
mCamera = null;
}
}}
完整代码
/**
* 视频录制控件
*
* @author lip
*
* @date 2015-3-16
*/
public class MovieRecorderView extends LinearLayout implements OnErrorListener,
OnInfoListener {private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private ProgressBar mProgressBar;private MediaRecorder mMediaRecorder;
private Camera mCamera;
private Timer mTimer;// 计时器
private OnRecordFinishListener mOnRecordFinishListener;// 录制完成回调接口private int mWidth;// 视频分辨率宽度
private int mHeight;// 视频分辨率高度
private boolean isOpenCamera;// 是否一开始就打开摄像头
private int mRecordMaxTime;// 一次拍摄最长时间
private int mTimeCount;// 时间计数
private File mVecordFile = null;// 文件
private boolean isCameraBack = false;
private Context context;
/** 滤镜枚举值 */
private final static String[] FILTER_VALUES = new String[] {
MediaRecorderFilter.CAMERA_FILTER_NO,
MediaRecorderFilter.CAMERA_FILTER_BLACKWHITE,
MediaRecorderFilter.CAMERA_FILTER_SHARPEN,
MediaRecorderFilter.CAMERA_FILTER_OLD_PHOTOS,
MediaRecorderFilter.CAMERA_FILTER_NEON_LIGHT,
MediaRecorderFilter.CAMERA_FILTER_ANTICOLOR,
MediaRecorderFilter.CAMERA_FILTER_PASS_THROUGH,
MediaRecorderFilter.CAMERA_FILTER_MOSAICS,
MediaRecorderFilter.CAMERA_FILTER_REMINISCENCE };public void setOnRecordFinishListener(OnRecordFinishListener finishListener) {
this.mOnRecordFinishListener = finishListener;
}public MovieRecorderView(Context context) {
this(context, null);
this.context = context;}
public MovieRecorderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
mWidth = 320;
mHeight = 240;
isOpenCamera = true;
mRecordMaxTime = 10;LayoutInflater.from(context).inflate(R.layout.camara, this);
mSurfaceView = (SurfaceView) findViewById(R.id.sufaceView);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new CustomCallBack());
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);}
/**
*
* @author liuyinjun
*
* @date 2015-2-5
*/
private class CustomCallBack implements Callback {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!isOpenCamera)
return;
try {
initCamera();} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (!isOpenCamera)
return;
freeCameraResource();}
}
/**
* 初始化摄像头
*
* @author lip
* @date 2015-3-16
* @throws IOException
*/
private void initCamera() throws IOException {
if (mCamera != null) {
freeCameraResource();
}
try {
if (!isCameraBack) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 打开摄像头} else {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 打开摄像头}
} catch (Exception e) {
e.printStackTrace();
freeCameraResource();
}
if (mCamera == null)
return;setCameraParams();
// 设置camera预览的角度,因为默认图片是倾斜90度的mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
mCamera.unlock();
}public void setCamara() {
if (mCamera == null)
return;setCameraParams();
// 设置camera预览的角度,因为默认图片是倾斜90度的mCamera.setDisplayOrientation(90);
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
mCamera.unlock();
}/**
* 设置摄像头为竖屏
*
* @author lip
* @date 2015-3-16
*/
private void setCameraParams() {
if (mCamera != null) {
Parameters params = mCamera.getParameters();
// 设置旋转代码
params.setRotation(90);
params.set("orientation", "portrait");mCamera.setParameters(params);
}
}/**
* 释放摄像头资源
*
* @author liuyinjun
* @date 2015-2-5
*/
private void freeCameraResource() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.lock();
mCamera.release();
mCamera = null;
}
}private void createRecordDir() {
// File sampleDir = new File(Environment.getExternalStorageDirectory() +
// File.separator + "im/video/");
File sampleDir = new File(Environment.getExternalStorageDirectory()
+ File.separator + "RecordVideo/");
// File sampleDir = new File("/video/");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
File vecordDir = sampleDir;
// 创建文件
try {
mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);// mp4格式
// LogUtils.i(mVecordFile.getAbsolutePath());
Log.d("Path:", mVecordFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}/**
* 初始化
*
* @author lip
* @date 2015-3-16
* @throws IOException
*/
private void initRecord() throws IOException {
initCamera();
mMediaRecorder = new MediaRecorder();mMediaRecorder.reset();
if (mCamera != null)
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setOnErrorListener(this);
mMediaRecorder.setOnInfoListener(this);
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 视频源
mMediaRecorder.setAudioSource(AudioSource.MIC);// 音频源
mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 视频输出格式
mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音频格式
mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
// mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);// 设置帧频率,然后就清晰了mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
// mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
// setSocket();
mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());try {
mMediaRecorder.prepare();
mMediaRecorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}private void setSocket() throws SocketException, IOException {
Socket socket = new Socket();
SocketAddress socAddress = new InetSocketAddress("", 100);
socket.setSoTimeout(10000);
// 关闭socket时,立即释放socket绑定端口以便端口重用,默认为false
socket.setReuseAddress(true);
// 关闭传输缓存,默认为false
socket.setTcpNoDelay(true);
// 设置socket保持存状态
socket.setKeepAlive(true);
// 关闭socket时,底层socket不会直接关闭,会延迟一会,直到发送完所有数据
// 等待10秒再关闭底层socket连接,0为立即关闭底层socket连接
socket.setSoLinger(true, 10);
// 设置性能参数,可设置任意整数,数值越大,相应的参数重要性越高(连接时间,延迟,带宽)
socket.setPerformancePreferences(3, 2, 1);
socket.connect(socAddress, 10000);
ParcelFileDescriptor descriptor = ParcelFileDescriptor
.fromSocket(socket);
mMediaRecorder.setOutputFile(descriptor.getFileDescriptor());InputStream inputStream = socket.getInputStream();
}
/**
* 开始录制视频
*
* @author liuyinjun
* @date 2015-2-5 // * @param fileName // * 视频储存位置
* @param onRecordFinishListener
* 达到指定时间之后回调接口
*/
public void record() {createRecordDir();
try {
if (!isOpenCamera)// 如果未打开摄像头,则打开
initCamera();
initRecord();
mTimeCount = 0;// 时间计数器重新赋值
mTimer = new Timer();
mTimer.schedule(new TimerTask() {@Override
public void run() {
// TODO Auto-generated method stub
mTimeCount++;
mProgressBar.setProgress(mTimeCount);// 设置进度条
String path = mVecordFile.getAbsolutePath();
FileInputStream fileInputStream = null;
byte[] bs = null;
int lenth = 0;
try {
fileInputStream = new FileInputStream(path);
bs = new byte[1024];
try {
lenth = fileInputStream.read(bs);
Log.i("________lenth+", "" + lenth);} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
stop();
Log.i("________stop+", "" + lenth);
if (mOnRecordFinishListener != null)
mOnRecordFinishListener.onRecordFinish();
}
}
}, 0, 1000);
} catch (IOException e) {
e.printStackTrace();
}
}/**
* 停止拍摄
*
* @author liuyinjun
* @date 2015-2-5
*/
public void stop() {
stopRecord();
releaseRecord();
freeCameraResource();
}/**
* 停止录制
*
* @author liuyinjun
* @date 2015-2-5
*/
public void stopRecord() {
mProgressBar.setProgress(0);
if (mTimer != null)
mTimer.cancel();
if (mMediaRecorder != null) {
// 设置后不会崩
mMediaRecorder.setOnErrorListener(null);
mMediaRecorder.setPreviewDisplay(null);
try {mMediaRecorder.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}/**
* 释放资源
*
* @author liuyinjun
* @date 2015-2-5
*/
private void releaseRecord() {
if (mMediaRecorder != null) {
mMediaRecorder.setOnErrorListener(null);
try {
mMediaRecorder.release();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
mMediaRecorder = null;
}public int getTimeCount() {
return mTimeCount;
}/**
* @return the mVecordFile
*/
public File getmVecordFile() {
return mVecordFile;
}/**
* 录制完成回调接口
*
* @author lip
*
* @date 2015-3-16
*/
public interface OnRecordFinishListener {
public void onRecordFinish();
}@Override
public void onError(MediaRecorder mr, int what, int extra) {
try {
if (mr != null)
mr.reset();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}private int position = 0;
/**
* 切换摄像头
*/
public void backCamera() {
if (!isCameraBack) {
isCameraBack = false;
} else {
isCameraBack = true;
}Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
position = Camera.getNumberOfCameras();for (int i = 0; i < position; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
freeCameraResource();
mCamera = Camera.open(i);
// deal(mCamera);
setCamara();
}
}}
public void fronCamera() {
if (!isCameraBack) {
isCameraBack = false;
} else {
isCameraBack = true;
}
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
position = Camera.getNumberOfCameras();
for (int i = 0; i < position; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
freeCameraResource();
mCamera = Camera.open(i);
setCamara();
// deal(mCamera);
}
}}
public Camera deal(Camera camera) {
// 设置camera预览的角度,因为默认图片是倾斜90度的
camera.setDisplayOrientation(90);Size pictureSize = null;
Size previewSize = null;
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewFrameRate(5);
// 设置旋转代码
parameters.setRotation(90);
// parameters.setPictureFormat(PixelFormat.JPEG);List<Size> supportedPictureSizes = SupportedSizesReflect
.getSupportedPictureSizes(parameters);// 获取手机支持的视屏分辨率大小集合
List<Size> supportedPreviewSizes = SupportedSizesReflect
.getSupportedPreviewSizes(parameters);if (supportedPictureSizes != null && supportedPreviewSizes != null
&& supportedPictureSizes.size() > 0
&& supportedPreviewSizes.size() > 0) {// 2.x
pictureSize = supportedPictureSizes.get(0);int maxSize = 1280;
if (maxSize > 0) {
for (Size size : supportedPictureSizes) {
if (maxSize >= Math.max(size.width, size.height)) {
pictureSize = size;
break;
}
}
}WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);previewSize = getOptimalPreviewSize(supportedPreviewSizes,
display.getWidth(), display.getHeight());parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPreviewSize(previewSize.width, previewSize.height);}
camera.setParameters(parameters);
return camera;
}private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;Size optimalSize = null;
double minDiff = Double.MAX_VALUE;int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
switch (what) {
case MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN:// 错误未知break;
case MediaRecorder.MEDIA_ERROR_SERVER_DIED:// 服务器链接失败break;
case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:// 记录信息的最大持续时间达到
stop();break;
case MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED:// 储信息达到最大文件大小break;
default:
break;
}}
// public void setCamaraFilter(int position) {
// FILTER_VALUES[position];
// }
}
android MediaRecorder录制音视频实现直播的基础相关推荐
- Android -- MediaRecorder录制短视频
一.权限 AndroidManifest.xml: <uses-permission android:name="android.permission.WRITE_EXTERNAL_S ...
- Android MediaRecorder录制视频音量小问题解决 (音视频转码合成)
之前写得太乱,回头看看感觉自己都有点看不懂,重新写下. 在android上需要做一个录像留言功能,需要生成MP4或者waw格式视频.但是使用MediaRecorder录制出的MP4视频格式音量太小,几 ...
- Android音视频点/直播模块开发
前言 随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能,那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式 ...
- Android音视频点/直播模块开发实践总结-zz
随着音视频领域的火热,在很多领域(教育,游戏,娱乐,体育,跑步,餐饮,音乐等)尝试做音视频直播/点播功能.那么作为开发一个小白,如何快速学习音视频基础知识,了解音视频编解码的传输协议,编解码方式,以及 ...
- android音/视频,直播
流媒体 采用流式传输的方式在Internet / Intranet播放的媒体格式.流媒体的数据流随时传送随 时播放,只是在开始时有些延迟.边下载边播入的流式传输方式不仅使启动延时大幅度地缩短,而且对系 ...
- 安卓Android中腾讯音视频和直播 API的使用
安卓Android中腾讯音视频和直播 API的使用 文章目录 安卓Android中腾讯音视频和直播 API的使用 前言:安卓Android中腾讯音视频和直播 API的使用,这里没有写UI,功能是放在一 ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译者: ...
- C# ffmpeg 录制音视频
最近研究用ffmpeg录制桌面视频,以下是研究时碰到的问题以及成果记录下. FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开源计算机程序.采用LGPL或GPL许可证.它提供了录 ...
- Android IOS WebRTC 音视频开发总结(六五)-- 给韩国电信巨头做咨询
Android IOS WebRTC 音视频开发总结(六五)-- 给韩国电信巨头做咨询 本文主要总结咨询过程中的一些问题,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号blackert ...
最新文章
- 继国务院后,上海也发布人工智能发展意见,2020年产业规模超千亿
- 防火墙技术指标---并发连接数/吞吐量
- ElasticSearch 知识点整理(入门)
- javascript的Foreach语法
- otl oracle存储过程,OTL调用存储过程/函数及注意事项
- Java中Jsp和Servlet上传和下载文件
- 英特尓祭出开挖数据价值的“六脉神剑”!
- 华中农业大学C语言实验5答案,物理实验报告册(上册)-华中农业大学实验.pdf
- Altium Designer(十):极坐标
- el-select默认选中 显示的是id 不是汉字
- 提升方法AdaBoost你真的懂吗
- 明道云在建筑工程行业的应用场景
- MC(移动立方体)算法
- 微信公众号网页 H5 video 标签自动播放
- 用Windows自带的系统恢复环境WinRE进行系统重大故障排查,轻松修复Windows蓝屏、白屏等问题
- 华为路ws5200设置虚拟服务器,华为WS5200无线路由器怎么设置?
- centos修正时区
- 关于EasyDarwinGo部署海康威视rtsp转hls视频多摄像头的服务器视频转码
- 斗罗大陆壁纸图片高清小舞146集八段摔杨无敌
- 判断是否qq或者微信内置浏览器
热门文章
- 成都传智播客新装上线
- 智慧餐厅解决方案-最新全套文件
- word图表标签与编号之间空格删除解决方案
- 三相整流器移相触发电路的整体FPGA设计
- java sinh_Java StrictMath sinh()用法及代码示例
- DIY强大的虚拟化环境-前言与目录
- Google中国(谷歌)汉化大事记 1
- 智慧市政管理系统升城市形象和品位
- 计算机配置文件保存到哪里,微信文件保存在哪里【设置教程】
- oppoR17手机计算机的隐藏功能,小技巧隐藏大“智慧”,原来OPPO R17还有这些实用功能...