近期做项目需要添加上传短视频功能,功能设置为类似于微信,点击开始拍摄,设置最长拍摄时间,经过研究最终实现了这个功能,下面就和大家分享一下,希望对你有帮助。
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的下载地址,方便大家下载学习,下载地址:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持移动技术网!
如对本文有疑问, 点击进行留言回复!!
LongClick原理、上下文菜单原理、EditText长按弹窗原理、WebView长按弹窗自定义、修复WebView全选重复bug ———————————————— 版权声明:本文为CSDN博主「
JobScheduler 实现 特定时间,特定条件(系统空闲,电池电量,磁盘空间 ……)下执行任务
温习Android基础知识——《第一行代码(第三版)》读书笔记 Chapter 10 Service
网友评论