近期做项目需要添加上传短视频功能,功能设置为类似于微信,点击开始拍摄,设置最长拍摄时间,经过研究最终实现了这个功能,下面就和大家分享一下,希望对你有帮助。

1.视频录制自定义控件:

/**
* 视频播放控件
*/
public class MovieRecorderView extends LinearLayout implements OnErrorListener { 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;// 文件 public MovieRecorderView(Context context) {
this(context, null);
} public MovieRecorderView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} @SuppressLint("NewApi")
public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.MovieRecorderView, defStyle, 0);
mWidth = a.getInteger(R.styleable.MovieRecorderView_width, 320);// 默认320
mHeight = a.getInteger(R.styleable.MovieRecorderView_height, 240);// 默认240 isOpenCamera = a.getBoolean(
R.styleable.MovieRecorderView_is_open_camera, true);// 默认打开
mRecordMaxTime = a.getInteger(
R.styleable.MovieRecorderView_record_max_time, 10);// 默认为10 LayoutInflater.from(context)
.inflate(R.layout.movie_recorder_view, this);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量 mSurfaceHolder = mSurfaceView.getHolder();
mSurfaceHolder.addCallback(new CustomCallBack());
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); a.recycle();
} /**
*
*/
private class CustomCallBack implements Callback { @Override
public void surfaceCreated(SurfaceHolder holder) {
if (!isOpenCamera)
return;
try {
initCamera();
} catch (IOException e) {
e.printStackTrace();
}
} @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) { } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (!isOpenCamera)
return;
freeCameraResource();
} } /**
* 初始化摄像头
*/
private void initCamera() throws IOException {
if (mCamera != null) {
freeCameraResource();
}
try {
mCamera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
freeCameraResource();
}
if (mCamera == null)
return; setCameraParams();
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
mCamera.unlock();
} /**
* 设置摄像头为竖屏
*/
private void setCameraParams() {
if (mCamera != null) {
Parameters params = mCamera.getParameters();
params.set("orientation", "portrait");
mCamera.setParameters(params);
}
} /**
* 释放摄像头资源
*/
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 + "ysb/video/");//录制视频的保存地址
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
File vecordDir = sampleDir;
// 创建文件
try {
mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);// mp4格式的录制的视频文件
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 初始化
* @throws IOException
*/
@SuppressLint("NewApi")
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(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 * 1024 * 100);// 设置帧频率,然后就清晰了
mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
// mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
mMediaRecorder.prepare();
try {
mMediaRecorder.start();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (RuntimeException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 开始录制视频
* @param fileName
* 视频储存位置
* @param onRecordFinishListener
* 达到指定时间之后回调接口
*/
public void record(final OnRecordFinishListener onRecordFinishListener) {
this.mOnRecordFinishListener = onRecordFinishListener;
createRecordDir();
try {
if (!isOpenCamera)// 如果未打开摄像头,则打开
initCamera();
initRecord();
mTimeCount = 0;// 时间计数器重新赋值
mTimer = new Timer();
mTimer.schedule(new TimerTask() { @Override
public void run() {
mTimeCount++;
mProgressBar.setProgress(mTimeCount);// 设置进度条
if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
stop();
if (mOnRecordFinishListener != null)
mOnRecordFinishListener.onRecordFinish();
}
}
}, 0, 1000);
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 停止拍摄
*/
public void stop() {
stopRecord();
releaseRecord();
freeCameraResource();
} /**
* 停止录制
*/
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();
}
}
} /**
* 释放资源
*/
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;
} //返回录制的视频文件
public File getmVecordFile() {
return mVecordFile;
} /**
* 录制完成回调接口
*/
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();
}
}
}

2.视频录制界面文件movie_recorder_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/background_dark"
android:orientation="vertical"> <SurfaceView
android:id="@+id/surfaceview"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
/> <ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="2dp"
/> </LinearLayout>

做好这些准备工作,下面我们就可以开始设计我们的视频录制功能了。PS:以上代码取至网上,在此向大牛致敬。

3.拍摄主界面,拍摄界面有两部分组成,上面是视频拍摄控件显示,下面是用户点击拍摄按钮,配置文件:activity_main.xml。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical"> <com.example.wechatvideorecorddemo.MovieRecorderView
android:id="@+id/movieRecorderView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="3dp" /> <Button
android:id="@+id/shoot_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/bg_movie_add_shoot"
android:text="按住拍"
android:textColor="#20b6ff"/> </LinearLayout>

4.有了主界面的视图,下面我们就开始书写我们的Activity文件MainActivity.java:

public class MainActivity extends Activity {

    private MovieRecorderView mRecorderView;//视频录制控件
private Button mShootBtn;//视频开始录制按钮
private boolean isFinish = true;
private boolean success = false;//防止录制完成后出现多次跳转事件 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecorderView = (MovieRecorderView) findViewById(R.id.movieRecorderView);
mShootBtn = (Button) findViewById(R.id.shoot_button); //用户长按事件监听
mShootBtn.setOnTouchListener(new OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {//用户按下拍摄按钮
mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot_select);
mRecorderView.record(new OnRecordFinishListener() { @Override
public void onRecordFinish() {
if(!success&&mRecorderView.getTimeCount()<10){//判断用户按下时间是否大于10秒
success = true;
handler.sendEmptyMessage(1);
}
}
});
} else if (event.getAction() == MotionEvent.ACTION_UP) {//用户抬起拍摄按钮
mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot);
if (mRecorderView.getTimeCount() > 3){//判断用户按下时间是否大于3秒
if(!success){
success = true;
handler.sendEmptyMessage(1);
}
} else {
success = false;
if (mRecorderView.getmVecordFile() != null)
mRecorderView.getmVecordFile().delete();//删除录制的过短视频
mRecorderView.stop();//停止录制
Toast.makeText(MainActivity.this, "视频录制时间太短", Toast.LENGTH_SHORT).show();
}
}
return true;
}
});
} @Override
public void onResume() {
super.onResume();
isFinish = true;
if (mRecorderView.getmVecordFile() != null)
mRecorderView.getmVecordFile().delete();//视频使用后删除
} @Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
isFinish = false;
success = false;
mRecorderView.stop();//停止录制
} @Override
public void onPause() {
super.onPause();
} @Override
public void onDestroy() {
super.onDestroy();
} private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if(success){
finishActivity();
}
}
}; //视频录制结束后,跳转的函数
private void finishActivity() {
if (isFinish) {
mRecorderView.stop();
Intent intent = new Intent(this, SuccessActivity.class);
Bundle bundle = new Bundle();
bundle.putString("text", mRecorderView.getmVecordFile().toString());
intent.putExtras(bundle);
startActivity(intent);
}
success = false;
} /**
* 录制完成回调
*/
public interface OnShootCompletionListener {
public void OnShootSuccess(String path, int second);
public void OnShootFailure();
}
}

到这里我们仿微信的短视频拍摄就已经大功告成,那么下面我们检验一下,我们录制的效果如何,下面我以Android提供的视频播放控件(VideoView)为大家介绍一下如何播放录制的短视频。

5.播放视频的配置文件activity_success.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical"> <TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/app_name" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:text="播放"
/>
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:text="暂停"
/>
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:text="重播"
/>
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:text="视频长度"
/>
</LinearLayout>
<VideoView
android:id="@+id/videoView1"
android:layout_width="wrap_content"
android:layout_height="500dp" /> </LinearLayout>

6.视频播放的控制代码SuccessActivity.java:

public class SuccessActivity extends Activity implements OnClickListener{

    private TextView text;//视频保存的路径
private Button button1;//播放开关
private Button button2;//暂停开关
private Button button3;//重新播放开关
private Button button4;//视频大小开关
private VideoView videoView1;//视频播放控件
private String file;//视频路径 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_success);
Bundle bundle = getIntent().getExtras();
file = bundle.getString("text");//获得拍摄的短视频保存地址
init();
setValue();
} //初始化
private void init() {
text = (TextView) findViewById(R.id.text);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
button4 = (Button) findViewById(R.id.button4);
videoView1 = (VideoView) findViewById(R.id.videoView1);
} //设置
private void setValue() {
text.setText(file);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
videoView1.setVideoPath(file);
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
videoView1.start();
break; case R.id.button2:
videoView1.pause();
break; case R.id.button3:
videoView1.resume();
videoView1.start();
break; case R.id.button4:
Toast.makeText(this, "视频长度:"+(videoView1.getDuration()/1024)+"M", Toast.LENGTH_SHORT).show();
break; default:
break;
}
} }

7.添加权限:

<!-- 视频录制的权限star   -->
<!-- 摄像头 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 音频即声音 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- sd卡写入权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 硬件支持 -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<!-- 视频录制的权限end -->

功能界面截图:

  

  

好了,到这里关于拍摄短视频的知识就和大家分享完毕,具体的实现很简单,相信大家看到这里已经已经学会了,当然如果你还有什么疑问,可以留言讨论。最后给大家分享一个demo的下载地址,方便大家下载学习,下载地址:http://pan.baidu.com/s/1hqts0pm

Android仿微信拍摄短视频的更多相关文章

  1. Android 仿微信小视频录制

    Android 仿微信小视频录制 WechatShortVideo和WechatShortVideo文章

  2. Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

  3. android多框架实现短视频应用、3D手势旋转、banner控件、指南针、智能管家等应用源码

    Android精选源码 android智能管家app源码 Android高仿拼多多分类列表 Android百度地图实例详解之仿摩拜单车APP RecyclerView的LayoutManager搭建流 ...

  4. Android仿微信界面

    效果图 原理介绍 1.先绘制一个颜色(例如:粉红) 2.设置Mode=DST_IN 3.绘制我们这个可爱的小机器人 回答我,显示什么,是不是显示交集,交集是什么?交集是我们的小机器人的非透明区域,也就 ...

  5. android仿微信红包动画、Kotlin综合应用、Xposed模块、炫酷下拉视觉、UC浏览器滑动动画等源码

    Android精选源码 仿微信打开红包旋转动画 使用Kotlin编写的Android应用,内容你想象不到 Android手机上的免Root Android系统日志Viewer 一个能让微信 Mater ...

  6. Android仿微信高效压缩图片(libjpeg)

    用过ios手机的同学应该很明显感觉到,ios拍照1M的图片要比安卓拍照排出来的5M的图片还要清晰.这是为什么呢? 这得了解android底层是如何对图片进行处理的. 当时谷歌开发Android的时候, ...

  7. Android 仿微信朋友圈添加图片

    github地址(欢迎下载Demo) https://github.com/zhouxu88/WXCircleAddPic 老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催的紧, ...

  8. Android 仿微信朋友圈发动态功能(相册图片多选)

    代码分享 代码名称: 仿微信朋友圈发动态功能(相册图片多选) 代码描述: 仿微信朋友圈发动态功能(相册图片多选) 代码托管地址: http://www.apkbus.com/android-15276 ...

  9. Android 仿微信朋友圈拍小视频上传到服务器

    这个接上一个写的实现拍小视频和传到服务器的  界面是这个样子滴. 我也知不知道怎么给图片搞小一点o(╯□╰)o 布局文件是这样的[认真脸] <?xml version="1.0&quo ...

随机推荐

  1. bootstrap之伪元素

    bootstrap之伪元素 参考地址:http://www.cnblogs.com/keyi/p/5943178.html http://www.runoob.com/css/css-pseudo-e ...

  2. Win8.1开机黑屏一段时间才能登录

    最近发现开机后有一段时间黑屏过后才能进人登录界面,并且时间越来越长,网上查询了很多方法都没有效果,只能自己找了. 网上有一种方法提到用msconfig诊断判断或者安全启动来查看是否有黑屏,于是试了一下 ...

  3. [IOS]Swift 遍历预制的本地资源文件

    我事先放了一堆svg文件,但是我是批量使用的,想要直接遍历他们加入到一个list中来,那我直接就遍历他们的名称,把他们的名字组成一个array. var ss:NSString = NSBundle. ...

  4. bfs判断连通图(无向)

    在图论中,连通图基于连通的概念.在一个无向图 G 中,若从顶点vi到顶点vj有路径相连(当然从vj到vi也一定有路径),则称vi和vj是连通的.如果 G 是有向图,那么连接vi和vj的路径中所有的边都 ...

  5. php报表使用

    php报表的使用: 1.到官网(http://jpgraph.net/)下载,建议下载jpgraph-3.0.7.tar.gz版本 2.解压后有两个文件夹 docportal:使用手册 src:报表核 ...

  6. nginx-nginx.conf脚本

    user www www; worker_processes ; error_log /usr/local/nginx/logs/error.log info ; pid /var/run/nginx ...

  7. 关于Java8函数式编程你需要了解的几点

    函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异. 函数作为一等公民 在理解函数作为一等公民这句话时,让我们先来看一下一种非常常 ...

  8. apk反编译

    在学习Android开发的过程你,你往往会去借鉴别人的应用是怎么开发的,那些漂亮的动画和精致的布局可能会让你爱不释手,作为一个开发者,你可能会很想知道这些效果界面是怎么去实现的,这时,你便可以对改应用 ...

  9. SQL Server 2008, 2008 R2, 2012 and 2014 完全支持TLS1.2加密传输

    SQL Server 2008, 2008 R2, 2012 and 2014 完全支持TLS1.2加密传输 微软高兴地宣布所有主流SQL Server客户端驱动和SQL Server发行版已经支持T ...

  10. Visual Studio跨平台开发Xamarin

    台湾微软的一系列Visual Studio跨平台开发Xamarin的资料,上面还有视频.具体参看 http://www.microsoft.com/taiwan/newsletter/library/ ...