2011-04-13 14 views
11

Hemos estado luchando con algunos problemas relacionados con SurfaceViews durante más de una semana, y no encontramos una solución adecuada para ellos. Leemos las otras preguntas en el foro con respecto a problemas similares (e incluso el código fuente de Mixare) pero no pudimos encontrar una respuesta, por lo que esperamos que nos ayudes de alguna manera.Luchando con SurfaceView, la cámara y OpenGL

Escenario: , Tenemos que

  • un SurfaceView de la cámara
  • un SurfaceView para una capa de OpenGL, lo que va en la parte superior de la cámara.
  • otra Vista, que muestra información sobre lo que podemos ver en la pantalla. Este se encuentra en la parte superior de ambos SurfaceViews.

Problema:

No importa cuánto nos esforcemos, ambos SurfaceViews aparentemente no se llevan bien entre sí. Si tratamos de:

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

(lo cual parece lógico), todo sale como se espera hasta que bloquear/desbloquear el teléfono. Después de eso, el GLSurfaceView simplemente desaparece (no el InfoView, ese aún se muestra).

Si, en cambio, tratamos de:

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

Entonces, el problema es que el GLSurfaceView sólo aparece después de bloqueo/desbloqueo, y antes de que la pantalla está mostrando la cámara y el InfoView.

Descubrimos que si dormimos el hilo principal durante 4.6 segundos (o más) después de ejecutar onStart() en la actividad que muestra las vistas, el comportamiento es el esperado (se muestran las vistas de cámara, superficie e información, incluso después de bloquear/desbloquear).

Lo que pasa es que estamos buscando una solución más ... elegante.

Nos parece que el problema es que la cámara tarda más de lo esperado en Camera.open(), por lo que se agrega la Vista de cámara, se agrega GLSurfaceView y cuando la cámara se abre, se abre en la parte superior de GLSurfaceView. Con respecto a esto, usamos bringToFront() en GLSurfaceView, y lo obtuvimos en la vista de información, pero después de bloquear/desbloquear la cámara aún se abrió sobre ella, dejándonos con una pantalla con la vista previa de la cámara solamente.

¿Alguna idea? ¿Cómo podemos mostrar SurfaceViews y la vista de información sobre ellos?

+0

Su pregunta va más allá de mi conocimiento, pero asegúrese de hacer llamadas a GLSurfaceView.onPause() y GLSurfaceView.onResume() como se supone que debe hacerlo desde su contenedor Activity. Eso es todo lo que puedo pensar sobre este tema. – harism

+0

Parece que estamos tratando de abordar el mismo problema. No vi su pregunta cuando me envió [mi] (http://stackoverflow.com/questions/5778647/how-to-properly-use-setzordermediaoverlay-on-android). ¿Intentó 'setZOrderMediaOverlay()'?Lo intenté pero no pude hacer funcionar este escenario. Quizás puedas descubrir cómo usarlo y solucionar este problema. – alokoko

Respuesta

2

Tuve el mismo problema. Como se da a entender a sí mismo: múltiples SurfaceView s no se llevan bien entre sí porque su orden Z no está definida.

En mi Samsung Galaxy S2 el orden es el mismo que usted describe (no sé cómo es en otros teléfonos). La forma en que lo resolvió, es la comprobación de primera hora de creación de la Activity en onCreate():

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 

    //... 

    if (savedInstanceState == null) 
    { 
     initCamView(); 
     initOpenGL(); 
    } 
    else 
    { 
     initOpenGL(); 
     initCamView(); 
    } 

    //... 
} 

con:

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 
} 

y:

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

No es la solución más elegante, pero es mejor que dejar que el hilo duerma durante 4.6 segundos.

También podría ser posible bloquear la pantalla en una sola orientación, pero luego debe hacer una gran cantidad de piratería para que las superposiciones giren de la manera correcta.

O, si sólo está apuntando Android 3.0 o superior (nivel de la API 8), sólo puede mostrar la cámara en un OpenGL SurfaceTexture. http://developer.android.com/reference/android/hardware/Camera.html#setPreviewTexture(android.graphics.SurfaceTexture)

4

intente esto:

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

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

esto funcionó para mí :)

+0

Perfecto, esto me llevó a setZOrderOnTop (onTop) que era exactamente lo que estaba buscando –

1

que tenía el mismo problema: quería un SurfaceView bajo un GLSurfaceView, la primera para reproducir vídeo y el segundo para correr un juego.

lo que hiciera, el orden z entre estos 2 puntos de vista de la superficie parece ser al azar.

Pero he encontrado la solución, gracias a este post: https://stackoverflow.com/a/6028907/1557915

El truco es eliminar el uso de diseño, pero en lugar de utilizar setContentView/addContentView.

1

superficie de cada SurfaceView tiene una Z-profundidad. Hay tres profundidades posibles: el valor por defecto (parte inferior), "superposición de los medios de comunicación" (por encima de ella), y "superior" (que está por encima de todo, incluyendo la interfaz de usuario basada en Vista). Si tiene dos superficies superpuestas a la misma profundidad, una ganará, pero no puede definir con seguridad cuál. Puede obtener un comportamiento consistente en un dispositivo solo para descubrir que funciona de otra manera en un dispositivo diferente.

La composición se realiza con superposiciones de hardware, cuando sea posible. Muchos dispositivos actualmente populares tienen 4 planos superpuestos. Una vez que lo supere, la composición se realizará con la GPU, que será más costosa. Si tiene una barra de estado, una barra de navegación y una IU de visualización, son tres, por lo que solo obtendrá un SurfaceView por poco dinero.

Para el ejemplo de la pregunta, lo mejor sería combinar tantas cosas como sea posible sobre la superficie que se queden con GLES. Esto puede incluir la salida de la cámara en la API 11+. Consulte la actividad "Textura de la cámara" en Grafika para ver un ejemplo. (Grafika también tiene una aplicación de demostración con tres SurfaceViews superpuestos, consulte la actividad "prueba de varias superficies")

Si desea obtener más información acerca de por qué SurfaceView se comporta de la manera que lo hace, consulte el documento Android System-Level Graphics.

Cuestiones relacionadas