如何在 Android 中捕获视频?

Posted

技术标签:

【中文标题】如何在 Android 中捕获视频?【英文标题】:How to capture video in Android? 【发布时间】:2010-11-05 04:44:19 【问题描述】:

我想创建一个录像机,目前还没有弄清楚如何设置参数才能成功通过MediaRecorder.prepare()方法。

执行下面的方法

public void start() throws IOException
    String state = android.os.Environment.getExternalStorageState();
    if(!state.equals(Environment.MEDIA_MOUNTED))
    
        throw new IOException("SD card is not mounted. It is " + state + ".");
    
    File directory = new File(path).getParentFile();
    if(!directory.exists() && !directory.mkdirs())
    
        throw new IOException("Path to file could not be created.");
    

    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
    recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
    recorder.setVideoFrameRate(15);
    recorder.setVideoSize(176, 144);
    recorder.setOutputFile(path);
    recorder.prepare();
    recorder.start();
    this.state = VideoRecorderState.STATE_RECORDING;

它在recorder.prepare(). 行抛出异常

如何设置参数以便能够捕获视频?

【问题讨论】:

不知道,但我很同情你。我刚从这方面的一些 J2ME 中毕业。至少可以说是喜怒无常! 【参考方案1】:

这是一个有效的 sn-p:

m_recorder = new MediaRecorder();
m_recorder.setPreviewDisplay(m_BeMeSurface);
m_recorder.setAudiosource(MediaRecorder.AudioSource.MIC);
m_recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
m_recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
m_recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
m_recorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
m_recorder.setMaxDuration((int) MAX_TIME); 
m_recorder.setOnInfoListener(m_BeMeSelf);
m_recorder.setVideoSize(320, 240); 
m_recorder.setVideoFrameRate(15); 
m_recorder.setOutputFile(m_path);

m_recorder.prepare();
m_recorder.start();

最重要的是表面。你没有它,所以没有它就会失败。

问候

BeMeCollective

【讨论】:

我问了一个关于 Surface 要求的问题。【参考方案2】:

我将在以下教程中准确回答这个问题: http://integratingstuff.wordpress.com/2010/10/18/writing-code-that-captures-videos-on-android/

您的代码在 prepare() 上失败的原因是您没有设置所有必要的属性。例如,您还需要设置 maxDuration。

【讨论】:

【参考方案3】:

我也有同样的问题。我是从后台录音服务出发的,希望创建一个后台视频录制服务。您无法真正录制背景视频,但可以在现有 UI 中使视频预览非常小。我按照教程:http://integratingstuff.wordpress.com/2010/10/18/writing-code-that-captures-videos-on-android/ 和示例相机预览演示。但最终http://www.apress.com/downloadable/download/sample/sample_id/39/ 中的示例代码足够简单,可以使用 tweek,但也足够完整,可以使用 setCamera。我将在此处发布我的解决方案,以节省其他人从玩具示例发展到具有高质量背景视频录制的复杂示例(如有必要使用前置摄像头)的时间。

这是带有“无”预览(预览是 1x1 像素,模拟不显眼的录制 LED)的 Android 视频录像机的来源,用于录制视频而不会分散用户的注意力。要使用您自己的 UI,只需将 video_recorder.xml 更改为您的布局(确保保留 VideoView)。它在 Android 2.2 和 3.0 设备上进行了测试。

合适的用例:

眼睛凝视跟踪库,让用户可以将眼睛用作鼠标来浏览网页 在实验室/诊所实验(心理语言学或言语病理学)中使用平板电脑摄像头代替摄像机

布局xml:

    <?xml version="1.0" encoding="utf-8"?>
<!-- This file is /res/layout/video_recorder.xml based on listing 9-6 in Pro Android 2 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_
        android:layout_>

    <RelativeLayout android:layout_
        android:layout_
        android:gravity="center">

            <VideoView android:id="@+id/videoView" android:layout_
                    android:layout_ />

    </RelativeLayout>
</LinearLayout>

Java 类:

import java.io.File;
import android.app.Activity;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.widget.Toast;
import android.widget.VideoView;
/**
 * Android video recorder with "no" preview (the preview is a 1x1 pixel which
 * simulates an unobtrusive recording led). Based on Pro Android 2 2010 (Hashimi
 * et al) source code in Listing 9-6. 
 * 
 * Also demonstrates how to use the front-facing and back-facing cameras. 
 * A calling Intent can pass an Extra to use the front facing camera if available.
 * 
 * Suitable use cases: 
 * A: eye gaze tracking library to let users use eyes as a mouse to navigate a web page 
 * B: use tablet camera(s) to replace video camera in lab experiments
 * (psycholingusitics or other experiments)
 * 
 * Video is recording is controlled in two ways: 
 * 1. Video starts and stops with the activity 
 * 2. Video starts and stops on any touch
 * 
 * To control recording in other ways see the try blocks of the onTouchEvent
 * 
 * To incorporate into project add these features and permissions to
 * manifest.xml:
 * 
 * <uses-feature android:name="android.hardware.camera"/> 
 * <uses-feature android:name="android.hardware.camera.autofocus"/>
 * 
 * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 * <uses-permission android:name="android.permission.CAMERA" /> 
 * <uses-permission android:name="android.permission.RECORD_AUDIO" />
 * 
 * Tested Date: October 2 2011 with manifest.xml 
 * <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="11"/>
 */
public class VideoRecorderSubExperiment extends Activity implements
        SurfaceHolder.Callback 
    public static final String EXTRA_USE_FRONT_FACING_CAMERA ="frontcamera";
    private static final String OUTPUT_FILE = "/sdcard/videooutput";
    private static final String TAG = "RecordVideo";
    private Boolean mRecording = false;
    private Boolean mUseFrontFacingCamera = false;
    private VideoView mVideoView = null;
    private MediaRecorder mVideoRecorder = null;
    private Camera mCamera;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.video_recorder);
        mVideoView = (VideoView) this.findViewById(R.id.videoView);

        //mUseFrontFacingCamera = getIntent().getExtras().getBoolean(
        //      EXTRA_USE_FRONT_FACING_CAMERA, true);
        if(mUseFrontFacingCamera)
            // If caller wants to use front facing camera, then make sure the device has one...
            // Hard coded to only open front facing camera on Xoom (model MZ604)
            // For more universal solution try: 
            // http://***.com/questions/2779002/how-to-open-front-camera-on-android-platform
            String deviceModel = android.os.Build.MODEL;
            if (deviceModel.contains("MZ604")) 
                mUseFrontFacingCamera = true;
             else 
                Toast.makeText(
                        getApplicationContext(),
                        "The App isn't designed to use this Android's front facing camera.\n " +
                        "The device model is : " + deviceModel, Toast.LENGTH_LONG).show();
                mUseFrontFacingCamera = false;
            
        

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

    public boolean onTouchEvent(MotionEvent event) 
        // can use the xy of the touch to start and stop recording
        float positionX = event.getX();
        float positionY = event.getY();

        switch (event.getAction()) 
        case MotionEvent.ACTION_DOWN:
            // Screen is pressed for the first time
            break;
        case MotionEvent.ACTION_MOVE:
            // Screen is still pressed, float have been updated
            break;
        case MotionEvent.ACTION_UP:
            // Screen is not touched anymore
            if (mRecording) 
                // To stop recording attach this try block to another event listener,
                // button etc
                try 
                    stopRecording();
                 catch (Exception e) 
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                
             else 
                // To begin recording attach this try block to another event listener,
                // button etc
                try 
                    beginRecording(mVideoView.getHolder());
                 catch (Exception e) 
                    Log.e(TAG, e.toString());
                    e.printStackTrace();
                
            
            break;
        
        return super.onTouchEvent(event);
    

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
        try 
            beginRecording(holder);
         catch (Exception e) 
            Log.e(TAG, e.toString());
            e.printStackTrace();
        
    

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) 
        Log.v(TAG, "Width x Height = " + width + "x" + height);
    

    private void stopRecording() throws Exception 
        mRecording = false;
        if (mVideoRecorder != null) 
            mVideoRecorder.stop();
            mVideoRecorder.release();
            mVideoRecorder = null;
        
        if (mCamera != null) 
            mCamera.reconnect();
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        
    

    @Override
    protected void onDestroy() 
        try 
            stopRecording();
         catch (Exception e) 
            Log.e(TAG, e.toString());
            e.printStackTrace();
        
        super.onDestroy();

    

    /**
     * Uses the surface defined in video_recorder.xml 
     * Tested using 
     * 2.2 (HTC Desire/Hero phone) -> Use all defaults works, records back facing camera with AMR_NB audio
     * 3.0 (Motorola Xoom tablet) -> Use all defaults doesn't work, works with these specs, might work with others
     * 
     * @param holder The surfaceholder from the videoview of the layout
     * @throws Exception
     */
    private void beginRecording(SurfaceHolder holder) throws Exception 
        if (mVideoRecorder != null) 
            mVideoRecorder.stop();
            mVideoRecorder.release();
            mVideoRecorder = null;
        
        if (mCamera != null) 
            mCamera.reconnect();
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        

        String uniqueOutFile = OUTPUT_FILE + System.currentTimeMillis() + ".3gp";
        File outFile = new File(uniqueOutFile);
        if (outFile.exists()) 
            outFile.delete();
        

        try 
            if (mUseFrontFacingCamera) 
                //hard coded assuming 1 is the front facing camera
                mCamera = Camera.open(1);
             else 
                mCamera = Camera.open();
            

            // Camera setup is based on the API Camera Preview demo
            mCamera.setPreviewDisplay(holder);
            Camera.Parameters parameters = mCamera.getParameters();
            parameters.setPreviewSize(640, 480);
            mCamera.setParameters(parameters);
            mCamera.startPreview();
            mCamera.unlock();

            mVideoRecorder = new MediaRecorder();
            mVideoRecorder.setCamera(mCamera);

            // Media recorder setup is based on Listing 9-6, Hashimi et all 2010
            // values based on best practices and good quality, 
            // tested via upload to YouTube and played in QuickTime on Mac Snow Leopard
            mVideoRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            mVideoRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mVideoRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);// THREE_GPP
                                                                                                                                            // is big-endian,
                                                                                                                                            // storing and
                                                                                                                                            // transferring
                                                                                                                                            // the most
                                                                                                                                            // significant
                                                                                                                                            // bytes first.
                                                                                                                                            // MPEG_4 as another option
            mVideoRecorder.setVideoSize(640, 480);// YouTube recommended size: 320x240,
                                                                            // OpenGazer eye tracker: 640x480
                                                                            // YouTube HD: 1280x720
            mVideoRecorder.setVideoFrameRate(20); //might be auto-determined due to lighting
            mVideoRecorder.setVideoEncodingBitRate(3000000);// 3 megapixel, or the max of
                                                                                                // the camera
            mVideoRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// MPEG_4_SP
                                                                                                                                // Simple Profile is
                                                                                                                                // for low bit
                                                                                                                                // rate and low
                                                                                                                                // resolution
                                                                                                                                // H264 is MPEG-4 Part 10 
                                                                                                                                //is commonly referred to
                                                                                                                                // as H.264 or AVC
            int sdk = android.os.Build.VERSION.SDK_INT;
            // Gingerbread and up can have wide band ie 16,000 hz recordings 
            // (Okay quality for human voice)
            if (sdk >= 10) 
                mVideoRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);
                mVideoRecorder.setAudioSamplingRate(16000);
             else 
                // Other devices only have narrow band, ie 8,000 hz 
                // (Same quality as a phone call, not really good quality for any purpose. 
                // For human voice 8,000 hz means /f/ and /th/ are indistinguishable)
                mVideoRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            
            mVideoRecorder.setMaxDuration(30000); // limit to 30 seconds
            mVideoRecorder.setPreviewDisplay(holder.getSurface());
            mVideoRecorder.setOutputFile(uniqueOutFile);
            mVideoRecorder.prepare();
            mVideoRecorder.start();
            mRecording = true;
         catch (Exception e) 
            Log.e(TAG, e.toString());
            e.printStackTrace();
        
    

【讨论】:

您发布的代码有效,我只想注释掉mUseFrontFacingCamera = getIntent().getExtras().getBoolean( EXTRA_USE_FRONT_FACING_CAMERA, true); 以使其正常工作。在 SGS2 ICS 4.0.3 和三星平板电脑 GTP1000 上测试 2.3.6。 Tks 分享,1up。 这是迄今为止我发现的最好的代码。除了一个问题。当我用硬编码的分辨率调用它时,它工作得很好。但是我必须将它称为一种方法,并且每次从用户那里获取不同的分辨率。当我用不同的分辨率调用它时,它给了我错误:start failed: -19 - 06-28 19:41:07.338: E/MediaRecorder(25092): try to delete broken file: /storage/sdcard0/Chimp_0160/recording.3gp【参考方案4】:

也许相机应用程序的source 可以帮助您调试它。

【讨论】:

【参考方案5】:

你检查过吗?

http://code.google.com/p/android/issues/detail?id=5050

这些家伙认为这是一个时间问题,并且 MediaRecorder 状态机可能需要在状态之间进行一些延迟(取决于硬件?)。

如果在每个状态完全实现时都有回调,那就太好了——然后我们就可以把准备放在里面了。

【讨论】:

【参考方案6】:

这可能是权限错误。您的 AndroidManifest 文件中是否设置了 android.permission.CAMERA 权限?

【讨论】:

【参考方案7】:

就我而言,复制和粘贴上面的示例不起作用。 然后,查看 MediaRecorder 中的方法,我找到了 setPreviewDisplay。 我通过 Camera.setPreviewDisplay 中使用的表面调用此方法,.prepare 中的 IOException 消失了,我能够录制视频。 尝试自己并发布结果。

【讨论】:

以上是关于如何在 Android 中捕获视频?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 android 的视频视图中显示的 ip 摄像头的流式视频中捕获图像

如何在我的 Android 应用中录制视频?

Android 如何将捕获的视频设置为 .mp4 而不是 .3gp

如何在 android 中播放来自 URL 的流媒体视频?

使用webrtc for android,如何在视频通话中保存图片?

Android Camera2 API:捕获视频而不预览