仿微信小视频
2015-09-30 15:31
501 查看
那个第一次写博客,文笔不是太好,所以只好把代码贴出来,然后解释一些,不好意思了,各位
第一方面:下面是对自定义的MovieRecorderView进行的分段解释
第一步:初始化各种数据:布局、参数等
代码:
第二步:初始化画布:防止在录制视频的时候,屏幕出现拉伸的状况
代码:
第三步:初始化Camera控件,与释放资源
代码:
第四步:初始化MediaRecorder控件
代码:
第五步:进行录制
代码
第六步:结束录制与释放资源
第二方面:下面是对录制的主页面进行解释与说明:当初我从网上下的各种相关demo,还有相关的博客说明,在这个地方处理的不多,当我们多次点击手机或者一不小心手抖动了一些之类的,很容易出现bug,所以进行了下面的处理
第一步:录制和停止录制
第二步:当录制完成之后,生成视频的缩略图,并进行保存和显示
代码下载:下载
转载:地址
第一方面:下面是对自定义的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(); } }
代码下载:下载
转载:地址
相关文章推荐
- android 代码实现控件之间的间距
- [Android]在代码里运行另一个程序的方法
- 肯特·贝克:改变人生的代码整理魔法
- 新注册
- 网页恶意代码的预防
- 高手写的Tracer-Flash代码调试类代码下载
- CSS代码缩写技巧
- 非主流Q-zOne代码代码搜集第1/2页
- 四大漏洞入侵博客
- CreateWeb.vbs 代码
- Lua中编译执行代码相关的函数详解
- 更有效率的css代码编写第1/3页
- 在Ubuntu系统上安装Ghost博客平台的教程
- 代码中到底应不应当写注释?
- SQL语言查询基础:连接查询 联合查询 代码
- 论坛头像随机变换代码
- .NET 常用功能和代码小结
- C#实现压缩HTML代码的方法
- asp编程中常用的javascript辅助代码第1/2页
- C#超实用代码段合集