最近在项目中遇到了视频的拍摄上传及本地预览功能,特地记录一下

1、基于本地视频的预览采用cardview进行显示,因此需要引入相应的jar包,我这里AS使用的是

compile 'com.android.support:cardview-v7:26.+'
compile 'com.android.support:design:26.+'

2、新建一个录制视频的界面如图

android 上传视频和图片不显示 安卓实现上传视频_ide

点击拍摄时进行视频拍摄,点击确定则返回相应的视频存储路径。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/tv_time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="注:最多可以录制30秒"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal">
            <Button
                android:id="@+id/btn_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="取消"
                />
            <Button
                android:id="@+id/btn"
                android:text="拍摄"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="15dp"/>
            <Button
                android:id="@+id/btn_sure"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="确定"
                android:layout_marginLeft="15dp"/>
        </LinearLayout>

    </LinearLayout>
</LinearLayout>

 3、接下来则是代码实现(文末有全部代码)

第一步当然是检查设备是否有摄像头,如果都没有摄像头,还谈什么视频拍摄呢

private boolean checkCameraHardware(Context context){
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            ToastUtils.showToast(context, "successfully detact camera!");
            return true;
        }
        else {
            ToastUtils.showToast(context, "not detact camera!!!");
            return false;
        }
    }

 核心设置如下

/**
     * 创建MediaRecorder实例,并为之设定基本属性
     * @return
     */
    private boolean prepareVideoRecorder(){
        try {
            recorder = new MediaRecorder();
            mCamera.unlock();
            recorder.setCamera(mCamera);

            recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);

//            recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

            // Set output file format
            recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

            // 这两项需要放在setOutputFormat之后
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

            recorder.setVideoSize(640, 480);
            recorder.setVideoFrameRate(30); //这是重点,帧值设置得越大,占内存越大,30基本上是满足了一般的视频要求,60的话上传就费劲了
            recorder.setVideoEncodingBitRate(3 * 1024 * 1024);
            recorder.setOrientationHint(90);
            //设置记录会话的最大持续时间(毫秒)
            recorder.setMaxDuration(30 * 1000);

            recorder.setPreviewDisplay(previewView.getHolder().getSurface());
            result_path = getOutputMediaPath();
            recorder.setOutputFile(result_path);
            recorder.prepare();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

注:此功能需要的权限有

Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE

完整代码如下

public class Activity_VideoCamera extends Activity {
    private Camera mCamera;
    private CameraPreviewView previewView;
    private MediaRecorder recorder;
    private boolean isrecording = false;
    private Button btn, btn_cancel, btn_sure;
    private TextView tv_time;
    Handler startTimehandler;
    private long baseTimer;
    private Timer timer;

    private String result_path ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video);
        //动态权限申请Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO,Manifest.permission.WRITE_EXTERNAL_STORAGE
        //    这个写法有问题,就不贴代码了自己另行写法吧
        if (Build.VERSION.SDK_INT >= 23){
            CommonUtils.requestLocPermissions(this);
            CommonUtils.requestPermissions(this);
            CommonUtils.requestVideoPermissions(this);
        }

        //判断是否有摄像头
        if (!checkCameraHardware(this)) {
            return;
        };
        mCamera = getCameraInstance();
        mCamera.setDisplayOrientation(90);
        previewView = new CameraPreviewView(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(previewView);
        btn = (Button) findViewById(R.id.btn);
        btn_sure = (Button) findViewById(R.id.btn_sure);
        btn_cancel = (Button) findViewById(R.id.btn_cancel);
        tv_time = (TextView) findViewById(R.id.tv_time);
        initEvent();

        startTimehandler = new Handler(){
            public void handleMessage(android.os.Message msg) {
                 if (null != tv_time) {
                    tv_time.setText("录制时间:" + (String) msg.obj);
                 }
            }
        };
    }

    private void initEvent(){
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                if (isrecording) {
                    releaseMediaRecoder();
                    //mCamera.lock();
                    btn.setText("拍摄");
                    isrecording = false;
                    timer.cancel();
                }
                else {
                    if (prepareVideoRecorder()) {
                        recorder.start();
                        btn.setText("Stop");
                        isrecording = true;
                        tv_time.setText("录制时间:00:00:00");
                        startTimer();
                    }
                    else {
                        releaseMediaRecoder();
                        timer.cancel();
                    }
                }
            }
        });
        btn_cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    File file = new File(result_path);
                    file.delete();
                    finish();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });

        btn_sure.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.putExtra("path", result_path);
                Activity_VideoCamera.this.setResult(RESULT_OK, intent);
                Activity_VideoCamera.this.finish();
            }
        });
    }

    public void startTimer(){
        baseTimer = SystemClock.elapsedRealtime();
        timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                int time = (int)((SystemClock.elapsedRealtime() - baseTimer) / 1000);
                String hh = new DecimalFormat("00").format(time / 3600);
                String mm = new DecimalFormat("00").format(time % 3600 / 60);
                String ss = new DecimalFormat("00").format(time % 60);
                String timeFormat = new String(hh + ":" + mm + ":" + ss);
                Message msg = new Message();
                msg.obj = timeFormat;
                startTimehandler.sendMessage(msg);
            }

        }, 0, 1000L);
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecoder();
        releaseCamera();
    }

    private void releaseMediaRecoder(){
        if (recorder != null) {
            recorder.reset();
            recorder.release();
            recorder = null;
            mCamera.lock();
        }
    }

    private void releaseCamera(){
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 创建MediaRecorder实例,并为之设定基本属性
     * @return
     */
    private boolean prepareVideoRecorder(){
        try {
            recorder = new MediaRecorder();
            mCamera.unlock();
            recorder.setCamera(mCamera);

            recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);

//            recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

            // Set output file format
            recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

            // 这两项需要放在setOutputFormat之后
            recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

            recorder.setVideoSize(640, 480);
            recorder.setVideoFrameRate(30);
            recorder.setVideoEncodingBitRate(3 * 1024 * 1024);
            recorder.setOrientationHint(90);
            //设置记录会话的最大持续时间(毫秒)
            recorder.setMaxDuration(30 * 1000);

            recorder.setPreviewDisplay(previewView.getHolder().getSurface());
            result_path = getOutputMediaPath();
            recorder.setOutputFile(result_path);
            recorder.prepare();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    /**
     * 获取输出video文件目录
     * @return
     */
    private String getOutputMediaPath() {
        java.util.Date date = new java.util.Date();
        String timeTemp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(date.getTime());
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), "MyCameraApp");
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
        }

        Log.e("Error", "getOutputMediaPath file path---"+
                mediaStorageDir.getPath() + File.separator +
                "VID_" + timeTemp+ ".mp4");
        return mediaStorageDir.getPath() + File.separator +
                "VID_" + timeTemp + ".mp4";
    }

    public class CameraPreviewView extends SurfaceView implements SurfaceHolder.Callback{
        private SurfaceHolder holder;

        public CameraPreviewView(Context context, Camera camera) {
            super(context);

            holder = getHolder();
            holder.addCallback(this);
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
            // TODO Auto-generated method stub

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            if (holder.getSurface() == null) {
                return;
            }

            try {
                if(mCamera != null) {
                    holder.removeCallback(this);
                    mCamera.setPreviewCallback(null);
                    mCamera.stopPreview();
                    mCamera.lock();
                    mCamera.release();
                    mCamera = null;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }

    /**
     * 获取camera实例
     * @return
     */
    public static Camera getCameraInstance(){
        Camera camera = null;
        try {
            camera = Camera.open();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return camera;
    }

    /**
     * 检测手机有无摄像头
     * @param context
     * @return
     */
    private boolean checkCameraHardware(Context context){
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            ToastUtils.showToast(context, "successfully detact camera!");
            return true;
        }
        else {
            ToastUtils.showToast(context, "not detact camera!!!");
            return false;
        }
    }


}

 在预览界面就简单了,在onresultActivity方法中实现如下代码

if (data != null) {
         final String filepath = data.getExtras().getString("path");
         final VideoView videoView = new VideoView(context);
         Uri uri = Uri.parse(filepath);
         videoView.setLayoutParams(layoutParams);
         videoView.setVideoURI(uri);
         videoView.setMediaController(new MediaController(context));
         videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
               @Override
                public void onPrepared(MediaPlayer mp) {
//                     videoView.start();
                }
         });
         ll_pics.addView(videoView,ll_pics.getChildCount() - 1);
         Log.e(TAG, "onActivityResult: " + filepath);
         file = new File(filepath);
         Log.e(TAG, "filename----"+ file.getName());
//       receiveHandler.sendEmptyMessage(HANDLE_UPLOAD_IMG);//实现上传方法
   }

实现上传的代码我这里就不展示了,如有不足望见谅 

PS:应大家都在找我要源码,再更新一下具体使用方法吧:

1、前面Activity_VideoCamera.jvav文件和以及对于的activity_video.xml文件就不多说了,复制代码新建文件就OK了。(注:其中的动态权限申请会有异常,自己处理一下吧)

2、在调用视频拍摄时,比如在Activity页面中点击按钮调用此页面时

Intent it = new Intent(context, Activity_VideoCamera.class);
startActivityForResult(it, 11);

然后在此Activity页面重写onresultActivity方法,添加如下代码

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1){
 if (data != null) {
         final String filepath = data.getExtras().getString("path");
         final VideoView videoView = new VideoView(context);
         Uri uri = Uri.parse(filepath);
         videoView.setLayoutParams(layoutParams);
         videoView.setVideoURI(uri);
         videoView.setMediaController(new MediaController(context));
         videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
               @Override
                public void onPrepared(MediaPlayer mp) {
//                     videoView.start();
                }
         });
         ll_pics.addView(videoView,ll_pics.getChildCount() - 1);//此处自己用一个LinearLayout控件来进行装载就ok了
         Log.e(TAG, "onActivityResult: " + filepath);
         file = new File(filepath);
         Log.e(TAG, "filename----"+ file.getName());
//       receiveHandler.sendEmptyMessage(HANDLE_UPLOAD_IMG);//实现上传方法
   }
}
}