Surface 视图显示黑屏以进行视频预览

Posted

技术标签:

【中文标题】Surface 视图显示黑屏以进行视频预览【英文标题】:Surface view displays black screen for video preview 【发布时间】:2013-12-09 17:08:33 【问题描述】:

您好,我正在开发一个类似于此链接的 android 视频应用 http://android-er.blogspot.in/2011/10/video-capture-using-mediarecorder-with.html 视频应用在哪里以框架布局显示。

我正在表面视图上尝试上面的那个,我的 xml 如下所示。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:textSize="20sp" >

<SurfaceView
    android:id="@+id/CameraView"
    android:layout_
    android:layout_
    android:focusable="true" />

<ImageView
    android:id="@+id/mybutton"
    android:layout_
    android:layout_
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:paddingLeft="2dp"
    android:paddingRight="2dp"
    android:src="@drawable/record_video" />

</RelativeLayout>

我不确定为什么它显示黑屏而不是相机视图。我的 ViewActivity.java 如下。

public class ViewActivity extends Activity implements OnClickListener, SurfaceHolder.Callback

MediaRecorder recorder;
SurfaceHolder holder;
boolean recording=false;
private MediaRecorder mediaRecorder;
private File file;
private ImageView recVideo;
private SurfaceView cameraView;
private Camera camera;

@Override
public void onCreate(Bundle savedInstanceState)

    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE); 

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    recorder = new MediaRecorder();
    initRecorder();

    setContentView(R.layout.view);

    recVideo = (ImageView)findViewById(R.id.mybutton);
    cameraView = (SurfaceView) findViewById(R.id.CameraView);

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

    recVideo.setClickable(true);
    recVideo.setOnClickListener(this);


private void initRecorder() 

    recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
    recorder.setAudiosource(MediaRecorder.AudioSource.DEFAULT);
    recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
    recorder.setOutputFile(this.initFile().getAbsolutePath());
    recorder.setMaxDuration(60000); // Set max duration 60 sec.
    recorder.setMaxFileSize(5000000); // Set max file size 5M



private void prepareRecorder()

    recorder.setPreviewDisplay(holder.getSurface());

    try 
    
        recorder.prepare();
     catch (IllegalStateException e) 
    
        e.printStackTrace();
        finish();
     
    catch (IOException e) 
    
        e.printStackTrace();
        finish();
    


public void onClick(View v)

    if (recording)
    
        recorder.stop();
        recording = false;

        initRecorder();
        prepareRecorder();
        Toast.makeText(ViewActivity.this,"Video Saved!",Toast.LENGTH_SHORT).show();
        startActivity(new Intent(ViewActivity.this,ViewActivity.class));
        finish();

    
    else 
    
        recorder.start();
        recording = true;
        recVideo.setImageDrawable(getResources().getDrawable(R.drawable.stop_recording));
    


public void surfaceCreated(SurfaceHolder holder) 

    prepareRecorder();



public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) 



public void surfaceDestroyed(SurfaceHolder holder) 

    if (recording) 
        recorder.stop();
        recording = false;
    
    recorder.release();
    finish();

我不确定我哪里出错了。如何使表面视图显示相机视图而不是黑屏。

请帮忙。

谢谢!

【问题讨论】:

我不太清楚,但你可以试试 recorder.setPreviewDisplay(holder.getSurface());在此 recorder.prepare(); 之后 试过了!没有变化。仍然显示黑屏 【参考方案1】:

这样做:

public class AndroidVideoCapture extends Activity 

    private Camera myCamera;
    private MyCameraSurfaceView myCameraSurfaceView;
    private MediaRecorder mediaRecorder;

    Button myButton;
    RadioButton flashOff, flashTorch;
    SurfaceHolder surfaceHolder;
    boolean recording;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        recording = false;

        setContentView(R.layout.main);

        // Get Camera for preview
        myCamera = getCameraInstance();
        if (myCamera == null) 
            Toast.makeText(AndroidVideoCapture.this, "Fail to get Camera",Toast.LENGTH_LONG).show();
        

        myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
        FrameLayout myCameraPreview = (FrameLayout) findViewById(R.id.videoview);
        myCameraPreview.addView(myCameraSurfaceView);

        myButton = (Button) findViewById(R.id.mybutton);
        myButton.setOnClickListener(myButtonOnClickListener);

        flashOff = (RadioButton) findViewById(R.id.flashoff);
        flashTorch = (RadioButton) findViewById(R.id.flashtorch);
    

    Button.OnTouchListener flashButtonOnTouchListener = new Button.OnTouchListener() 

        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) 
            // TODO Auto-generated method stub

            if (myCamera != null) 
                Parameters parameters = myCamera.getParameters();

                switch (arg1.getAction()) 
                case MotionEvent.ACTION_DOWN:
                    parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
                    myCamera.setParameters(parameters);
                    break;
                case MotionEvent.ACTION_UP:
                    parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
                    myCamera.setParameters(parameters);
                    break;
                
                ;
            

            return true;
        
    ;

    Button.OnClickListener flashModeButtonOnClickListener = new Button.OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub

        
    ;

    Button.OnClickListener myButtonOnClickListener = new Button.OnClickListener() 

        @Override
        public void onClick(View v) 
            // TODO Auto-generated method stub
            if (recording) 
                // stop recording and release camera
                mediaRecorder.stop(); // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object

                myCamera.lock(); 
                // take camera access back from
                recording = false;
                // MediaRecorder
                // inform the user that recording has stopped
                // Exit after saved
                //finish();
             else 

                // Release Camera before MediaRecorder start
                releaseCamera();

                if (!prepareMediaRecorder()) 
                    Toast.makeText(AndroidVideoCapture.this,
                            "Fail in prepareMediaRecorder()!\n - Ended -",
                            Toast.LENGTH_LONG).show();
                    finish();
                

                mediaRecorder.start();
                recording = true;
                myButton.setText("STOP");
            
        
    ;

    private Camera getCameraInstance() 
        // TODO Auto-generated method stub
        Camera c = null;
        try 
            c = Camera.open(); // attempt to get a Camera instance
            c.setDisplayOrientation(90);
         catch (Exception e) 
            // Camera is not available (in use or does not exist)
        
        return c; // returns null if camera is unavailable
    

    private String getFlashModeSetting() 
        if (flashTorch.isChecked()) 
            return Parameters.FLASH_MODE_TORCH;
         else 
            return Parameters.FLASH_MODE_OFF;
        
    

    private boolean prepareMediaRecorder() 
        myCamera = getCameraInstance();

        Parameters parameters = myCamera.getParameters();
        parameters.setFlashMode(getFlashModeSetting());
        myCamera.setParameters(parameters);

        mediaRecorder = new MediaRecorder();

        myCamera.unlock();
        mediaRecorder.setCamera(myCamera);

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

        mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

        mediaRecorder.setOutputFile(getOutputMediaFile("movie"));
        mediaRecorder.setMaxDuration(6000000); // Set max duration 60 sec.
        mediaRecorder.setMaxFileSize(50000000); // Set max file size 5M

        mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());

        mediaRecorder.setOrientationHint(90);

        try 
            mediaRecorder.prepare();
         catch (IllegalStateException e) 
            releaseMediaRecorder();
            return false;
         catch (IOException e) 
            releaseMediaRecorder();
            return false;
        
        return true;

    

    @Override
    protected void onPause() 
        super.onPause();
        releaseMediaRecorder(); // if you are using MediaRecorder, release it
                                // first
        releaseCamera(); // release the camera immediately on pause event
    

    private void releaseMediaRecorder() 
        if (mediaRecorder != null) 
            mediaRecorder.reset(); // clear recorder configuration
            mediaRecorder.release(); // release the recorder object
            mediaRecorder = null;
            myCamera.lock(); // lock camera for later use
        
    

    private void releaseCamera() 
        if (myCamera != null) 
            myCamera.release();
            // release the camera for other applications
            myCamera = null;
        
    

    public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback 

        private SurfaceHolder mHolder;
        private Camera mCamera;

        public MyCameraSurfaceView(Context context, Camera camera) 
            super(context);
            mCamera = camera;

            // Install a SurfaceHolder.Callback so we get notified when the
            // underlying surface is created and destroyed.
            mHolder = getHolder();
            mHolder.addCallback(this);
            // deprecated setting, but required on Android versions prior to 3.0
            mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format,int weight, int height) 
            // If your preview can change or rotate, take care of those events
            // here.
            // Make sure to stop the preview before resizing or reformatting it.

            if (mHolder.getSurface() == null) 
                // preview surface does not exist
                return;
            

            // stop preview before making changes
            try 
                mCamera.stopPreview();
             catch (Exception e) 
                // ignore: tried to stop a non-existent preview
            

            // make any resize, rotate or reformatting changes here

            // start preview with new settings
            try 
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();

             catch (Exception e) 
            
        

        @Override
        public void surfaceCreated(SurfaceHolder holder) 
            // TODO Auto-generated method stub
            // The Surface has been created, now tell the camera where to draw
            // the preview.
            try 
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
             catch (IOException e) 
            
        

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) 
            // TODO Auto-generated method stub

        
    

    private static String getOutputMediaFile(String sufix) 

        String mediaFile;
        File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "/YappBack");
        if (!mediaStorageDir.exists()) 
            if (!mediaStorageDir.mkdirs()) 
                Log.d("VideoLogger", "failed to create directory");
                return null;
            
        
        String timeStamp = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
        if (!sufix.equals("movie")) 
            mediaFile = mediaStorageDir.getPath() + File.separator + "output_"+ timeStamp + "_" + sufix + ".txt";
         else 
            mediaFile = mediaStorageDir.getPath() + File.separator + "output_"+ timeStamp + ".mp4";

        
        //mediaFile = Environment.getExternalStorageDirectory().getPath()+ "/default.mp4";
        return mediaFile;
    

XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical" >

    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical" >

        <FrameLayout
            android:id="@+id/videoview"
            android:layout_
            android:layout_ />

        <LinearLayout
            android:layout_
            android:layout_
            android:orientation="vertical" >

            <Button
                android:id="@+id/mybutton"
                android:layout_
                android:layout_
                android:text="REC"
                android:textSize="12dp" />

            <RadioGroup
                android:layout_
                android:layout_
                android:orientation="vertical" >

                <RadioButton
                    android:id="@+id/flashoff"
                    android:layout_
                    android:layout_
                    android:checked="true"
                    android:text="OFF"
                    android:textSize="8dp" />

                <RadioButton
                    android:id="@+id/flashtorch"
                    android:layout_
                    android:layout_
                    android:text="Torch"
                    android:textSize="8dp" />
            </RadioGroup>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

【讨论】:

请解释一下?【参考方案2】:

确保您已在清单文件中声明 CAMERA 权限。

还要检查您是否已从设置中授予相机权限。

【讨论】:

这不提供问题的答案,应该是评论。请参阅When should I comment?。一旦你有足够的reputation,你就可以在任何帖子上comment;相反,provide answers that don't require clarification from the asker.【参考方案3】:

确保您在camera.setPreviewTexture(surfaceTexture); 之后调用mediaRecorder.setPreviewDisplay(new Surface(surfaceTexture));,然后诀窍是在mediaRecorder.start(); 之前调用camera.stopPreview()

【讨论】:

以上是关于Surface 视图显示黑屏以进行视频预览的主要内容,如果未能解决你的问题,请参考以下文章

Camera2:从已创建的 CameraCaptureSession 中删除 Surface

ffmpeg解码后的视频帧怎样显示出来

Android 摄像头预览 ---- SurfaceView 和 Camera

Android 使用CameraX实现预览/拍照/录制视频/图片分析/对焦/缩放/切换摄像头等操作

重用滤镜导致GPUImage黑屏

surfacego3接上键盘子菜单闪退