本文主要讲述了在Android项目中模仿微信的拍摄和上传短视频功能,点击开始拍摄,设置最长拍摄时间,现在把实现思路和代码整理出来分享给Android程序员兄弟们,希望给他们的开发工作带来帮助。
1.视频录制自定义控件:
1 | <span style= "font-size: medium;" > /** |
4 | public class MovieRecorderView extends LinearLayout implements OnErrorListener { |
6 | private SurfaceView mSurfaceView; |
7 | private SurfaceHolder mSurfaceHolder; |
8 | private ProgressBar mProgressBar; |
10 | private MediaRecorder mMediaRecorder; |
11 | private Camera mCamera; |
13 | private OnRecordFinishListener mOnRecordFinishListener; |
17 | private boolean isOpenCamera; |
18 | private int mRecordMaxTime; |
19 | private int mTimeCount; |
20 | private File mVecordFile = null ; |
22 | public MovieRecorderView(Context context) { |
26 | public MovieRecorderView(Context context, AttributeSet attrs) { |
27 | this (context, attrs, 0 ); |
30 | @SuppressLint ( "NewApi" ) |
31 | public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) { |
32 | super (context, attrs, defStyle); |
34 | TypedArray a = context.obtainStyledAttributes(attrs, |
35 | R.styleable.MovieRecorderView, defStyle, 0 ); |
36 | mWidth = a.getInteger(R.styleable.MovieRecorderView_width, 320 ); |
37 | mHeight = a.getInteger(R.styleable.MovieRecorderView_height, 240 ); |
39 | isOpenCamera = a.getBoolean( |
40 | R.styleable.MovieRecorderView_is_open_camera, true ); |
41 | mRecordMaxTime = a.getInteger( |
42 | R.styleable.MovieRecorderView_record_max_time, 10 ); |
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); |
50 | mSurfaceHolder = mSurfaceView.getHolder(); |
51 | mSurfaceHolder.addCallback( new CustomCallBack()); |
52 | mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
60 | private class CustomCallBack implements Callback { |
63 | public void surfaceCreated(SurfaceHolder holder) { |
68 | } catch (IOException e) { |
74 | public void surfaceChanged(SurfaceHolder holder, int format, int width, |
80 | public void surfaceDestroyed(SurfaceHolder holder) { |
91 | private void initCamera() throws IOException { |
92 | if (mCamera != null ) { |
96 | mCamera = Camera.open(); |
97 | } catch (Exception e) { |
105 | mCamera.setDisplayOrientation( 90 ); |
106 | mCamera.setPreviewDisplay(mSurfaceHolder); |
107 | mCamera.startPreview(); |
114 | private void setCameraParams() { |
115 | if (mCamera != null ) { |
116 | Parameters params = mCamera.getParameters(); |
117 | params.set( "orientation" , "portrait" ); |
118 | mCamera.setParameters(params); |
125 | private void freeCameraResource() { |
126 | if (mCamera != null ) { |
127 | mCamera.setPreviewCallback( null ); |
128 | mCamera.stopPreview(); |
135 | private void createRecordDir() { |
137 | File sampleDir = new File(Environment.getExternalStorageDirectory() |
138 | + File.separator + "ysb/video/" ); |
139 | if (!sampleDir.exists()) { |
142 | File vecordDir = sampleDir; |
145 | mVecordFile = File.createTempFile( "recording" , ".mp4" , vecordDir); |
146 | } catch (IOException e) { |
153 | * @throws IOException |
155 | @SuppressLint ( "NewApi" ) |
156 | private void initRecord() throws IOException { |
157 | mMediaRecorder = new MediaRecorder(); |
158 | mMediaRecorder.reset(); |
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); |
169 | mMediaRecorder.setVideoEncodingBitRate( 1 * 1024 * 1024 * 100 ); |
170 | mMediaRecorder.setOrientationHint( 90 ); |
171 | mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP); |
173 | mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath()); |
174 | mMediaRecorder.prepare(); |
176 | mMediaRecorder.start(); |
177 | } catch (IllegalStateException e) { |
179 | } catch (RuntimeException e) { |
181 | } catch (Exception e) { |
190 | * @param onRecordFinishListener |
193 | public void record( final OnRecordFinishListener onRecordFinishListener) { |
194 | this .mOnRecordFinishListener = onRecordFinishListener; |
201 | mTimer = new Timer(); |
202 | mTimer.schedule( new TimerTask() { |
207 | mProgressBar.setProgress(mTimeCount); |
208 | if (mTimeCount == mRecordMaxTime) { |
210 | if (mOnRecordFinishListener != null ) |
211 | mOnRecordFinishListener.onRecordFinish(); |
215 | } catch (IOException e) { |
226 | freeCameraResource(); |
232 | public void stopRecord() { |
233 | mProgressBar.setProgress( 0 ); |
236 | if (mMediaRecorder != null ) { |
238 | mMediaRecorder.setOnErrorListener( null ); |
239 | mMediaRecorder.setPreviewDisplay( null ); |
241 | mMediaRecorder.stop(); |
242 | } catch (IllegalStateException e) { |
244 | } catch (RuntimeException e) { |
246 | } catch (Exception e) { |
255 | private void releaseRecord() { |
256 | if (mMediaRecorder != null ) { |
257 | mMediaRecorder.setOnErrorListener( null ); |
259 | mMediaRecorder.release(); |
260 | } catch (IllegalStateException e) { |
262 | } catch (Exception e) { |
266 | mMediaRecorder = null ; |
269 | public int getTimeCount() { |
274 | public File getmVecordFile() { |
281 | public interface OnRecordFinishListener { |
282 | public void onRecordFinish(); |
286 | public void onError(MediaRecorder mr, int what, int extra) { |
290 | } catch (IllegalStateException e) { |
292 | } catch (Exception e) { |
2.视频录制界面文件movie_recorder_view.xml:
1 | <span style= "font-size: medium;" ><?xml version= "1.0" encoding= "utf-8" ?> |
4 | android:layout_width= "match_parent" |
5 | android:layout_height= "match_parent" |
6 | android:background= "@android:color/background_dark" |
7 | android:orientation= "vertical" > |
10 | android:id= "@+id/surfaceview" |
11 | android:layout_width= "fill_parent" |
12 | android:layout_height= "0dp" |
13 | android:layout_weight= "1" |
17 | android:id= "@+id/progressBar" |
18 | style= "?android:attr/progressBarStyleHorizontal" |
19 | android:layout_width= "match_parent" |
20 | android:layout_height= "2dp" |
做好这些准备工作,下面我们就可以开始设计我们的视频录制功能了。PS:以上代码取至网上,在此向大牛致敬。
3.拍摄主界面,拍摄界面有两部分组成,上面是视频拍摄控件显示,下面是用户点击拍摄按钮,配置文件:
1 | <span style= "font-size: medium;" ><?xml version= "1.0" encoding= "utf-8" ?> |
4 | android:layout_width= "match_parent" |
5 | android:layout_height= "match_parent" |
6 | android:background= "@android:color/white" |
7 | android:orientation= "vertical" > |
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" /> |
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" |
23 | android:textColor= "#20b6ff" /> |
4.有了主界面的视图,下面我们就开始书写我们的Activity文件MainActivity.java:
1 | <span style= "font-size: medium;" > public class MainActivity extends Activity { |
3 | private MovieRecorderView mRecorderView; |
4 | private Button mShootBtn; |
5 | private boolean isFinish = true ; |
6 | private boolean success = false ; |
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); |
16 | mShootBtn.setOnTouchListener( new OnTouchListener() { |
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() { |
25 | public void onRecordFinish() { |
26 | if (!success&&mRecorderView.getTimeCount()< 10 ){ |
28 | handler.sendEmptyMessage( 1 ); |
32 | } else if (event.getAction() == MotionEvent.ACTION_UP) { |
33 | mShootBtn.setBackgroundResource(R.drawable.bg_movie_add_shoot); |
34 | if (mRecorderView.getTimeCount() > 3 ){ |
37 | handler.sendEmptyMessage( 1 ); |
41 | if (mRecorderView.getmVecordFile() != null ) |
42 | mRecorderView.getmVecordFile().delete(); |
44 | Toast.makeText(MainActivity. this , "视频录制时间太短" , Toast.LENGTH_SHORT).show(); |
53 | public void onResume() { |
56 | if (mRecorderView.getmVecordFile() != null ) |
57 | mRecorderView.getmVecordFile().delete(); |
61 | public void onSaveInstanceState(Bundle outState) { |
62 | super .onSaveInstanceState(outState); |
69 | public void onPause() { |
74 | public void onDestroy() { |
78 | private Handler handler = new Handler() { |
80 | public void handleMessage(Message msg) { |
88 | private void finishActivity() { |
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); |
103 | public interface OnShootCompletionListener { |
104 | public void OnShootSuccess(String path, int second); |
105 | public void OnShootFailure(); |
到这里我们仿微信的短视频拍摄就已经大功告成,那么下面我们检验一下,我们录制的效果如何,下面我以Android提供的视频播放控件(VideoView)为大家介绍一下如何播放录制的短视频。
5.播放视频的配置文件activity_success.xml:
1 | <span style= "font-size: medium;" ><?xml version= "1.0" encoding= "utf-8" ?> |
4 | android:layout_width= "match_parent" |
5 | android:layout_height= "match_parent" |
6 | android:background= "@android:color/white" |
7 | android:orientation= "vertical" > |
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" /> |
16 | android:layout_width= "match_parent" |
17 | android:layout_height= "wrap_content" |
18 | android:orientation= "horizontal" |
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" |
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" |
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" |
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" |
58 | android:id= "@+id/videoView1" |
59 | android:layout_width= "wrap_content" |
60 | android:layout_height= "500dp" /> |
6.视频播放的控制代码SuccessActivity.java:
1 | <span style= "font-size: medium;" > public class SuccessActivity extends Activity implements OnClickListener{ |
4 | private Button button1; |
5 | private Button button2; |
6 | private Button button3; |
7 | private Button button4; |
8 | private VideoView videoView1; |
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" ); |
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); |
32 | private void setValue() { |
34 | button1.setOnClickListener( this ); |
35 | button2.setOnClickListener( this ); |
36 | button3.setOnClickListener( this ); |
37 | button4.setOnClickListener( this ); |
38 | videoView1.setVideoPath(file); |
42 | public void onClick(View v) { |
58 | Toast.makeText( this , "视频长度:" +(videoView1.getDuration()/ 1024 )+ "M" , Toast.LENGTH_SHORT).show(); |
功能界面截图:


好了,到这里关于拍摄短视频的知识就和大家分享完毕,具体的实现很简单,相信大家看到这里已经已经学会了。
本文到此结束,需要的朋友可以参考下。