Борьба с SurfaceView, камерой и OpenGL - PullRequest
11 голосов
/ 13 апреля 2011

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

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

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

Проблема:

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

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, так и информационное представление поверх них?

Ответы [ 4 ]

5 голосов
/ 30 ноября 2011

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

mLayout.addView(mRenderView);
mLayout.addView(mCustomSurfaceView);

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

это сработало для меня:)

3 голосов
/ 29 июля 2011

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

На моем Samsung Galaxy S2 порядок такой же, как вы описали (не знаю, как на других телефонах). Способ, которым я решил это, проверяет первое создание Activity in 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)

1 голос
/ 29 июля 2014

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

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

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

Если вы хотите узнать больше о том, почему SurfaceView ведет себя так, как он, см. Графика на уровне системы Android документ.

1 голос
/ 07 марта 2013

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

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

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

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

...