Борьба с SurfaceView, камерой и OpenGL

Мы боремся с некоторыми проблемами, связанными с SurfaceViews, более недели, и не находим подходящего решения для них. Мы читаем другие вопросы на форуме относительно похожих проблем (и даже исходного кода Mixare), но не можем найти ответ, поэтому мы надеемся, что вы каким-то образом поможете нам.

Сценарий: у нас есть

  • A SurfaceView для камеры
  • SurfaceView для слоя OpenGL, который находится поверх камеры.
  • Другой вид, который показывает некоторую информацию о том, что мы видим на экране. Этот идет поверх обоих SurfaceViews.

Проблема:

Как бы мы ни старались, оба SurfaceViews, похоже, не ладят друг с другом. Если мы попытаемся:

setContentView(mCameraPreview); addContentView(mGLSurfaceView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); addContentView(mInfoView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 

(Что кажется логичным), все идет так, как ожидалось, до тех пор, пока мы не заблокируем / не разблокируем телефон. После этого GLSurfaceView просто исчезает (а не InfoView, который все еще отображается).

Если вместо этого мы попытаемся:

 setContentView(mGLSurfaceView); addContentView(mCameraPreview, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); addContentView(mInfoView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); 

Тогда проблема в том, что GLSurfaceView появляется только после блокировки / разблокировки, а перед этим на экране отображается камера и InfoView.

Мы обнаружили, что если мы спам основной поток за 4,6 секунды (или больше) после выполнения onStart () в активности, которая показывает представления, поведение будет таким же, как и ожидалось (отображаются как изображения камеры, glsurface, так и информация, даже после блокировки / разблокировки ).

Дело в том, что мы ищем более … элегантное решение.

Нам кажется, что проблема заключается в том, что камера занимает больше времени, чем ожидалось в Camera.open() , и поэтому добавляется представление камеры, добавляется GLSurfaceView, и когда камера фактически открывается, она открывается поверх GLSurfaceView. Что касается этого, мы использовали bringToFront() в GLSurfaceView и получили его поверх информационного представления, но после блокировки / разблокировки камера все еще открылась поверх него, оставив нам экран с предварительным просмотром камеры.

Есть идеи? Как мы можем показать как SurfaceViews, так и представление информации сверху?

попробуй это:

 mLayout.addView(mRenderView); mLayout.addView(mCustomSurfaceView); // without this line, the camera preview cannot be displayed // when running activity at first time. mCustomSurfaceView.setZOrderMediaOverlay(true); 

Это сработало для меня 🙂

У меня такая же проблема. Когда вы намекаете на себя: несколько SurfaceView s не ладят друг с другом тем, что их Z-порядок не определен.

На моем Samsung Galaxy S2 заказ такой же, как вы описываете (не знаете, как это делается на других телефонах). Как я решил это, проверяется на первый раз создание Activity в onCreate() :

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... if ( savedInstanceState == null ) { initCamView(); initOpenGL(); } else { initOpenGL(); initCamView(); } //... } 

с:

 private void initOpenGL() { mGLSurfaceView = new GLSurfaceView(this); mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); mOGLRenderer = new OGLRenderer(this); mGLSurfaceView.setRenderer(mOGLRenderer); mRL.addView(mGLSurfaceView); // mRL is the Relative Layout } 

а также:

 private void initCamView() { mCamView = new CustomCameraView( this.getApplicationContext(), this.getWindowManager() ); mRL.addView(mCamView); // mRL is the Relative Layout } 

Не самое изящное решение, но лучше, чем позволить нить спать на 4,6 секунды.

Также можно было бы просто заблокировать экран в одной ориентации, но тогда вам нужно сделать много уродливого взлома, чтобы накладывать правильные повороты.

Или, если вы ориентируетесь только на Android 3.0 или выше (уровень API 8), вы можете просто показать камеру в OpenGL SurfaceTexture. http://developer.android.com/reference/android/hardware/Camera.html#setPreviewTexture(android.graphics.SurfaceTexture )

У меня была та же проблема: мне нужен SurfaceView под GLSurfaceView, первый для воспроизведения видео, а второй для запуска игры.

Независимо от того, что я сделал, порядок z между этими двумя поверхностными видами кажется случайным.

Но я нашел решение, благодаря этому сообщению: https://stackoverflow.com/a/6028907/1557915

Хитрость заключается в том, чтобы удалить использование макета, но вместо этого использовать setContentView / addContentView.

Каждая поверхность SurfaceView имеет Z-глубину. Существуют три возможные глубины: по умолчанию (внизу), «наложение медиа» (над ним) и «верх» (что выше всего, включая пользовательский интерфейс на основе представления). Если у вас есть две перекрывающиеся поверхности на одной и той же глубине, одна победит, но вы не можете надежно определить, какой из них. Вы можете добиться последовательного поведения на одном устройстве, только чтобы найти, что он работает другим способом на другом устройстве.

Композиция выполняется с помощью аппаратных накладок, когда это возможно. Многие популярные в настоящее время устройства имеют 4 плоскости наложения. Как только вы превысите это, композиция будет выполнена с использованием графического процессора, который будет дороже. Если у вас есть строка состояния, панель навигации и View UI, это три, поэтому вы получаете только один SurfaceView для дешевых.

Для примера в вопросе было бы лучше объединить как можно больше вещей на поверхность, которая будет визуализироваться с помощью GLES. Это может включать выход камеры на API 11+. См. Пример «Текстура из камеры» в Grafika . (У Grafika также есть демонстрационное приложение с тремя перекрывающимися SurfaceViews, см. «Активность с несколькими поверхностями»).

Если вы хотите узнать больше о том, почему SurfaceView ведет себя так, как это делается, см. Документ « Системный уровень Android» .