模擬微信短視頻拍攝

本文主要講述了在Android項目中模仿微信的拍攝和上傳短視頻功能,點擊開始拍攝,設置最長拍攝時間,現在把實現思路和代碼整理出來分享給Android程序員兄弟們,希望給他們的開發工作帶來幫助。

1.視頻錄製自定義控件:

1 <span style="font-size: medium;">/**
2  * 視頻播放控件
3  */
4 public class MovieRecorderView extends LinearLayout implements OnErrorListener {
5  
6     private SurfaceView mSurfaceView;
7     private SurfaceHolder mSurfaceHolder;
8     private ProgressBar mProgressBar;
9  
10     private MediaRecorder mMediaRecorder;
11     private Camera mCamera;
12     private Timer mTimer;// 計時器
13     private OnRecordFinishListener mOnRecordFinishListener;// 錄製完成回調接口
14  
15     private int mWidth;// 視頻分辨率寬度
16     private int mHeight;// 視頻分辨率高度
17     private boolean isOpenCamera;// 是否一開始就打開攝像頭
18     private int mRecordMaxTime;// 一次拍攝最長時間
19     private int mTimeCount;// 時間計數
20     private File mVecordFile = null;// 文件
21  
22     public MovieRecorderView(Context context) {
23         this(context, null);
24     }
25  
26     public MovieRecorderView(Context context, AttributeSet attrs) {
27         this(context, attrs, 0);
28     }
29  
30     @SuppressLint("NewApi")
31     public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
32         super(context, attrs, defStyle);
33  
34         TypedArray a = context.obtainStyledAttributes(attrs,
35                 R.styleable.MovieRecorderView, defStyle, 0);
36         mWidth = a.getInteger(R.styleable.MovieRecorderView_width, 320);// 默認320
37         mHeight = a.getInteger(R.styleable.MovieRecorderView_height, 240);// 默認240
38  
39         isOpenCamera = a.getBoolean(
40                 R.styleable.MovieRecorderView_is_open_camera, true);// 默認打開
41         mRecordMaxTime = a.getInteger(
42                 R.styleable.MovieRecorderView_record_max_time, 10);// 默認爲10
43  
44         LayoutInflater.from(context)
45                 .inflate(R.layout.movie_recorder_view, this);
46         mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
47         mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
48         mProgressBar.setMax(mRecordMaxTime);// 設置進度條最大量
49  
50         mSurfaceHolder = mSurfaceView.getHolder();
51         mSurfaceHolder.addCallback(new CustomCallBack());
52         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
53  
54         a.recycle();
55     }
56  
57     /**
58      *
59      */
60     private class CustomCallBack implements Callback {
61  
62         @Override
63         public void surfaceCreated(SurfaceHolder holder) {
64             if (!isOpenCamera)
65                 return;
66             try {
67                 initCamera();
68             } catch (IOException e) {
69                 e.printStackTrace();
70             }
71         }
72  
73         @Override
74         public void surfaceChanged(SurfaceHolder holder, int format, int width,
75                 int height) {
76  
77         }
78  
79         @Override
80         public void surfaceDestroyed(SurfaceHolder holder) {
81             if (!isOpenCamera)
82                 return;
83             freeCameraResource();
84         }
85  
86     }
87  
88     /**
89      * 初始化攝像頭
90      */
91     private void initCamera() throws IOException {
92         if (mCamera != null) {
93             freeCameraResource();
94         }
95         try {
96             mCamera = Camera.open();
97         } catch (Exception e) {
98             e.printStackTrace();
99             freeCameraResource();
100         }
101         if (mCamera == null)
102             return;
103  
104         setCameraParams();
105         mCamera.setDisplayOrientation(90);
106         mCamera.setPreviewDisplay(mSurfaceHolder);
107         mCamera.startPreview();
108         mCamera.unlock();
109     }
110  
111     /**
112      * 設置攝像頭爲豎屏
113      */
114     private void setCameraParams() {
115         if (mCamera != null) {
116             Parameters params = mCamera.getParameters();
117             params.set("orientation", "portrait");
118             mCamera.setParameters(params);
119         }
120     }
121  
122     /**
123      * 釋放攝像頭資源
124      */
125     private void freeCameraResource() {
126         if (mCamera != null) {
127             mCamera.setPreviewCallback(null);
128             mCamera.stopPreview();
129             mCamera.lock();
130             mCamera.release();
131             mCamera = null;
132         }
133     }
134  
135     private void createRecordDir() {
136         //錄製的視頻保存文件夾
137         File sampleDir = new File(Environment.getExternalStorageDirectory()
138                 + File.separator + "ysb/video/");//錄製視頻的保存地址
139         if (!sampleDir.exists()) {
140             sampleDir.mkdirs();
141         }
142         File vecordDir = sampleDir;
143         // 創建文件
144         try {
145             mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);// mp4格式的錄製的視頻文件
146         } catch (IOException e) {
147             e.printStackTrace();
148         }
149     }
150  
151     /**
152      * 初始化
153      * @throws IOException
154      */
155     @SuppressLint("NewApi")
156     private void initRecord() throws IOException {
157         mMediaRecorder = new MediaRecorder();
158         mMediaRecorder.reset();
159         if (mCamera != null)
160             mMediaRecorder.setCamera(mCamera);
161         mMediaRecorder.setOnErrorListener(this);
162         mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
163         mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 視頻源
164         mMediaRecorder.setAudioSource(AudioSource.MIC);// 音頻源
165         mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 視頻輸出格式
166         mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音頻格式
167         mMediaRecorder.setVideoSize(mWidth, mHeight);// 設置分辨率:
168         // mMediaRecorder.setVideoFrameRate(16);// 這個我把它去掉了,感覺沒什麼用
169         mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 1024 * 100);// 設置幀頻率,然後就清晰了
170         mMediaRecorder.setOrientationHint(90);// 輸出旋轉90度,保持豎屏錄製
171         mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 視頻錄製格式
172         // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
173         mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
174         mMediaRecorder.prepare();
175         try {
176             mMediaRecorder.start();
177         } catch (IllegalStateException e) {
178             e.printStackTrace();
179         } catch (RuntimeException e) {
180             e.printStackTrace();
181         } catch (Exception e) {
182             e.printStackTrace();
183         }
184     }
185  
186     /**
187      * 開始錄製視頻
188      * @param fileName
189      *            視頻儲存位置
190      * @param onRecordFinishListener
191      *            達到指定時間之後回調接口
192      */
193     public void record(final OnRecordFinishListener onRecordFinishListener) {
194         this.mOnRecordFinishListener = onRecordFinishListener;
195         createRecordDir();
196         try {
197             if (!isOpenCamera)// 如果未打開攝像頭,則打開
198                 initCamera();
199             initRecord();
200             mTimeCount = 0;// 時間計數器重新賦值
201             mTimer = new Timer();
202             mTimer.schedule(new TimerTask() {
203  
204                 @Override
205                 public void run() {
206                     mTimeCount++;
207                     mProgressBar.setProgress(mTimeCount);// 設置進度條
208                     if (mTimeCount == mRecordMaxTime) {// 達到指定時間,停止拍攝
209                         stop();
210                         if (mOnRecordFinishListener != null)
211                             mOnRecordFinishListener.onRecordFinish();
212                     }
213                 }
214             }, 0, 1000);
215         } catch (IOException e) {
216             e.printStackTrace();
217         }
218     }
219  
220     /**
221      * 停止拍攝
222      */
223     public void stop() {
224         stopRecord();
225         releaseRecord();
226         freeCameraResource();
227     }
228  
229     /**
230      * 停止錄製
231      */
232     public void stopRecord() {
233         mProgressBar.setProgress(0);
234         if (mTimer != null)
235             mTimer.cancel();
236         if (mMediaRecorder != null) {
237             // 設置後不會崩
238             mMediaRecorder.setOnErrorListener(null);
239             mMediaRecorder.setPreviewDisplay(null);
240             try {
241                 mMediaRecorder.stop();
242             } catch (IllegalStateException e) {
243                 e.printStackTrace();
244             } catch (RuntimeException e) {
245                 e.printStackTrace();
246             } catch (Exception e) {
247                 e.printStackTrace();
248             }
249         }
250     }
251  
252     /**
253      * 釋放資源
254      */
255     private void releaseRecord() {
256         if (mMediaRecorder != null) {
257             mMediaRecorder.setOnErrorListener(null);
258             try {
259                 mMediaRecorder.release();
260             } catch (IllegalStateException e) {
261                 e.printStackTrace();
262             } catch (Exception e) {
263                 e.printStackTrace();
264             }
265         }
266         mMediaRecorder = null;
267     }
268  
269     public int getTimeCount() {
270         return mTimeCount;
271     }
272  
273     //返回錄製的視頻文件
274     public File getmVecordFile() {
275         return mVecordFile;
276     }
277  
278     /**
279      * 錄製完成回調接口
280      */
281     public interface OnRecordFinishListener {
282         public void onRecordFinish();
283     }
284  
285     @Override
286     public void onError(MediaRecorder mr, int what, int extra) {
287         try {
288             if (mr != null)
289                 mr.reset();
290         } catch (IllegalStateException e) {
291             e.printStackTrace();
292         } catch (Exception e) {
293             e.printStackTrace();
294         }
295     }
296 }</span>

2.視頻錄製界面文件movie_recorder_view.xml:

1 <span style="font-size: medium;"><?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     xmlns:tools="http://schemas.android.com/tools"
4     android:layout_width="match_parent"
5     android:layout_height="match_parent"
6     android:background="@android:color/background_dark"
7     android:orientation="vertical">
8  
9     <SurfaceView
10          android:id="@+id/surfaceview"
11          android:layout_width="fill_parent"
12          android:layout_height="0dp"
13          android:layout_weight="1"
14           />
15  
16     <ProgressBar
17         android:id="@+id/progressBar"
18         style="?android:attr/progressBarStyleHorizontal"
19         android:layout_width="match_parent"
20         android:layout_height="2dp"
21         />
22  
23 </LinearLayout></span>

做好這些準備工作,下面我們就可以開始設計我們的視頻錄製功能了。PS:以上代碼取至網上,在此向大牛致敬。

3.拍攝主界面,拍攝界面有兩部分組成,上面是視頻拍攝控件顯示,下面是用戶點擊拍攝按鈕,配置文件:

1 <span style="font-size: medium;"><?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     xmlns:tools="http://schemas.android.com/tools"
4     android:layout_width="match_parent"
5     android:layout_height="match_parent"
6     android:background="@android:color/white"
7     android:orientation="vertical">
8  
9     <com.example.wechatvideorecorddemo.MovieRecorderView
10         android:id="@+id/movieRecorderView"
11         android:layout_width="match_parent"
12         android:layout_height="0dp"
13         android:layout_weight="1"
14         android:layout_margin="3dp" />
15  
16     <Button
17         android:id="@+id/shoot_button"
18         android:layout_width="wrap_content"
19         android:layout_height="wrap_content"
20         android:layout_gravity="center"
21         android:background="@drawable/bg_movie_add_shoot"
22         android:text="按住拍"
23         android:textColor="#20b6ff"/>
24  
25 </LinearLayout></span>

4.有了主界面的視圖,下面我們就開始書寫我們的Activity文件MainActivity.java:

1 <span style="font-size: medium;">public class MainActivity extends Activity {
2  
3     private MovieRecorderView mRecorderView;//視頻錄製控件
4     private Button mShootBtn;//視頻開始錄製按鈕
5     private boolean isFinish = true;
6     private boolean success = false;//防止錄製完成後出現多次跳轉事件
7  
8     @Override
9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12         mRecorderView = (MovieRecorderView) findViewById(R.id.movieRecorderView);
13         mShootBtn = (Button) findViewById(R.id.shoot_button);
14  
15         //用戶長按事件監聽
16         mShootBtn.setOnTouchListener(new OnTouchListener() {
17  
18             @Override
19             public boolean onTouch(View v, MotionEvent event) {
20                 if (event.getAction() == MotionEvent.ACTION_DOWN) {//用戶按下拍攝按鈕
21                     mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot_select);
22                     mRecorderView.record(new OnRecordFinishListener() {
23  
24                         @Override
25                         public void onRecordFinish() {
26                             if(!success&&mRecorderView.getTimeCount()<10){//判斷用戶按下時間是否大於10秒
27                                 success = true;
28                                 handler.sendEmptyMessage(1);
29                             }
30                         }
31                     });
32                 } else if (event.getAction() == MotionEvent.ACTION_UP) {//用戶擡起拍攝按鈕
33                     mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot);
34                     if (mRecorderView.getTimeCount() > 3){//判斷用戶按下時間是否大於3秒
35                         if(!success){
36                             success = true;
37                             handler.sendEmptyMessage(1);
38                         }
39                     } else {
40                         success = false;
41                         if (mRecorderView.getmVecordFile() != null)
42                             mRecorderView.getmVecordFile().delete();//刪除錄製的過短視頻
43                         mRecorderView.stop();//停止錄製
44                         Toast.makeText(MainActivity.this, "視頻錄製時間太短", Toast.LENGTH_SHORT).show();
45                     }
46                 }
47                 return true;
48             }
49         });
50     }
51  
52     @Override
53     public void onResume() {
54         super.onResume();
55         isFinish = true;
56         if (mRecorderView.getmVecordFile() != null)
57             mRecorderView.getmVecordFile().delete();//視頻使用後刪除
58     }
59  
60     @Override
61     public void onSaveInstanceState(Bundle outState) {
62         super.onSaveInstanceState(outState);
63         isFinish = false;
64         success = false;
65         mRecorderView.stop();//停止錄製
66     }
67  
68     @Override
69     public void onPause() {
70         super.onPause();
71     }
72  
73     @Override
74     public void onDestroy() {
75         super.onDestroy();
76     }
77  
78     private Handler handler = new Handler() {
79         @Override
80         public void handleMessage(Message msg) {
81             if(success){
82                 finishActivity();
83             }
84         }
85     };
86  
87     //視頻錄製結束後,跳轉的函數
88     private void finishActivity() {
89         if (isFinish) {
90             mRecorderView.stop();
91             Intent intent = new Intent(this, SuccessActivity.class);
92             Bundle bundle = new Bundle();
93             bundle.putString("text", mRecorderView.getmVecordFile().toString());
94             intent.putExtras(bundle);
95             startActivity(intent);
96         }
97         success = false;
98     }
99  
100     /**
101      * 錄製完成回調
102      */
103      public interface OnShootCompletionListener {
104          public void OnShootSuccess(String path, int second);
105          public void OnShootFailure();
106      }
107 }</span>

到這裏我們仿微信的短視頻拍攝就已經大功告成,那麼下面我們檢驗一下,我們錄製的效果如何,下面我以Android提供的視頻播放控件(VideoView)爲大家介紹一下如何播放錄製的短視頻。

5.播放視頻的配置文件activity_success.xml:

1 <span style="font-size: medium;"><?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     xmlns:tools="http://schemas.android.com/tools"
4     android:layout_width="match_parent"
5     android:layout_height="match_parent"
6     android:background="@android:color/white"
7     android:orientation="vertical">
8  
9     <TextView
10         android:id="@+id/text"
11         android:layout_width="wrap_content"
12         android:layout_height="wrap_content"
13         android:layout_gravity="center"
14         android:text="@string/app_name" />
15     <LinearLayout
16         android:layout_width="match_parent"
17         android:layout_height="wrap_content"
18         android:orientation="horizontal"
19         >
20         <Button
21             android:id="@+id/button1"
22             android:layout_width="match_parent"
23             android:layout_height="wrap_content"
24             android:layout_weight="1"
25             android:gravity="center"
26             android:padding="5dp"
27             android:text="播放"
28             />
29         <Button
30             android:id="@+id/button2"
31             android:layout_width="match_parent"
32             android:layout_height="wrap_content"
33             android:layout_weight="1"
34             android:gravity="center"
35             android:padding="5dp"
36             android:text="暫停"
37             />
38         <Button
39             android:id="@+id/button3"
40             android:layout_width="match_parent"
41             android:layout_height="wrap_content"
42             android:layout_weight="1"
43             android:gravity="center"
44             android:padding="5dp"
45             android:text="重播"
46             />
47         <Button
48             android:id="@+id/button4"
49             android:layout_width="match_parent"
50             android:layout_height="wrap_content"
51             android:layout_weight="1"
52             android:gravity="center"
53             android:padding="5dp"
54             android:text="視頻長度"
55             />
56     </LinearLayout>
57     <VideoView
58         android:id="@+id/videoView1"
59         android:layout_width="wrap_content"
60         android:layout_height="500dp" />
61  
62 </LinearLayout></span>

6.視頻播放的控制代碼SuccessActivity.java:

1 <span style="font-size: medium;">public class SuccessActivity extends Activity implements OnClickListener{
2  
3     private TextView text;//視頻保存的路徑
4     private Button button1;//播放開關
5     private Button button2;//暫停開關
6     private Button button3;//重新播放開關
7     private Button button4;//視頻大小開關
8     private VideoView videoView1;//視頻播放控件
9     private String file;//視頻路徑
10  
11     @Override
12     protected void onCreate(Bundle savedInstanceState) {
13         super.onCreate(savedInstanceState);
14         setContentView(R.layout.activity_success);
15         Bundle bundle = getIntent().getExtras();
16         file = bundle.getString("text");//獲得拍攝的短視頻保存地址
17         init();
18         setValue();
19     }
20  
21     //初始化
22     private void init() {
23         text = (TextView) findViewById(R.id.text);
24         button1 = (Button) findViewById(R.id.button1);
25         button2 = (Button) findViewById(R.id.button2);
26         button3 = (Button) findViewById(R.id.button3);
27         button4 = (Button) findViewById(R.id.button4);
28         videoView1 = (VideoView) findViewById(R.id.videoView1);
29     }
30  
31     //設置
32     private void setValue() {
33         text.setText(file);
34         button1.setOnClickListener(this);
35         button2.setOnClickListener(this);
36         button3.setOnClickListener(this);
37         button4.setOnClickListener(this);
38         videoView1.setVideoPath(file);
39     }
40  
41     @Override
42     public void onClick(View v) {
43         switch (v.getId()) {
44         case R.id.button1:
45             videoView1.start();
46             break;
47  
48         case R.id.button2:
49             videoView1.pause();       
50             break;
51  
52         case R.id.button3:
53             videoView1.resume();
54             videoView1.start();
55             break;
56  
57         case R.id.button4:
58             Toast.makeText(this, "視頻長度:"+(videoView1.getDuration()/1024)+"M", Toast.LENGTH_SHORT).show();
59             break;
60  
61         default:
62             break;
63         }
64     }
65  
66 }</span>

功能界面截圖:

Android仿微信拍攝短視頻

Android仿微信拍攝短視頻

好了,到這裏關於拍攝短視頻的知識就和大家分享完畢,具體的實現很簡單,相信大家看到這裏已經已經學會了。

本文到此結束,需要的朋友可以參考下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章