Nexus 10,前置摄像头预览为黑色(无预览)
Nexus 10, Front facing camera Preview is black (no preview)
所以我正在从事与相机相关的项目,我已经在许多设备上对其进行了测试,除 Nexus 10 外,所有设备都通过了测试。
真搞不懂是怎么回事,网上也没有人讨论这个问题
我能够在两个不同的 Nexus 10 (wifi) 设备上重现该问题。
这是我的 activity 的代码:
public class MainActivity extends Activity {
private static Camera mCamera;
private static boolean mCameraOpen;
private static ImageView mPreviewImageView;
private SurfaceView mPreviewSurfaceView;
private static boolean mPreviewRunning;
private static Handler mHandler;
private static int TESTS_COUNT = 0;
private Camera.Parameters mCameraParameters;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
mPreviewSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
mPreviewImageView = (ImageView) findViewById(R.id.imageview);
mPreviewSurfaceView.getHolder().addCallback(mCallback);
TextView view = (TextView) findViewById(R.id.textview);
view.setText("Format: " + String.valueOf(TESTS_COUNT));
}
@Override
public void onResume(){
super.onResume();
if (mCamera == null){
for (int i = 0; i < Camera.getNumberOfCameras(); i++){
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
mCamera = Camera.open(i);
Camera.Parameters params = mCamera.getParameters();
params.set("camera-id", 2);
List<Integer> formats = params.getSupportedPreviewFormats();
if (formats.size() > TESTS_COUNT) {
Log.e("Camera", "testing preview format at index: " + TESTS_COUNT);
params.setPreviewFormat(formats.get(TESTS_COUNT));
mCamera.setParameters(params);
mCameraOpen = true;
SurfaceHolder holder = mPreviewSurfaceView.getHolder();
if (holder != null && holder.getSurface() != null && holder.getSurface().isValid()) {
mCallback.surfaceCreated(holder);
}
mCameraParameters = params;
break;
} else {
finish();
}
}
}
}
}
@Override
public void onPause(){
super.onPause();
if (mPreviewRunning){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mPreviewRunning = false;
}
if (mCameraOpen){
mCamera.release();
mCamera = null;
mCameraOpen = false;
}
}
@Override
public void onDestroy(){
super.onDestroy();
}
private final SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (mCameraOpen && mCamera != null){
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
private int count;
private int total;
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
if (count == 15){
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
// pWidth and pHeight define the size of the preview Frame
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Alter the second parameter of this to the actual format you are receiving
YuvImage yuv = new YuvImage(bytes, ImageFormat.NV21, previewSize.width, previewSize.height, null);
// bWidth and bHeight define the size of the bitmap you wish the fill with the preview image
yuv.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 50, out);
byte[] bitmapBytes = out.toByteArray();
final Bitmap bitmap= BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
mHandler.post(new Runnable() {
@Override
public void run() {
mPreviewImageView.setImageBitmap(bitmap);
}
});
count = 0;
total++;
if (total > 5){
TESTS_COUNT++;
if (TESTS_COUNT == mCameraParameters.getSupportedPreviewSizes().size()) {
finish();
return;
}
Intent intent = new Intent( MainActivity.this, MainActivity.class);
startActivity(intent);
}
} else {
count++;
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()){
if (size.width == width && size.height == height){
if (mCameraOpen && mCamera != null && mPreviewRunning == false) {
mCameraParameters.setPreviewSize(width, height);
mCamera.setParameters(mCameraParameters);
mCamera.startPreview();
mPreviewRunning = true;
break;
}
}
}
if (mPreviewRunning == false){
Log.e("CameraPreview", "size not supported");
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
};
}
我的布局:
<LinearLayout 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" tools:context=".MainActivity"
android:orientation="vertical"
android:weightSum="2">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="2">
<SurfaceView
android:layout_width="640px"
android:layout_height="480px"
android:id="@+id/surfaceview"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/imageview"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textview"
android:textSize="40sp"/>
</LinearLayout>
</LinearLayout>
并显示:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
没有错误信息,只是黑屏
潜在的问题是,"How to debug this?" 答案一如既往,是想出尽可能多的假设来解释这些结果,然后检验这些假设.
这里有一些假设(想多了):
- 没有找到任何摄像头。
- 它没有找到任何前置摄像头。
- 它误解了相机参数。
- 设置
mCallback
太晚了,也就是需要之后
- 它没有找到有效的表面。
- 未成功注册相机帧。
- 它正在注册,但没有收到任何相机帧。
- 它正在接收相机帧但无法显示它们,例如图像不是预期的格式,或者
setImageBitmap(bitmap)
Runnable 不是 运行.
TESTS_COUNT
没有按照您的意愿去做。
您可以通过日志记录来检验假设,但对于大部分情况,在调试器中单步执行它并检查数据值(例如 params
.[=14=)会更快、提供更多信息]
如果您不熟悉调试器,现在是时候了!
我在装有 Lollipop 5.1 的 Nexus 10 上测试 activity。我有时会注意到,当我旋转屏幕时,应用程序会崩溃。我通过修改方法 surfaceChanged
的开头解决了这个问题:
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
{
if (mCameraParameters==null) return;
...
}
此外,如果你想研究一个在android上使用相机硬件的工作示例,你可以参考项目android_instacam及其源代码。
请使用名为 CtsVerifier 的应用验证您的设备,此应用包含在 Android 开源项目中,并且是 android 设备 (CTS) 兼容性测试套件的一部分。 CTS Verifier 有一系列检查相机的测试。check this link
如果前置摄像头在此应用程序中不起作用,您可以确定。那么您的设备可能已损坏,或者 hal 层发生了一些损坏。如果是这种情况,您可以尝试 downgrade/upgrade 您的 android os。如果不是,则可能是硬件损坏。
所以我正在从事与相机相关的项目,我已经在许多设备上对其进行了测试,除 Nexus 10 外,所有设备都通过了测试。
真搞不懂是怎么回事,网上也没有人讨论这个问题
我能够在两个不同的 Nexus 10 (wifi) 设备上重现该问题。
这是我的 activity 的代码:
public class MainActivity extends Activity {
private static Camera mCamera;
private static boolean mCameraOpen;
private static ImageView mPreviewImageView;
private SurfaceView mPreviewSurfaceView;
private static boolean mPreviewRunning;
private static Handler mHandler;
private static int TESTS_COUNT = 0;
private Camera.Parameters mCameraParameters;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
mPreviewSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
mPreviewImageView = (ImageView) findViewById(R.id.imageview);
mPreviewSurfaceView.getHolder().addCallback(mCallback);
TextView view = (TextView) findViewById(R.id.textview);
view.setText("Format: " + String.valueOf(TESTS_COUNT));
}
@Override
public void onResume(){
super.onResume();
if (mCamera == null){
for (int i = 0; i < Camera.getNumberOfCameras(); i++){
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
mCamera = Camera.open(i);
Camera.Parameters params = mCamera.getParameters();
params.set("camera-id", 2);
List<Integer> formats = params.getSupportedPreviewFormats();
if (formats.size() > TESTS_COUNT) {
Log.e("Camera", "testing preview format at index: " + TESTS_COUNT);
params.setPreviewFormat(formats.get(TESTS_COUNT));
mCamera.setParameters(params);
mCameraOpen = true;
SurfaceHolder holder = mPreviewSurfaceView.getHolder();
if (holder != null && holder.getSurface() != null && holder.getSurface().isValid()) {
mCallback.surfaceCreated(holder);
}
mCameraParameters = params;
break;
} else {
finish();
}
}
}
}
}
@Override
public void onPause(){
super.onPause();
if (mPreviewRunning){
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mPreviewRunning = false;
}
if (mCameraOpen){
mCamera.release();
mCamera = null;
mCameraOpen = false;
}
}
@Override
public void onDestroy(){
super.onDestroy();
}
private final SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (mCameraOpen && mCamera != null){
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
private int count;
private int total;
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
if (count == 15){
Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
// pWidth and pHeight define the size of the preview Frame
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Alter the second parameter of this to the actual format you are receiving
YuvImage yuv = new YuvImage(bytes, ImageFormat.NV21, previewSize.width, previewSize.height, null);
// bWidth and bHeight define the size of the bitmap you wish the fill with the preview image
yuv.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 50, out);
byte[] bitmapBytes = out.toByteArray();
final Bitmap bitmap= BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
mHandler.post(new Runnable() {
@Override
public void run() {
mPreviewImageView.setImageBitmap(bitmap);
}
});
count = 0;
total++;
if (total > 5){
TESTS_COUNT++;
if (TESTS_COUNT == mCameraParameters.getSupportedPreviewSizes().size()) {
finish();
return;
}
Intent intent = new Intent( MainActivity.this, MainActivity.class);
startActivity(intent);
}
} else {
count++;
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
for (Camera.Size size : mCameraParameters.getSupportedPreviewSizes()){
if (size.width == width && size.height == height){
if (mCameraOpen && mCamera != null && mPreviewRunning == false) {
mCameraParameters.setPreviewSize(width, height);
mCamera.setParameters(mCameraParameters);
mCamera.startPreview();
mPreviewRunning = true;
break;
}
}
}
if (mPreviewRunning == false){
Log.e("CameraPreview", "size not supported");
}
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
};
}
我的布局:
<LinearLayout 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" tools:context=".MainActivity"
android:orientation="vertical"
android:weightSum="2">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity"
android:orientation="horizontal"
android:layout_weight="1"
android:weightSum="2">
<SurfaceView
android:layout_width="640px"
android:layout_height="480px"
android:id="@+id/surfaceview"/>
<ImageView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/imageview"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textview"
android:textSize="40sp"/>
</LinearLayout>
</LinearLayout>
并显示:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
没有错误信息,只是黑屏
潜在的问题是,"How to debug this?" 答案一如既往,是想出尽可能多的假设来解释这些结果,然后检验这些假设.
这里有一些假设(想多了):
- 没有找到任何摄像头。
- 它没有找到任何前置摄像头。
- 它误解了相机参数。
- 设置
mCallback
太晚了,也就是需要之后 - 它没有找到有效的表面。
- 未成功注册相机帧。
- 它正在注册,但没有收到任何相机帧。
- 它正在接收相机帧但无法显示它们,例如图像不是预期的格式,或者
setImageBitmap(bitmap)
Runnable 不是 运行. TESTS_COUNT
没有按照您的意愿去做。
您可以通过日志记录来检验假设,但对于大部分情况,在调试器中单步执行它并检查数据值(例如 params
.[=14=)会更快、提供更多信息]
如果您不熟悉调试器,现在是时候了!
我在装有 Lollipop 5.1 的 Nexus 10 上测试 activity。我有时会注意到,当我旋转屏幕时,应用程序会崩溃。我通过修改方法 surfaceChanged
的开头解决了这个问题:
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
{
if (mCameraParameters==null) return;
...
}
此外,如果你想研究一个在android上使用相机硬件的工作示例,你可以参考项目android_instacam及其源代码。
请使用名为 CtsVerifier 的应用验证您的设备,此应用包含在 Android 开源项目中,并且是 android 设备 (CTS) 兼容性测试套件的一部分。 CTS Verifier 有一系列检查相机的测试。check this link
如果前置摄像头在此应用程序中不起作用,您可以确定。那么您的设备可能已损坏,或者 hal 层发生了一些损坏。如果是这种情况,您可以尝试 downgrade/upgrade 您的 android os。如果不是,则可能是硬件损坏。