用MediaRecorder实现简单的录像功能

思路:定义一个SurfaceView用来显示预览,在SurfaceHolder的回调中用Camera对象启动预览。然后调用MediaRecorder来录像。仅仅是实现了简单的录像開始和停止功能。顶部能显示显示录像的时间,还有待完好。

代码例如以下:

在AndroidManifest.xml加入以下的权限:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 硬件支持 -->
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

activity_main.xml

<RelativeLayout 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" >

    <SurfaceView
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/timestamp_minute_prefix"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7F00FF"
            android:textSize="30sp"
            android:text="0"/>

        <TextView
            android:id="@+id/timestamp_minute_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7F00FF"
            android:textSize="30sp"
            android:text="0"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7F00FF"
            android:textSize="30sp"
            android:text=":"/>

        <TextView
            android:id="@+id/timestamp_second_prefix"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7F00FF"
            android:textSize="30sp"
            android:text="0"/>

        <TextView
            android:id="@+id/timestamp_second_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#7F00FF"
            android:textSize="30sp"
            android:text="0"/>
    </LinearLayout>

    <ImageButton
        android:id="@+id/record_shutter"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="15dp"
        android:background="@android:color/transparent"
        android:scaleType="centerCrop"
        android:src="@drawable/recording_shutter" />

</RelativeLayout>

MainActivity.java

package com.jackie.videorecorder;

import java.io.File;

import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.TextView;

import org.w3c.dom.Text;

public class MainActivity extends Activity implements OnClickListener {
    private SurfaceView mCameraPreview;
    private SurfaceHolder mSurfaceHolder;
    private ImageButton mShutter;
    private TextView mMinutePrefix;
    private TextView mMinuteText;
    private TextView mSecondPrefix;
    private TextView mSecondText;

    private Camera mCamera;
    private MediaRecorder mRecorder;

    private final static int CAMERA_ID = 0;

    private boolean mIsRecording = false;
    private boolean mIsSufaceCreated = false;

    private static final String TAG = "Jackie";

    private Handler mHandler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mCameraPreview = (SurfaceView) findViewById(R.id.camera_preview);
        mMinutePrefix = (TextView) findViewById(R.id.timestamp_minute_prefix);
        mMinuteText = (TextView) findViewById(R.id.timestamp_minute_text);
        mSecondPrefix = (TextView) findViewById(R.id.timestamp_second_prefix);
        mSecondText = (TextView) findViewById(R.id.timestamp_second_text);

        mSurfaceHolder = mCameraPreview.getHolder();
        mSurfaceHolder.addCallback(mSurfaceCallback);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        mShutter = (ImageButton) findViewById(R.id.record_shutter);
        mShutter.setOnClickListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mIsRecording) {
            stopRecording();
        }
        stopPreview();
    }

    private  SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() {

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mIsSufaceCreated = false;
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mIsSufaceCreated = true;
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            startPreview();
        }
    };

    //启动预览
    private void startPreview() {
        //保证仅仅有一个Camera对象
        if (mCamera != null || !mIsSufaceCreated) {
            Log.d(TAG, "startPreview will return");
            return;
        }

        mCamera = Camera.open(CAMERA_ID);

        Parameters parameters = mCamera.getParameters();
        Size size = getBestPreviewSize(CameraUtils.PREVIEW_WIDTH, CameraUtils.PREVIEW_HEIGHT, parameters);
        if (size != null) {
            parameters.setPreviewSize(size.width, size.height);
        }

        parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
        parameters.setPreviewFrameRate(20);

        //设置相机预览方向
        mCamera.setDisplayOrientation(90);

        mCamera.setParameters(parameters);

        try {
            mCamera.setPreviewDisplay(mSurfaceHolder);
//			mCamera.setPreviewCallback(mPreviewCallback);
        } catch (Exception e) {
            Log.d(TAG, e.getMessage());
        }

        mCamera.startPreview();
    }

    private void stopPreview() {
        //释放Camera对象
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(null);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }

            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
        Camera.Size result = null;

        for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
            if (size.width <= width && size.height <= height) {
                if (result == null) {
                    result = size;
                } else {
                    int resultArea = result.width * result.height;
                    int newArea = size.width * size.height;

                    if (newArea > resultArea) {
                        result = size;
                    }
                }
            }
        }

        return result;
    }

    @Override
    public void onClick(View v) {
        if (mIsRecording) {
            stopRecording();
        } else {
            initMediaRecorder();
            startRecording();

            //開始录像后,每隔1s去更新录像的时间戳
            mHandler.postDelayed(mTimestampRunnable, 1000);
        }
    }

    private void initMediaRecorder() {
        mRecorder = new MediaRecorder();//实例化
        mCamera.unlock();
        //给Recorder设置Camera对象,保证录像跟预览的方向保持一致
        mRecorder.setCamera(mCamera);
        mRecorder.setOrientationHint(90);  //改变保存后的视频文件播放时是否横屏(不加这句。视频文件播放的时候角度是反的)
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置从麦克风採集声音
        mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置从摄像头採集图像
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);  // 设置视频的输出格式 为MP4
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置音频的编码格式
        mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式
        mRecorder.setVideoSize(176, 144);  // 设置视频大小
        mRecorder.setVideoFrameRate(20); // 设置帧率
//        mRecorder.setMaxDuration(10000); //设置最大录像时间为10s
        mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        //设置视频存储路径
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder");
        if (!file.exists()) {
            //多级目录的创建
            file.mkdirs();
        }
        mRecorder.setOutputFile(file.getPath() + File.separator + "VID_" + System.currentTimeMillis() + ".mp4");
    }

    private void startRecording() {
        if (mRecorder != null) {
            try {
                mRecorder.prepare();
                mRecorder.start();
            } catch (Exception e) {
                mIsRecording = false;
                Log.e(TAG, e.getMessage());
            }
        }

        mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter_hl));
        mIsRecording = true;
    }

    private void stopRecording() {
        if (mCamera != null) {
            mCamera.lock();
        }

        if (mRecorder != null) {
            mRecorder.stop();
            mRecorder.release();
            mRecorder = null;
        }

        mShutter.setImageDrawable(getResources().getDrawable(R.drawable.recording_shutter));
        mIsRecording = false;

        mHandler.removeCallbacks(mTimestampRunnable);

        //将录像时间还原
        mMinutePrefix.setVisibility(View.VISIBLE);
        mMinuteText.setText("0");
        mSecondPrefix.setVisibility(View.VISIBLE);
        mSecondText.setText("0");

        //重新启动预览
        startPreview();
    }

    private Runnable mTimestampRunnable = new Runnable() {
        @Override
        public void run() {
            updateTimestamp();
            mHandler.postDelayed(this, 1000);
        }
    };

    private void updateTimestamp() {
        int second = Integer.parseInt(mSecondText.getText().toString());
        int minute = Integer.parseInt(mMinuteText.getText().toString());
        second++;
        Log.d(TAG, "second: " + second);

        if (second < 10) {
            mSecondText.setText(String.valueOf(second));
        } else if (second >= 10 && second < 60) {
            mSecondPrefix.setVisibility(View.GONE);
            mSecondText.setText(String.valueOf(second));
        } else if (second >= 60) {
            mSecondPrefix.setVisibility(View.VISIBLE);
            mSecondText.setText("0");

            minute++;
            mMinuteText.setText(String.valueOf(minute));
        } else if (minute >= 60) {
            mMinutePrefix.setVisibility(View.GONE);
        }
    }
}

效果例如以下:

时间: 2024-07-31 18:09:57

用MediaRecorder实现简单的录像功能的相关文章

ffmpeg学习4--ffmpeg类的简单封装,包含解码和定时录像功能

ffmpeg学习4--ffmpeg类的简单封装,包含解码和定时录像功能 参考网上的资料,简单封装了一下ffmpeg,这里记录一下,其它传感器编码及项目中用到的已经抽离,这里只包含解码和录像部分.这只是个玩具级别的测试.完整测试代码下载:代码下载 ffmpegDeCode.h #pragma once #include "stdafx.h" #include<iostream> using namespace std; extern char *VideoPath; exte

Android简单的利用MediaRecorder进行录音的实例代码

MainActivity.java package com.example.soundrecord_demo; import java.io.IOException; import android.media.MediaRecorder; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; import android.view.Vie

Android实现录屏直播(一)ScreenRecorder的简单分析

应项目需求瞄准了Bilibili的录屏直播功能,基本就仿着做一个吧.研究后发现Bilibili是使用的MediaProjection 与 VirtualDisplay结合实现的,需要 Android 5.0 Lollipop API 21以上的系统才能使用. 其实官方提供的android-ScreenCapture这个Sample中已经有了MediaRecorder的实现与使用方式,还有使用MediaRecorder实现的录制屏幕到本地文件的Demo,从中我们都能了解这些API的使用. 而如果需

Unity3D 实现简单的语音聊天 [Android版本]

上次简单说了iOS版本的聊天功能 Unity3D 实现简单的语音聊天 [iOS版本] 这次我们接着上篇来说下Android版本来实现简单的语音聊天,流程和iOS基一样的 @[email protected] 在这里我们可能会遇到一下问题: 1.U3D C# 与 Android Java之间是怎么通讯 2.Android怎么调用原生的录音功能和播放功能 好,我们逐一解决问题 1.U3D C# 与 Android Java之间是怎么通讯 相比iOS,Android这边会比较简单些 再C# 中这样调用

Android开发手记(31) 使用MediaRecorder录音

使用Android手机的时候,有时我们会用到录音功能,本文简单的介绍了如何使用MediaRecorder通过手机自带麦克风进行录音. 首先,既然是录音,我们需要录音和写外存的权限: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.RECORD_AUDIO&q

[Android]实现简单的相机程序

好久没写了,有些东西做过都快忘了,赶紧记一下. 现在来实现一个简单的相机程序. 原文地址http://www.cnblogs.com/rossoneri/p/4246134.html 当然需要的话可以直接调用系统的camera程序,但自己实现会使用更自由. 呐,既然要用实现相机,那就需要先了解一下调用camera的类android.hardware.camera android.hardware.Camera The Camera class is used to set image captu

Android项目开发五-《星星生活志》1.使用MediaRecorder录制音频

Android设备实现录制音频的简单demo 转载请注明; http://blog.csdn.net/u013670933/article/details/26089487 代码例如以下: public class MainActivity extends Activity { File soundFile;//输出文件 MediaRecorder mRecorder; @Override protected void onCreate(Bundle savedInstanceState) {

通过Android录音进行简单音频分析

Android录音有MediaRecorder和AudioRecord两种方式,前者使用方便,可以直接生成录音文件,但是录音格式为aac和amr等等,都经过压缩处理,不方便进行音频分析. 而用AudioRecord可以得到PCM编码的原音频数据,可以用FFT对数据进行处理,简单分析声音的频率. 1.AndroidRecord录音 private static final String FILE_NAME = "MainMicRecord"; private static final i

MediaRecorder实现微信、QQ、人人、易信等语音录制功能工具:MediaUtilAPI

本文介绍使用MediaRecorder进行录制音频.录制视频学习,熟悉MediaRecorder执行流程,通过简单的Demo结合解释运行效果,最后封装MediaRecorder的API工具,实现常见比如:微信.QQ.易信.人人.支付宝等录音功能模块开发,最后测试效果. 点击查看详情