好吧,我正在尝试开发一款采用前置摄像头拍摄的应用。 我有一个奇怪的错误。预览看起来很好,但输出视频出现了低分辨率的绿线和高分辨率的绿线
这是代码:
package feipeng.yacamcorder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.VideoEncoder;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;
/***
* TODO: 1. sound on/off 2. resolution change
*
* @author roman10
*
*/
public class Main extends Activity implements SurfaceHolder.Callback {
private SurfaceView prSurfaceView;
private Button prStartBtn;
private Button prSettingsBtn;
private boolean prRecordInProcess;
private SurfaceHolder prSurfaceHolder;
private Camera prCamera;
private final String cVideoFilePath = "/sdcard/r10videocam/";
private Context prContext;
private MediaRecorder prMediaRecorder;
private CamcorderProfile mProfile;
private final int cMaxRecordDurationInMs = 30000;
private final long cMaxFileSizeInBytes = 5000000;
private final int cFrameRate = 20;
private File prRecordedFile;
private static final int REQUEST_DECODING_OPTIONS = 0;
private static final String TAG = "aaa";
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
switch (requestCode) {
case REQUEST_DECODING_OPTIONS:
if (resultCode == RESULT_OK) {
updateEncodingOptions();
}
break;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
prContext = this.getApplicationContext();
setContentView(R.layout.main);
Utils.createDirIfNotExist(cVideoFilePath);
prSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
prStartBtn = (Button) findViewById(R.id.main_btn1);
prSettingsBtn = (Button) findViewById(R.id.main_btn2);
prRecordInProcess = false;
prStartBtn.setOnClickListener(new View.OnClickListener() {
// @Override
@Override
public void onClick(View v) {
if (prRecordInProcess == false) {
startRecording();
} else {
stopRecording();
}
}
});
prSettingsBtn.setOnClickListener(new View.OnClickListener() {
// @Override
@Override
public void onClick(View v) {
Intent lIntent = new Intent();
lIntent.setClass(prContext,
feipeng.yacamcorder.SettingsDialog.class);
startActivityForResult(lIntent, REQUEST_DECODING_OPTIONS);
}
});
prSurfaceHolder = prSurfaceView.getHolder();
prSurfaceHolder.addCallback(this);
prSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
prMediaRecorder = new MediaRecorder();
}
private Camera openFrontFacingCamera() {
Camera camera = null;
// Look for front-facing camera, using the Gingerbread API.
// Java reflection is used for backwards compatibility with
// pre-Gingerbread APIs.
try {
Class<?> cameraClass = Class.forName("android.hardware.Camera");
Object cameraInfo = null;
Field field = null;
int cameraCount = 0;
Method getNumberOfCamerasMethod = cameraClass
.getMethod("getNumberOfCameras");
if (getNumberOfCamerasMethod != null) {
cameraCount = (Integer) getNumberOfCamerasMethod.invoke(null,
(Object[]) null);
}
Class<?> cameraInfoClass = Class
.forName("android.hardware.Camera$CameraInfo");
if (cameraInfoClass != null) {
cameraInfo = cameraInfoClass.newInstance();
}
if (cameraInfo != null) {
field = cameraInfo.getClass().getField("facing");
}
Method getCameraInfoMethod = cameraClass.getMethod("getCameraInfo",
Integer.TYPE, cameraInfoClass);
if (getCameraInfoMethod != null && cameraInfoClass != null
&& field != null) {
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
getCameraInfoMethod.invoke(null, camIdx, cameraInfo);
int facing = field.getInt(cameraInfo);
if (facing == 1) { // Camera.CameraInfo.CAMERA_FACING_FRONT
try {
Method cameraOpenMethod = cameraClass.getMethod(
"open", Integer.TYPE);
if (cameraOpenMethod != null) {
camera = (Camera) cameraOpenMethod.invoke(null,
camIdx);
mProfile = CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW);
}
} catch (RuntimeException e) {
Log.e(TAG,
"Camera failed to open: "
+ e.getLocalizedMessage());
}
}
}
}
}
// Ignore the bevy of checked exceptions the Java Reflection API throws
// - if it fails, who cares.
catch (ClassNotFoundException e) {
Log.e(TAG, "ClassNotFoundException" + e.getLocalizedMessage());
} catch (NoSuchMethodException e) {
Log.e(TAG, "NoSuchMethodException" + e.getLocalizedMessage());
} catch (NoSuchFieldException e) {
Log.e(TAG, "NoSuchFieldException" + e.getLocalizedMessage());
} catch (IllegalAccessException e) {
Log.e(TAG, "IllegalAccessException" + e.getLocalizedMessage());
} catch (InvocationTargetException e) {
Log.e(TAG, "InvocationTargetException" + e.getLocalizedMessage());
} catch (InstantiationException e) {
Log.e(TAG, "InstantiationException" + e.getLocalizedMessage());
} catch (SecurityException e) {
Log.e(TAG, "SecurityException" + e.getLocalizedMessage());
}
if (camera == null) {
// Try using the pre-Gingerbread APIs to open the camera.
try {
camera = Camera.open();
} catch (RuntimeException e) {
Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
}
}
return camera;
}
private boolean startRecording() {
prCamera.stopPreview();
try {
prCamera.unlock();
prMediaRecorder.setCamera(prCamera);
// set audio source as Microphone, video source as camera
// state: Initial=>Initialized
prMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
prMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// set the file output format: 3gp or mp4
// state: Initialized=>DataSourceConfigured
String lVideoFileFullPath;
String lDisplayMsg = "Current container format: ";
if (Utils.puContainerFormat == SettingsDialog.cpu3GP) {
lDisplayMsg += "3GP\n";
lVideoFileFullPath = ".3gp";
prMediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
} else if (Utils.puContainerFormat == SettingsDialog.cpuMP4) {
lDisplayMsg += "MP4\n";
lVideoFileFullPath = ".mp4";
prMediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
} else {
lDisplayMsg += "3GP\n";
lVideoFileFullPath = ".3gp";
prMediaRecorder
.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
}
// the encoders:
// audio: AMR-NB
prMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);
// video: H.263, MP4-SP, or H.264
// prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
// prMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
lDisplayMsg += "Current encoding format: ";
if (Utils.puEncodingFormat == SettingsDialog.cpuH263) {
lDisplayMsg += "H263\n";
prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
} else if (Utils.puEncodingFormat == SettingsDialog.cpuMP4_SP) {
lDisplayMsg += "MPEG4-SP\n";
prMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
} else if (Utils.puEncodingFormat == SettingsDialog.cpuH264) {
lDisplayMsg += "H264\n";
prMediaRecorder.setVideoEncoder(VideoEncoder.H264);
} else {
lDisplayMsg += "H263\n";
prMediaRecorder.setVideoEncoder(VideoEncoder.H263);
}
lVideoFileFullPath = cVideoFilePath
+ String.valueOf(System.currentTimeMillis())
+ lVideoFileFullPath;
prRecordedFile = new File(lVideoFileFullPath);
prMediaRecorder.setOutputFile(prRecordedFile.getPath());
if (Utils.puResolutionChoice == SettingsDialog.cpuRes176) {
prMediaRecorder.setVideoSize(176, 144);
} else if (Utils.puResolutionChoice == SettingsDialog.cpuRes320) {
prMediaRecorder.setVideoSize(320, 240);
} else if (Utils.puResolutionChoice == SettingsDialog.cpuRes720) {
prMediaRecorder.setVideoSize(720, 480);
}
Toast.makeText(prContext, lDisplayMsg, Toast.LENGTH_LONG).show();
prMediaRecorder.setVideoFrameRate(cFrameRate);
prMediaRecorder.setPreviewDisplay(prSurfaceHolder.getSurface());
prMediaRecorder.setMaxDuration(cMaxRecordDurationInMs);
prMediaRecorder.setMaxFileSize(cMaxFileSizeInBytes);
// prepare for capturing
// state: DataSourceConfigured => prepared
prMediaRecorder.prepare();
// start recording
// state: prepared => recording
prMediaRecorder.start();
prStartBtn.setText("Stop");
prRecordInProcess = true;
return true;
} catch (IOException _le) {
_le.printStackTrace();
return false;
}
}
private void stopRecording() {
prMediaRecorder.stop();
prMediaRecorder.reset();
try {
prCamera.reconnect();
} catch (IOException e) {
e.printStackTrace();
}
prStartBtn.setText("Start");
prRecordInProcess = false;
prCamera.startPreview();
}
// @Override
@Override
public void surfaceChanged(SurfaceHolder _holder, int _format, int _width,
int _height) {
Camera.Parameters lParam = prCamera.getParameters();
// //lParam.setPreviewSize(_width, _height);
// //lParam.setPreviewSize(320, 240);
// lParam.setPreviewFormat(PixelFormat.JPEG);
prCamera.setParameters(lParam);
try {
prCamera.setPreviewDisplay(_holder);
prCamera.startPreview();
// prPreviewRunning = true;
} catch (IOException _le) {
_le.printStackTrace();
}
}
// @Override
@Override
public void surfaceCreated(SurfaceHolder arg0) {
prCamera = openFrontFacingCamera();
if (prCamera == null) {
Toast.makeText(this.getApplicationContext(),
"Camera is not available!", Toast.LENGTH_SHORT).show();
finish();
}
}
// @Override
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
if (prRecordInProcess) {
stopRecording();
} else {
prCamera.stopPreview();
}
prMediaRecorder.release();
prMediaRecorder = null;
prCamera.release();
prCamera = null;
}
private void updateEncodingOptions() {
if (prRecordInProcess) {
stopRecording();
startRecording();
Toast.makeText(prContext, "Recording restarted with new options!",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(prContext, "Recording options updated!",
Toast.LENGTH_SHORT).show();
}
}
}
P.S。 使用galaxy s1。
任何想法?
答案 0 :(得分:0)
我在4.0.4上运行的三星Nexus S上尝试了你的代码,效果很好。 MediaRecorder的设置如下:
private boolean startRecording() {
...
prMediaRecorder.setCamera(prCamera);
prMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
prMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
prMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
prMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
prMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
prMediaRecorder.setOutputFile("/sdcard/video.mp4");
prMediaRecorder.setVideoSize(320, 240);//If higher produces error -19
prMediaRecorder.setVideoFrameRate(15);//If higher produces error -19
prMediaRecorder.setPreviewDisplay(prSurfaceHolder.getSurface());
prMediaRecorder.setMaxDuration(cMaxRecordDurationInMs);
prMediaRecorder.setMaxFileSize(cMaxFileSizeInBytes);
prMediaRecorder.prepare();
prMediaRecorder.start();
...
}//endOfStartRecording()
对于10秒的记录,它会产生大小约为300 KB的.mp4文件。质量不是很好,但它是我能得到的最高品质。请记住,前置摄像头不如后置摄像头那么强大。