Изображение камеры Android искажено - SurfaceHolder -
У меня странная проблема с камерой-SurfaceHolder.
Я хочу показать изображение камеры в моей деятельности. На моем GalaxyS1 все работает очень хорошо (CyanogenMod - Android 4.4) На моем S3 (также CyanogenMod - Android 4.4), с другой стороны, это выглядит странно.
Пейзажное изображение без строки заголовка хорошо, но когда я показываю строку заголовка или превращаю ее в портретный режим, оно выглядит искаженным:
--- РЕДАКТИРОВАТЬ ---
Спасибо Алекс Кон за вашу помощь. Похоже, ты прав. Предварительный просмотр для режима portraid теперь работает хорошо. Но все же это выглядит искаженным на пейзажном виде. Я проверил масштаб предварительного просмотра, и он выглядит хорошо. Насколько я вижу, я также правильно установил размер предварительного просмотра. Так что с ним не так?
Вот текущий код:
private static final String TAG = CameraView.class.getSimpleName();
private SurfaceHolder surfaceHolder;
private Camera camera;
private List<Size> mSupportedPreviewSizes;
private Size mPreviewSize;
public CameraView(Activity activity) {
super(activity);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
camera = Camera.open();
mSupportedPreviewSizes = camera.getParameters()
.getSupportedPreviewSizes();
setCameraDisplayOrientation(activity, 0, camera);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
camera.setParameters(parameters);
camera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
} catch (IOException exception) {
camera.release();
camera = null;
}
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
camera.stopPreview();
camera.release();
camera = null;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w,
int h) {...}
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, Camera camera) {...}
--- РЕДАКТИРОВАТЬ ---
Я зарегистрировал значения для onMeasure и Измененная поверхность. Кажется, они в порядке:
Портрет:
ПОВЕРХНОСТЬ ИЗМЕНЕНА: Witdh:720 Высота:1134
Измерение: ширина: 720 высота:1134
Пейзаж:
ПОВЕРХНОСТЬ ИЗМЕНЕНА: Witdh:1280 Высота:590
Измерение: ширина: 1280 высота:590
Предпросмотр Размер: Ширина: 704 Высота:576
Я получаю следующие возможные размеры предварительного просмотра.
В массиве 8 элементов:
960 х 720, 1280 х 720, 1184 х 666, 960 х 640,704 х 576, 640 х 480, 352 х 288, 320 х 240
Надеюсь, кто-нибудь может помочь!
Спасибо, Тобиас
1 ответ
Источником вашей проблемы является следующая строка:
parameters.setPreviewSize(w, h);
в surfaceChanged()
метод. Вы не можете установить размер предварительного просмотра на произвольные значения в Android. Вы должны использовать только пары (w, h), возвращаемые Parameters.getSupportedPreviewSizes (). В противном случае вы нажмете, что кажется успешным, это допустимая форма неопределенной ситуации поведения. На самом деле, многие устройства просто вызывают RuntimeException на camera.setParameters(parameters)
, но ваши платформы разработки решили вести себя по-другому.
Не требуется, чтобы размер предварительного просмотра был таким же, как у поверхности, используемой для его отображения, например, можно использовать предварительный просмотр 320x240 на поверхности 640x480. Но если ваш предварительный просмотр и поверхность имеют разные пропорции, изображение будет выглядеть растянутым (см. ). Небольшие искажения могут быть допустимыми, например, при использовании предварительного просмотра 1280x720 при 800x400 пикселей, но при превышении определенного порога у вас нет другого выбора, кроме как использовать только часть экрана, оставляя поля выше и ниже предварительного просмотра.
Вы можете найти то, что придумало сообщество разработчиков: использовать getOptimalPreviewSize()
для заданной ширины высота (это только один пример).