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
Android 摄像头预览 ---- SurfaceView 和 Camera