您的位置:首页 > 移动开发 > 微信开发

仿微信小视频

2015-09-30 15:31 501 查看
那个第一次写博客,文笔不是太好,所以只好把代码贴出来,然后解释一些,不好意思了,各位

第一方面:下面是对自定义的MovieRecorderView进行的分段解释

第一步:初始化各种数据:布局、参数等

代码:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//下面的参数大多是可以进行配置的:
// 视频分辨率宽度(分辨率)
mWidth = 640;
// 视频分辨率高度(分辨率)
mHeight = 480;
// 一次拍摄最长时间
mRecordMaxTime = 8;
// 是否一开始就打开摄像头
isOpenCamera = true;

LayoutInflater.from(context).inflate(R.layout.view_movie_recorder, this);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
mBottomLayout = (LinearLayout) findViewById(R.id.bottom_layout);
initSurfaceView(context);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);

mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new CustomCallBack());
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

a.recycle();
}


:下面是对应的布局:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/bottom_layout"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>

<SurfaceView
android:id="@+id/surfaceview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>

</LinearLayout>
:给SurfaceView添加一个LinearLayout外布局是为了进行第二步的操作;

<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
/>
</LinearLayout>


第二步:初始化画布:防止在录制视频的时候,屏幕出现拉伸的状况

代码:

private void initSurfaceView(Context context) {
//获取手机屏幕的宽度
final int w = DeviceUtils.getScreenWidth(context);
//可以设置视频的位置:上 下 左 右
//((LinearLayout.LayoutParams) mBottomLayout.getLayoutParams()).topMargin = w;
int width = w;
int height = w * 4 / 3;
//设置SurfaceView的宽高属性: 这个LayoutParams类是用于child view(子视图) 向 parent view(父视
//图)传达自己的意愿的一个东西,上面的LinearLayout外布局就是为了设置SurfaceView的宽高
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSurfaceView.getLayoutParams();
lp.width = width;
lp.height = height;
mSurfaceView.setLayoutParams(lp);
}


第三步:初始化Camera控件,与释放资源

代码:

/**
* 初始化摄像头
* @throws IOException
*/
private void initCamera() throws IOException {
if (mCamera != null) {
//记得一定要释放摄像头资源
freeCameraResource();
}

try {
mCamera = Camera.open();
//获取对应手机可以使用的宽高分辨率
List<Camera.Size> supportedVideoSizes = mCamera.getParameters().getSupportedVideoSizes() == null ? mCamera.getParameters().getSupportedPreviewSizes() : mCamera.getParameters().getSupportedVideoSizes();
Log.w("TTT", (supportedVideoSizes == null ? "null" : supportedVideoSizes.size()) + "");
for (Camera.Size supportedVideoSize : supportedVideoSizes) {
Log.w("TTT", "h:" + supportedVideoSize.height + "--- w:" + supportedVideoSize.width);
}
} catch (Exception e) {
e.printStackTrace();
freeCameraResource();
}
if (mCamera == null)
return;
//  setCameraParams();
//设置摄像头的顺时针方向旋转90度
mCamera.setDisplayOrientation(90);
//为摄像头设置SurfaceHolder对象:必须在SurfaceHolder创建完成的时候
mCamera.setPreviewDisplay(mSurfaceHolder);
//开启预览功能
mCamera.startPreview();
//锁定摄像头
mCamera.unlock();
}
private final Object releaseMutex = new Object();

/**
* 释放摄像头资源
* 添加一个同步锁,防止出现线程的问题
*/
private void freeCameraResource() {
synchronized (releaseMutex) {
if (mCamera != null) {
mCam
e320
era.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.lock();
mCamera.release();
mCamera = null;
}
}
}


第四步:初始化MediaRecorder控件

代码:

/**
* 初始化
* @throws IOException
*/
private void initRecord() throws IOException {
mMediaRecorder = new MediaRecorder();
mMediaRecorder.reset();
if (mCamera != null) {
mMediaRecorder.setCamera(mCamera);
}
mMediaRecorder.setOnErrorListener(this);
mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
// 视频源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 音频源
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 必须在prepare之前,setXXXSource之后
// 视频输出格式

mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 音频格式
mMediaRecorder.setAudioEncodingBitRate(32);
mMediaRecorder.setAudioSamplingRate(48);
mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
//设置视频的帧率
mMediaRecorder.setVideoFrameRate(24);
mMediaRecorder.setVideoEncodingBitRate(mBitRate);// 设置帧频率,然后就清晰了
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// 视频录制格式
mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
// mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
mMediaRecorder.prepare();
try {
mMediaRecorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}


第五步:进行录制

代码

/**
* 开始录制
* @param mRecordMaxTime : 时间
* @param mWidth:宽
* @param mHeight:高
* @param bitRate:比特率
* @param onRecordFinishListener:录制完成时的监听
*/
public void record(final int mRecordMaxTime,int mWidth,int mHeight,int bitRate, final OnRecordFinishListener onRecordFinishListener) {
//设置一些上面说的可以进行设置的参数
this.mRecordMaxTime = mRecordMaxTime;
this.mOnRecordFinishListener = onRecordFinishListener;
this.mHeight = mHeight;
this.mWidth = mWidth;
this.mBitRate = bitRate;
mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量
createRecordDir();
try {
if (!isOpenCamera) {// 如果未打开摄像头,则打开
initCamera();
}
initRecord();
mTimeCount = 0;// 时间计数器重新赋值
mTimer = new Timer();
//进行时间计数:刷新ProgressBar条
mTimer.schedule(new TimerTask() {

@Override
public void run() {
// TODO Auto-generated method stub
mTimeCount++;
mProgressBar.setProgress(mTimeCount);// 设置进度条
if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
stop();
if (mOnRecordFinishListener != null)
mOnRecordFinishListener.onRecordFinish(getmVecordString(), getmRecordFile(), getTimeCount());
}
}
}, 0, 1000);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 录制完成回调接口
*/
public interface OnRecordFinishListener {
public void onRecordFinish(String path, File recordFile, int time);
}


第六步:结束录制与释放资源

/**
* 停止拍摄
*/
public void stop() {
stopRecord();
releaseRecord();
freeCameraResource();
}**
* 停止录制
*/
public void stopRecord() {
mProgressBar.setProgress(0);
if (mTimer != null)
mTimer.cancel();
if (mMediaRecorder != null) {
// 设置后不会崩
mMediaRecorder.setOnErrorListener(null);
try {
mMediaRecorder.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
mMediaRecorder.setPreviewDisplay(null);
}
}
/**
* 释放资源
*/
private void releaseRecord() {
if (mMediaRecorder != null) {
mMediaRecorder.setOnErrorListener(null);
try {
mMediaRecorder.release();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
mMediaRecorder = null;
}


第二方面:下面是对录制的主页面进行解释与说明:当初我从网上下的各种相关demo,还有相关的博客说明,在这个地方处理的不多,当我们多次点击手机或者一不小心手抖动了一些之类的,很容易出现bug,所以进行了下面的处理

第一步:录制和停止录制

//在OnLongClickListener方法中进行录制视频,可以防止多次点击出现的各种bug
mShootBtn.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
isStart = true;
//开始录制
mRecorderView.record(8, 640, 480, MovieRecorderView.BIG_BIT_RATE, new MovieRecorderView.OnRecordFinishListener() {

@Override
public void onRecordFinish(String path, File recordFile, int time) {
isStart = false;
handler.sendEmptyMessage(1);
}
});
//当开始录制后才会走下面的OnTouch事件,走stop
mShootBtn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (isStart) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:

if (mRecorderView != null) {
mRecorderView.stop();

if (mRecorderView.getTimeCount() > 1) {
finishActivity();
} else {
if (!mRecorderView.getmRecordFile().exists()) {
mRecorderView.getmRecordFile().delete();
}
//   mRecorderView.stop();
Toast.makeText(MainActivity.this,
getString(R.string.smallTime), Toast.LENGTH_SHORT).show();
MainActivity.this.finish();
}
}
break;

}

}
return true;
}
});
return true;
}
});


第二步:当录制完成之后,生成视频的缩略图,并进行保存和显示

private void finishActivity() {
if (isFinish) {
if (mRecorderView != null) {
//mRecorderView.stop();
//生成视频的缩略图,并进行保存
String videoPath = mRecorderView.getmRecordFile().getAbsolutePath();
Bitmap thumbnailBitmap = Utils.getVoiceBitmap(videoPath, 640, 480);
String tempBitmapPath = videoPath.substring(0, videoPath.length() - 4);
String thumbPath = tempBitmapPath + ".jpg";
saveBitmap(thumbnailBitmap, thumbPath);

Intent intent = new Intent();
//视频地址
intent.putExtra("videoPath", videoPath);
//缩略图
intent.putExtra("thumbPath", thumbPath);
setResult(RESULT_OK, intent);
finish();
} else {
finish();
}
}
}

/** 保存方法
* @param getimage
* @param bitmapPath*/
public void saveBitmap(Bitmap getimage, String bitmapPath) {
File f = new File(bitmapPath);
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
getimage.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


代码下载:下载

转载:地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  代码 博客 仿微信