近期比較忙,非常久没更新博客,今天我们仿一个美拍或者糗事百科的录像功能。

首先确认步奏:

1、打开摄像头;

2、開始录制;

3、支持分段录制,并支持分段删除;

4、把分段录制的视频进行合并;

不说废话了先上图:

事实上布局没什么好看的,布局就不看了。直接上代码。

  1. package com.example.shipin;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import android.annotation.SuppressLint;
  7. import android.app.AlertDialog;
  8. import android.app.AlertDialog.Builder;
  9. import android.content.DialogInterface;
  10. import android.content.Intent;
  11. import android.content.SharedPreferences;
  12. import android.graphics.Color;
  13. import android.hardware.Camera;
  14. import android.hardware.Camera.CameraInfo;
  15. import android.hardware.Camera.Parameters;
  16. import android.media.CamcorderProfile;
  17. import android.media.MediaRecorder;
  18. import android.media.MediaRecorder.OnErrorListener;
  19. import android.media.MediaRecorder.OnInfoListener;
  20. import android.os.Build;
  21. import android.os.Bundle;
  22. import android.os.CountDownTimer;
  23. import android.os.Environment;
  24. import android.os.Handler;
  25. import android.preference.PreferenceManager;
  26. import android.provider.MediaStore;
  27. import android.view.KeyEvent;
  28. import android.view.MotionEvent;
  29. import android.view.SurfaceHolder;
  30. import android.view.SurfaceView;
  31. import android.view.View;
  32. import android.view.View.OnClickListener;
  33. import android.view.View.OnTouchListener;
  34. import android.widget.ImageButton;
  35. import android.widget.ImageView;
  36. import android.widget.LinearLayout;
  37. import android.widget.RelativeLayout.LayoutParams;
  38. import android.widget.Toast;
  39. public class VideoNewActivity extends BaseActivity implements SurfaceHolder.Callback {
  40. /** 视频最大支持15秒 */
  41. public static final int VIDEO_TIME_END = 15;
  42. /** 视频最少必须5秒 */
  43. public static final int VIDEO_TIME = 5;
  44. /** 最少得录制多少秒 */
  45. private ImageView img_at_last;
  46. /** 闪现光标图片 */
  47. private ImageView img_shan;
  48. /** 删除录制 */
  49. private ImageView img_delete;
  50. /** 開始录制 */
  51. private ImageButton img_start;
  52. /** 确认 */
  53. private ImageView img_enter;
  54. /** 闪光灯切换 */
  55. private ImageView img_flashlight;
  56. /** 摄像头切换 */
  57. private ImageView img_camera;
  58. /** 选择录像 */
  59. private ImageView img_video;
  60. /** 返回button */
  61. private ImageView img_back;
  62. /** 计时器 */
  63. private TimeCount timeCount;
  64. /** 录制了多少秒 */
  65. private int now;
  66. /** 每次录制结束时是多少秒 */
  67. private int old;
  68. /** 录制进度控件 */
  69. private LinearLayout linear_seekbar;
  70. /** 屏幕宽度 */
  71. private int width;
  72. /** 偶数才运行 */
  73. private int even;
  74. /** 是否点击删除了一次 */
  75. private boolean isOnclick = false;
  76. /** 录制视频集合 */
  77. private ArrayList<VideoNewBean> list;
  78. /** 录制bean */
  79. private VideoNewBean bean;
  80. /** 为了能保存到bundler 录制bean */
  81. private VideoNewParentBean parent_bean;
  82. /** 录制视频保存文件 */
  83. private String vedioPath;
  84. /** 合并之后的视频文件 */
  85. private String videoPath_merge;
  86. /** 是否满足视频的最少播放时长 */
  87. private boolean isMeet = false;
  88. /** 录制视频的类 */
  89. private MediaRecorder mMediaRecorder;
  90. /** 摄像头对象 */
  91. private Camera mCamera;
  92. /** 显示的view */
  93. private SurfaceView surfaceView;
  94. /** 摄像头參数 */
  95. private Parameters mParameters;
  96. // /** 视频输出质量 */
  97. private CamcorderProfile mProfile;
  98. /** 文本属性获取器 */
  99. private SharedPreferences mPreferences;
  100. /** 刷新界面的回调 */
  101. private SurfaceHolder mHolder;
  102. /** 1表示后置,0表示前置 */
  103. private int cameraPosition = 1;
  104. /** 路径 */
  105. private String Ppath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/videoTest/";
  106. // /** 压缩jni */
  107. // private LoadJNI vk;
  108. @Override
  109. protected int getContentViewId() {
  110. return R.layout.activity_video_new;
  111. }
  112. @SuppressWarnings("deprecation")
  113. @Override
  114. protected void findViews() {
  115. img_camera = (ImageView) findViewById(R.id.video_new_img_right);
  116. img_flashlight = (ImageView) findViewById(R.id.video_new_img_flashlight);
  117. surfaceView = (SurfaceView) findViewById(R.id.video_new_surfaceview);
  118. img_at_last = (ImageView) findViewById(R.id.video_new_img_time_atlast);
  119. img_shan = (ImageView) findViewById(R.id.video_new_img_time_start);
  120. img_delete = (ImageView) findViewById(R.id.video_new_img_delete);
  121. img_start = (ImageButton) findViewById(R.id.video_new_img_start);
  122. img_enter = (ImageView) findViewById(R.id.video_new_img_enter);
  123. img_back = (ImageView) findViewById(R.id.video_new_img_back);
  124. img_video = (ImageView) findViewById(R.id.video_new_img_video);
  125. linear_seekbar = (LinearLayout) findViewById(R.id.video_new_seekbar);
  126. width = getWindowManager().getDefaultDisplay().getWidth();
  127. LayoutParams layoutParam = (LayoutParams) surfaceView.getLayoutParams();
  128. // 高:宽 4 : 3
  129. layoutParam.height = width / 3 * 4;
  130. // 隐藏多少dp才干让屏幕显示正常像素
  131. layoutParam.topMargin = -(width / 3 * 4 - width - DisplayUtil.dip2px(VideoNewActivity.this, 44));
  132. surfaceView.setLayoutParams(layoutParam);
  133. LayoutParams layoutParams = (LayoutParams) img_at_last.getLayoutParams();
  134. layoutParams.leftMargin = width / VIDEO_TIME_END * VIDEO_TIME;
  135. img_at_last.setLayoutParams(layoutParams);
  136. }
  137. @Override
  138. protected void onSaveInstanceState(Bundle outState) {
  139. parent_bean.setList(list);
  140. outState.putSerializable("parent_bean", parent_bean);
  141. super.onSaveInstanceState(outState);
  142. }
  143. @Override
  144. protected void onRestoreInstanceState(Bundle savedInstanceState) {
  145. parent_bean = (VideoNewParentBean) savedInstanceState.getSerializable("parent_bean");
  146. list = parent_bean.getList();
  147. super.onRestoreInstanceState(savedInstanceState);
  148. }
  149. @SuppressWarnings("deprecation")
  150. @Override
  151. protected void init() {
  152. handler.postDelayed(runnable, 0);
  153. even = 0;
  154. old = 0;
  155. // 创建目录
  156. File file = new File(Ppath);
  157. if (!file.exists()) {
  158. file.mkdir();
  159. }
  160. list = new ArrayList<VideoNewBean>();
  161. parent_bean = new VideoNewParentBean();
  162. // 安装一个SurfaceHolder.Callback
  163. mHolder = surfaceView.getHolder();
  164. mHolder.addCallback(this);
  165. // 针对低于3.0的Android
  166. mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  167. mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
  168. readVideoPreferences();
  169. }
  170. @Override
  171. protected void onStart() {
  172. super.onStart();
  173. // 获取Camera实例
  174. mCamera = getCamera();
  175. if (mCamera != null) {
  176. // 因为android不支持竖屏录制,所以须要顺时针转90度。让其游览器显示正常
  177. mCamera.setDisplayOrientation(90);
  178. mCamera.lock();
  179. initCameraParameters();
  180. }
  181. }
  182. @Override
  183. protected void onPause() {
  184. super.onPause();
  185. releaseCamera();
  186. }
  187. /**
  188. * 获取摄像头实例
  189. *
  190. * @version 1.0
  191. * @createTime 2015年6月16日,上午10:44:11
  192. * @updateTime 2015年6月16日,上午10:44:11
  193. * @createAuthor WangYuWen
  194. * @updateAuthor WangYuWen
  195. * @updateInfo (此处输入改动内容,若无改动可不写.)
  196. *
  197. * @return
  198. */
  199. private Camera getCamera() {
  200. Camera camera = null;
  201. try {
  202. camera = Camera.open();
  203. } catch (Exception e) {
  204. camera = null;
  205. }
  206. return camera;
  207. }
  208. private Handler handler = new Handler();
  209. private Runnable runnable = new Runnable() {
  210. @Override
  211. public void run() {
  212. if (img_shan.isShown()) {
  213. img_shan.setVisibility(View.GONE);
  214. } else {
  215. img_shan.setVisibility(View.VISIBLE);
  216. }
  217. handler.postDelayed(runnable, 500);
  218. }
  219. };
  220. @SuppressLint("ClickableViewAccessibility")
  221. @Override
  222. protected void widgetListener() {
  223. img_start.setOnTouchListener(new OnTouchListener() {
  224. @Override
  225. public boolean onTouch(View v, MotionEvent event) {
  226. switch (event.getAction()) {
  227. case MotionEvent.ACTION_DOWN:
  228. if (isOnclick) {
  229. ((ImageView) linear_seekbar.getChildAt(linear_seekbar.getChildCount() - 2)).setBackgroundColor(getResources().getColor(
  230. R.color.ff1f8fe4));
  231. }
  232. even = 1;
  233. img_delete.setVisibility(View.VISIBLE);
  234. img_enter.setVisibility(View.VISIBLE);
  235. img_video.setVisibility(View.GONE);
  236. img_camera.setVisibility(View.GONE);
  237. addView_Red();
  238. // 构造CountDownTimer对象
  239. timeCount = new TimeCount(30000 - old, 50);
  240. timeCount.start();// 開始计时
  241. startRecord();
  242. break;
  243. case MotionEvent.ACTION_UP:
  244. old = now + old;
  245. if (old >= VIDEO_TIME * 1000) {
  246. isMeet = true;
  247. }
  248. timeCount.cancel();
  249. addView_black();
  250. stopRecord();
  251. break;
  252. }
  253. return false;
  254. }
  255. });
  256. /** 删除button */
  257. img_delete.setOnClickListener(new OnClickListener() {
  258. @Override
  259. public void onClick(View v) {
  260. isOnclick = false;
  261. if (even % 2 == 0) {
  262. if (linear_seekbar.getChildCount() > 1) {
  263. linear_seekbar.removeViewAt(linear_seekbar.getChildCount() - 1);
  264. linear_seekbar.removeViewAt(linear_seekbar.getChildCount() - 1);
  265. }
  266. if (list.size() > 0) {
  267. for (int i = 0; i < list.size(); i++) {
  268. File file = new File(list.get(list.size() - 1).getPath());
  269. if (file.exists()) {
  270. file.delete();
  271. }
  272. }
  273. old -= list.get(list.size() - 1).getTime();
  274. list.remove(list.size() - 1);
  275. if (old < VIDEO_TIME * 1000) {
  276. isMeet = false;
  277. }
  278. if (list.size() <= 0) {
  279. img_delete.setVisibility(View.GONE);
  280. img_enter.setVisibility(View.GONE);
  281. img_video.setVisibility(View.VISIBLE);
  282. img_camera.setVisibility(View.VISIBLE);
  283. }
  284. }
  285. } else {
  286. if (linear_seekbar.getChildCount() > 1) {
  287. isOnclick = true;
  288. ((ImageView) linear_seekbar.getChildAt(linear_seekbar.getChildCount() - 2)).setBackgroundColor(getResources().getColor(
  289. R.color.ff135689));
  290. }
  291. }
  292. even++;
  293. }
  294. });
  295. /** 开启或关闭闪光灯 */
  296. img_flashlight.setOnClickListener(new OnClickListener() {
  297. @Override
  298. public void onClick(View v) {
  299. if (cameraPosition != 0) {// 前置摄像头的时候不能切换闪光灯
  300. if (mParameters != null) {
  301. if (mParameters.getFlashMode() != null && mParameters.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
  302. mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
  303. img_flashlight.setImageResource(R.drawable.img_video_new_flashlight_close);
  304. } else if (mParameters.getFlashMode() != null && mParameters.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) {
  305. mParameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
  306. img_flashlight.setImageResource(R.drawable.img_video_new_flashlight_open);
  307. }
  308. if (mCamera != null) {
  309. mCamera.setParameters(mParameters);
  310. }
  311. }
  312. }
  313. }
  314. });
  315. /** 摄像头切换 */
  316. img_camera.setOnClickListener(new OnClickListener() {
  317. @Override
  318. public void onClick(View v) {
  319. switchCamera();
  320. }
  321. });
  322. /** 确认button */
  323. img_enter.setOnClickListener(new OnClickListener() {
  324. @Override
  325. public void onClick(View v) {
  326. if (isMeet) {
  327. int size = list.size();
  328. String[] strs = new String[size];
  329. videoPath_merge = Ppath + System.currentTimeMillis() + ".mp4";
  330. for (int i = 0; i < size; i++) {
  331. strs[i] = list.get(i).getPath();
  332. }
  333. try {
  334. FUckTest.appendVideo(strs, videoPath_merge);
  335. for (int i = size - 1; i >= 0; i--) {
  336. File file = new File(list.get(i).getPath());
  337. if (file.exists()) {
  338. file.delete();
  339. }
  340. list.remove(i);
  341. }
  342. Intent it = new Intent(VideoNewActivity.this,VideoActivity.class);
  343. it.putExtra("path", videoPath_merge);
  344. startActivity(it);
  345. } catch (IOException e) {
  346. e.printStackTrace();
  347. }
  348. } else {
  349. Toast.makeText(VideoNewActivity.this, "视频最少必须录制5秒以上才干用!", Toast.LENGTH_LONG).show();
  350. }
  351. }
  352. });
  353. /** 选择录像button */
  354. img_video.setOnClickListener(new OnClickListener() {
  355. @Override
  356. public void onClick(View v) {
  357. //下一篇博客将会加进来
  358. }
  359. });
  360. img_back.setOnClickListener(new OnClickListener() {
  361. @Override
  362. public void onClick(View v) {
  363. if (list.size() > 0) {
  364. exitVideoNewDialog();
  365. } else {
  366. releaseCamera();
  367. finish();
  368. }
  369. }
  370. });
  371. surfaceView.setOnClickListener(new OnClickListener() {
  372. @Override
  373. public void onClick(View v) {
  374. if (mParameters != null && mCamera != null) {
  375. mParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
  376. try {
  377. mCamera.setParameters(mParameters);
  378. } catch (Exception e) {
  379. e.printStackTrace();
  380. }
  381. }
  382. }
  383. });
  384. }
  385. @Override
  386. public boolean dispatchKeyEvent(KeyEvent event) {
  387. if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
  388. if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
  389. if (list.size() > 0) {
  390. exitVideoNewDialog();
  391. } else {
  392. releaseCamera();
  393. finish();
  394. }
  395. }
  396. return true;
  397. }
  398. return super.dispatchKeyEvent(event);
  399. }
  400. /**
  401. * 弹出对话框
  402. *
  403. * @version 1.0
  404. * @createTime 2015年6月16日,下午3:45:35
  405. * @updateTime 2015年6月16日,下午3:45:35
  406. * @createAuthor WangYuWen
  407. * @updateAuthor WangYuWen
  408. * @updateInfo (此处输入改动内容,若无改动可不写.)
  409. *
  410. */
  411. private void exitVideoNewDialog() {
  412. AlertDialog.Builder builder = new Builder(VideoNewActivity.this);
  413. builder.setMessage("确定放弃这段视频吗?");
  414. builder.setTitle("温馨提示");
  415. builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
  416. @Override
  417. public void onClick(DialogInterface dialog, int which) {
  418. dialog.dismiss();
  419. for (int i = 0; i < list.size(); i++) {
  420. File file = new File(list.get(i).getPath());
  421. if (file.exists()) {
  422. file.delete();
  423. }
  424. }
  425. finish();
  426. }
  427. });
  428. builder.create().show();
  429. }
  430. /**
  431. * 切换摄像头
  432. *
  433. * @version 1.0
  434. * @createTime 2015年6月16日,上午10:40:17
  435. * @updateTime 2015年6月16日,上午10:40:17
  436. * @createAuthor WangYuWen
  437. * @updateAuthor WangYuWen
  438. * @updateInfo (此处输入改动内容,若无改动可不写.)
  439. *
  440. */
  441. @SuppressLint("NewApi")
  442. private void switchCamera() {
  443. // 切换前后摄像头
  444. int cameraCount = 0;
  445. CameraInfo cameraInfo = new CameraInfo();
  446. cameraCount = Camera.getNumberOfCameras();// 得到摄像头的个数
  447. for (int i = 0; i < cameraCount; i++) {
  448. Camera.getCameraInfo(i, cameraInfo);// 得到每个摄像头的信息
  449. if (cameraPosition == 1) {
  450. // 如今是后置。变更为前置
  451. if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {// 代表摄像头的方位。CAMERA_FACING_FRONT前置
  452. // CAMERA_FACING_BACK后置
  453. // 前置摄像头时必须关闭闪光灯。不然会报错
  454. if (mParameters != null) {
  455. if (mParameters.getFlashMode() != null && mParameters.getFlashMode().equals(Parameters.FLASH_MODE_TORCH)) {
  456. mParameters.setFlashMode(Parameters.FLASH_MODE_OFF);
  457. img_flashlight.setImageResource(R.drawable.img_video_new_flashlight_close);
  458. }
  459. if (mCamera != null) {
  460. mCamera.setParameters(mParameters);
  461. }
  462. }
  463. // 释放Camera
  464. releaseCamera();
  465. // 打开当前选中的摄像头
  466. mCamera = Camera.open(i);
  467. mCamera.setDisplayOrientation(90);
  468. mCamera.lock();
  469. // 通过surfaceview显示取景画面
  470. setStartPreview(mHolder);
  471. cameraPosition = 0;
  472. break;
  473. }
  474. } else {
  475. // 如今是前置, 变更为后置
  476. if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {// 代表摄像头的方位,CAMERA_FACING_FRONT前置
  477. // CAMERA_FACING_BACK后置
  478. // 释放Camera
  479. releaseCamera();
  480. // 打开当前选中的摄像头
  481. mCamera = Camera.open(i);
  482. mCamera.setDisplayOrientation(90);
  483. mCamera.lock();
  484. // 通过surfaceview显示取景画面
  485. setStartPreview(mHolder);
  486. cameraPosition = 1;
  487. break;
  488. }
  489. }
  490. }
  491. }
  492. /**
  493. * 定义一个倒计时的内部类
  494. *
  495. * @Description
  496. * @author
  497. * @version 1.0
  498. * @date 2015-5-25
  499. * @Copyright: Copyright (c) 2015 Shenzhen Utoow Technology Co., Ltd.
  500. * All rights reserved.
  501. */
  502. private class TimeCount extends CountDownTimer {
  503. public TimeCount(long millisInFuture, long countDownInterval) {
  504. super(millisInFuture, countDownInterval);// 參数依次为总时长,和计时的时间间隔
  505. }
  506. @Override
  507. public void onFinish() {// 计时完成时触发
  508. }
  509. @Override
  510. public void onTick(long millisUntilFinished) {// 计时过程显示
  511. now = (int) (30000 - millisUntilFinished - old);
  512. if ((old > 0 && old > VIDEO_TIME * 1000) || (old == 0 && now > VIDEO_TIME * 1000)) {
  513. img_enter.setEnabled(true);
  514. }
  515. if (linear_seekbar.getChildCount() > 0) {
  516. ImageView img = (ImageView) linear_seekbar.getChildAt(linear_seekbar.getChildCount() - 1);
  517. LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) img.getLayoutParams();
  518. layoutParams.width = (int) (((float) now / 1000f) * (width / VIDEO_TIME_END)) + 1;
  519. img.setLayoutParams(layoutParams);
  520. }
  521. }
  522. }
  523. /**
  524. * 初始化摄像头參数
  525. *
  526. * @version 1.0
  527. * @createTime 2015年6月15日,下午4:53:41
  528. * @updateTime 2015年6月15日,下午4:53:41
  529. * @createAuthor WangYuWen
  530. * @updateAuthor WangYuWen
  531. * @updateInfo (此处输入改动内容,若无改动可不写.)
  532. *
  533. */
  534. @SuppressWarnings("deprecation")
  535. private void initCameraParameters() {
  536. // 初始化摄像头參数
  537. mParameters = mCamera.getParameters();
  538. mParameters.setPreviewSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
  539. mParameters.setPreviewFrameRate(mProfile.videoFrameRate);
  540. mParameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
  541. // 设置白平衡參数。
  542. String whiteBalance = mPreferences.getString("pref_camera_whitebalance_key", "auto");
  543. if (isSupported(whiteBalance, mParameters.getSupportedWhiteBalance())) {
  544. mParameters.setWhiteBalance(whiteBalance);
  545. }
  546. // 參数设置颜色效果。
  547. String colorEffect = mPreferences.getString("pref_camera_coloreffect_key", "none");
  548. if (isSupported(colorEffect, mParameters.getSupportedColorEffects())) {
  549. mParameters.setColorEffect(colorEffect);
  550. }
  551. try {
  552. mCamera.setParameters(mParameters);
  553. } catch (Exception e) {
  554. e.printStackTrace();
  555. }
  556. }
  557. /**
  558. * 開始录制
  559. *
  560. * @version 1.0
  561. * @createTime 2015年6月15日,下午4:48:49
  562. * @updateTime 2015年6月15日,下午4:48:49
  563. * @createAuthor WangYuWen
  564. * @updateAuthor WangYuWen
  565. * @updateInfo (此处输入改动内容,若无改动可不写.)
  566. *
  567. */
  568. @SuppressLint("NewApi")
  569. private void startRecord() {
  570. try {
  571. bean = new VideoNewBean();
  572. vedioPath = Ppath + System.currentTimeMillis() + ".mp4";
  573. bean.setPath(vedioPath);
  574. mCamera.unlock();
  575. mMediaRecorder = new MediaRecorder();// 创建mediaRecorder对象
  576. mMediaRecorder.setCamera(mCamera);
  577. // 设置录制视频源为Camera(相机)
  578. mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
  579. mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
  580. mMediaRecorder.setProfile(mProfile);
  581. // mMediaRecorder.setVideoSize(560,560);//设置视频大小(分辨率)
  582. mMediaRecorder.setVideoEncodingBitRate(1024 * 1024);// 设置视频一次写多少字节(可调节视频空间大小)
  583. // 最大期限
  584. mMediaRecorder.setMaxDuration(35 * 1000);
  585. // 第4步:指定输出文件 , 设置视频文件输出的路径
  586. mMediaRecorder.setOutputFile(vedioPath);
  587. mMediaRecorder.setPreviewDisplay(mHolder.getSurface());
  588. // // 设置保存录像方向
  589. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
  590. if (cameraPosition == 1) {
  591. //因为不支持竖屏录制。后置摄像头须要把视频顺时针旋转90度、、可是视频本身在电脑上看还是逆时针旋转了90度
  592. mMediaRecorder.setOrientationHint(90);
  593. } else if (cameraPosition == 0) {
  594. //因为不支持竖屏录制,前置摄像头须要把视频顺时针旋转270度、、而前置摄像头在电脑上则是顺时针旋转了90度
  595. mMediaRecorder.setOrientationHint(270);
  596. }
  597. }
  598. mMediaRecorder.setOnInfoListener(new OnInfoListener() {
  599. @Override
  600. public void onInfo(MediaRecorder mr, int what, int extra) {
  601. }
  602. });
  603. mMediaRecorder.setOnErrorListener(new OnErrorListener() {
  604. @Override
  605. public void onError(MediaRecorder mr, int what, int extra) {
  606. recodError();
  607. }
  608. });
  609. // 第6步:依据以上配置准备MediaRecorder
  610. mMediaRecorder.prepare();
  611. mMediaRecorder.start();
  612. } catch (IllegalStateException e) {
  613. e.printStackTrace();
  614. recodError();
  615. } catch (IOException e) {
  616. e.printStackTrace();
  617. recodError();
  618. } catch (RuntimeException e) {
  619. e.printStackTrace();
  620. recodError();
  621. }
  622. }
  623. /**
  624. * 异常处理
  625. *
  626. * @version 1.0
  627. * @createTime 2015年6月16日,上午10:49:18
  628. * @updateTime 2015年6月16日,上午10:49:18
  629. * @createAuthor WangYuWen
  630. * @updateAuthor WangYuWen
  631. * @updateInfo (此处输入改动内容,若无改动可不写.)
  632. *
  633. */
  634. private void recodError() {
  635. AlertDialog.Builder builder = new Builder(VideoNewActivity.this);
  636. builder.setMessage("该设备暂不支持视频录制");
  637. builder.setTitle("出错啦");
  638. builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
  639. @Override
  640. public void onClick(DialogInterface dialog, int which) {
  641. dialog.dismiss();
  642. finish();
  643. }
  644. });
  645. builder.create().show();
  646. }
  647. /**
  648. * 结束录制
  649. *
  650. * @version 1.0
  651. * @createTime 2015年6月15日,下午4:48:53
  652. * @updateTime 2015年6月15日,下午4:48:53
  653. * @createAuthor WangYuWen
  654. * @updateAuthor WangYuWen
  655. * @updateInfo (此处输入改动内容,若无改动可不写.)
  656. *
  657. */
  658. private void stopRecord() {
  659. if (bean != null) {
  660. if (list.size() > 0) {
  661. bean.setTime(now - list.get(list.size() - 1).getTime());
  662. } else {
  663. bean.setTime(now);
  664. }
  665. bean.setCameraPosition(cameraPosition);
  666. list.add(bean);
  667. }
  668. if (mMediaRecorder != null) {
  669. try {
  670. // 停止录像,释放camera
  671. mMediaRecorder.setOnErrorListener(null);
  672. mMediaRecorder.setOnInfoListener(null);
  673. mMediaRecorder.stop();
  674. // 清除recorder配置
  675. mMediaRecorder.reset();
  676. // 释放recorder对象
  677. mMediaRecorder.release();
  678. mMediaRecorder = null;
  679. // 没超过3秒就删除录制全部数据
  680. if (old < 3000) {
  681. clearList();
  682. }
  683. } catch (Exception e) {
  684. clearList();
  685. }
  686. }
  687. }
  688. /**
  689. * 清楚数据
  690. *
  691. * @version 1.0
  692. * @createTime 2015年6月25日,下午6:04:28
  693. * @updateTime 2015年6月25日,下午6:04:28
  694. * @createAuthor WangYuWen
  695. * @updateAuthor WangYuWen
  696. * @updateInfo (此处输入改动内容,若无改动可不写.)
  697. *
  698. */
  699. private void clearList() {
  700. Toast.makeText(VideoNewActivity.this, "单次录制视频最少3秒", Toast.LENGTH_LONG).show();
  701. if (linear_seekbar.getChildCount() > 1) {
  702. linear_seekbar.removeViewAt(linear_seekbar.getChildCount() - 1);
  703. linear_seekbar.removeViewAt(linear_seekbar.getChildCount() - 1);
  704. }
  705. if (list.size() > 0) {
  706. for (int i = 0; i < list.size(); i++) {
  707. File file = new File(list.get(list.size() - 1).getPath());
  708. if (file.exists()) {
  709. file.delete();
  710. }
  711. }
  712. list.remove(list.size() - 1);
  713. if (list.size() <= 0) {
  714. img_delete.setVisibility(View.GONE);
  715. img_enter.setVisibility(View.GONE);
  716. img_video.setVisibility(View.VISIBLE);
  717. img_camera.setVisibility(View.VISIBLE);
  718. }
  719. }
  720. }
  721. private static boolean isSupported(String value, List<String> supported) {
  722. return supported == null ? false : supported.indexOf(value) >= 0;
  723. }
  724. public static boolean getVideoQuality(String quality) {
  725. return "youtube".equals(quality) || "high".equals(quality);
  726. }
  727. /**
  728. * 设置摄像头參数
  729. *
  730. * @version 1.0
  731. * @createTime 2015年6月15日,下午5:12:31
  732. * @updateTime 2015年6月15日,下午5:12:31
  733. * @createAuthor WangYuWen
  734. * @updateAuthor WangYuWen
  735. * @updateInfo (此处输入改动内容,若无改动可不写.)
  736. *
  737. */
  738. private void readVideoPreferences() {
  739. String quality = mPreferences.getString("pref_video_quality_key", "high");
  740. boolean videoQualityHigh = getVideoQuality(quality);
  741. // 设置视频质量。
  742. Intent intent = getIntent();
  743. if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) {
  744. int extraVideoQuality = intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
  745. videoQualityHigh = (extraVideoQuality > 0);
  746. }
  747. videoQualityHigh = false;
  748. mProfile = CamcorderProfile.get(videoQualityHigh ? CamcorderProfile.QUALITY_HIGH : CamcorderProfile.QUALITY_LOW);
  749. mProfile.videoFrameWidth = (int) (mProfile.videoFrameWidth * 2.0f);
  750. mProfile.videoFrameHeight = (int) (mProfile.videoFrameHeight * 2.0f);
  751. mProfile.videoBitRate = 256000 * 3;
  752. CamcorderProfile highProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
  753. mProfile.videoCodec = highProfile.videoCodec;
  754. mProfile.audioCodec = highProfile.audioCodec;
  755. mProfile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
  756. }
  757. /**
  758. * 加入红色进度条
  759. *
  760. * @version 1.0
  761. * @createTime 2015年6月15日,下午3:04:21
  762. * @updateTime 2015年6月15日,下午3:04:21
  763. * @createAuthor WangYuWen
  764. * @updateAuthor WangYuWen
  765. * @updateInfo (此处输入改动内容,若无改动可不写.)
  766. *
  767. */
  768. private void addView_Red() {
  769. ImageView img = new ImageView(VideoNewActivity.this);
  770. img.setBackgroundColor(getResources().getColor(R.color.ff1f8fe4));
  771. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DisplayUtil.dip2px(VideoNewActivity.this, 1), LinearLayout.LayoutParams.MATCH_PARENT);
  772. img.setLayoutParams(layoutParams);
  773. linear_seekbar.addView(img);
  774. }
  775. /**
  776. * 加入黑色断条
  777. *
  778. * @version 1.0
  779. * @createTime 2015年6月15日,下午3:03:52
  780. * @updateTime 2015年6月15日,下午3:03:52
  781. * @createAuthor WangYuWen
  782. * @updateAuthor WangYuWen
  783. * @updateInfo (此处输入改动内容,若无改动可不写.)
  784. *
  785. */
  786. private void addView_black() {
  787. ImageView img = new ImageView(VideoNewActivity.this);
  788. img.setBackgroundColor(Color.BLACK);
  789. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DisplayUtil.dip2px(VideoNewActivity.this, 2), LinearLayout.LayoutParams.MATCH_PARENT);
  790. img.setLayoutParams(layoutParams);
  791. linear_seekbar.addView(img);
  792. }
  793. @Override
  794. public void surfaceCreated(SurfaceHolder holder) {
  795. setStartPreview(holder);
  796. }
  797. @Override
  798. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  799. // 先开启在关闭 先开启录制在关闭能够 解决游览的时候比較卡顿的现象,可是会有视频开启时声音。打开这个功能时较慢
  800. // startRecord();
  801. // stopRecord();
  802. }
  803. @Override
  804. public void surfaceDestroyed(SurfaceHolder holder) {
  805. releaseCamera();
  806. }
  807. /**
  808. * 设置camera显示取景画面,并预览
  809. *
  810. * @version 1.0
  811. * @createTime 2015年6月16日,上午10:48:15
  812. * @updateTime 2015年6月16日,上午10:48:15
  813. * @createAuthor WangYuWen
  814. * @updateAuthor WangYuWen
  815. * @updateInfo (此处输入改动内容,若无改动可不写.)
  816. *
  817. * @param holder
  818. */
  819. private void setStartPreview(SurfaceHolder holder) {
  820. try {
  821. if (mCamera != null) {
  822. mCamera.setPreviewDisplay(holder);
  823. mCamera.startPreview();
  824. }
  825. } catch (IOException e) {
  826. }
  827. }
  828. /**
  829. * 释放Camera
  830. *
  831. * @version 1.0
  832. * @createTime 2015年6月16日,上午10:38:08
  833. * @updateTime 2015年6月16日,上午10:38:08
  834. * @createAuthor WangYuWen
  835. * @updateAuthor WangYuWen
  836. * @updateInfo (此处输入改动内容,若无改动可不写.)
  837. *
  838. */
  839. private void releaseCamera() {
  840. if (mCamera != null) {
  841. mCamera.setPreviewCallback(null);
  842. mCamera.stopPreview();// 停掉原来摄像头的预览
  843. mCamera.release();
  844. mCamera = null;
  845. }
  846. }
  847. }

核心代码就这么点。bean之类的其它工具类的没贴出来,假设须要看效果的朋友能够去下载demo;

希望大家多多关注我的博客。多多支持我。

如有好意见或更好的方式欢迎留言谈论。

尊重原创转载请注明:(http://blog.csdn.net/u013895206) 。

以下是地址传送门:

http://download.csdn.net/detail/u013895206/8850751

android 视频开发2分之1(仿美拍,糗百)的更多相关文章

  1. android 视频开发2分之2(仿美拍,糗百)

    上一篇写了分段录制和合并视频.这一篇则是选择视频,然后截断视频. 1.从sdcard中找到视频资源: 2.分析视频,拿到你须要的帧数当你的图片.(我的是依据參数来算的多少秒1帧的图片,通常是1秒1帧来 ...

  2. Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  3. Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  4. 本人讲课时录制的Android应用开发技术教学视频

    网盘地址:http://yun.baidu.com/pcloud/album/info?query_uk=1963923831&album_id=3523786484935252365 本人讲 ...

  5. 移动开发 android 入门开发 阶段视频

    一直想把 android 的开发学习录制成视频,这里录制了一部分供大家学习. http://www.chuanke.com/s5402069.html 到这里,文档,源码,视频基本就全了,祝愿大家能够 ...

  6. Android IOS WebRTC 音视频开发总结(四六)-- 从另一个角度看国内首届WebRTC大会

    文章主要从开发者角度谈国内首届WebRTC大会,支持原创,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,更多详见www.rtc.help. -------------------- ...

  7. Android IOS WebRTC 音视频开发总结(六)-- iOS开发之含泪经验

    前段时间在搞webrtc iOS开发,所以将标题改为了Android IOS WebRTC 音视频开发总结, 下面都是开发过程中的经验总结,转载请说明出处(博客园RTC.Blacker): 1. IO ...

  8. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  9. Android 音视频开发(一) : 通过三种方式绘制图片

    版权声明:转载请说明出处:http://www.cnblogs.com/renhui/p/7456956.html 在 Android 音视频开发学习思路 里面,我们写到了,想要逐步入门音视频开发,就 ...

随机推荐

  1. Http请求1

    package Test; import java.io.IOException; import java.io.InputStreamReader; import java.net.URISynta ...

  2. idea安装插件plugin(主要针对网络连接不上的情况)

    https://blog.csdn.net/duoduo1636546/article/details/80104711

  3. Scala-基础-流程控制语句

    import junit.framework.TestCase import scala.util.control.Breaks._ //流程控制语句 //关键字 if else match clas ...

  4. 在C语言中模仿java的LinkedList集合的使用(不要错过哦)

    在C语言中,多个数据的储存通常会用到数组.但是C语言的数组有个缺陷,就是固定长度,超过数组的最大长度就会溢出.怎样实现N个数储存起来而不被溢出呢. 学过java的都知道,java.util包里有一个L ...

  5. HTML5 页面调用微信接口

    参考微信微信官方文档JS_SDK:https://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#JSSDK.E4.BD.B ...

  6. 继续C#开发or转做产品

    本人今年大四,C#开发,在一家公司实习了一年后,面临一个选择,是继续C#开发还是转做产品?我C#开发能力目前还一般,但很有兴趣.也喜欢设计与创意,做过产品专员.求大婶们指导!

  7. tomcat日志详释

    1.tomcat的日志分类: 一是运行中的日志,它主要记录运行的一些信息,尤其是一些异常错误日志信息 . 二是访问日志信息,它记录的访问的时间,IP ,访问的资料等相关信息. 2.tomcat的日志目 ...

  8. Fiddler——基本常识

    web session界面 inspector面板 xml:查看XML数据 json:查看json数据 raw:可以完整查看请求的内容 cookies:可以查看请求的cookie header:查看请 ...

  9. Exceptions & Errors - 异常与错误

    来源于 Ry’s Objective-C Tutorial - RyPress 一个学习Objective-C基础知识的网站. 个人觉得很棒,所以决定抽时间把章节翻译一下. 本人的英语水平有限,有让大 ...

  10. spring 实例 bean 的方式

    一.使用构造器实例化: <bean id="personService" class="cn.mytest.service.impl.PersonServiceBe ...