2016-04-13 18 views
12

Sto cercando aiuto per un problema con il codice Grafika's CameraCaptureActivity. Voglio creare un'app in grado di registrare la fotocamera e visualizzare un'anteprima, quindi questo esempio e questo codice sembravano esattamente ciò che volevo e fino ad ora è stato fantastico, questo numero appart.Anteprima fotocamera Android allungata utilizzando il codice CameraCapture Grafika

Il problema è che quando la dimensione dell'anteprima della fotocamera non corrisponde alle dimensioni esatte dello GLSurfaceView che uso per visualizzare l'anteprima mostra un'anteprima allungata.

Ecco come appare:

Preview stretched

Come si può vedere che è allungata orizzontalmente dal momento che il foglio di nota è un quadrato perfetto.

Per questo preciso Esempio su un Samsung Galaxy S4, le dimensioni della fotocamera anteprima è 1280x720 (estratto da dimensioni di anteprima disponibili utilizzando Camera2 API), e il GLSurfaceView è 1920x1080 a coprire l'intero schermo.

Quando appare?

Il problema appare quando il SurfaceView è upscaled rispetto alla uscita della telecamera, anche se ho sempre assicurarsi il rapporto resti corretta (1920x1080 = 1,5 * 1280x720).

Che codice stai usando?

io uso il codice di Grafika, tra cui:

Un registro?

Ecco cosa SurfaceFlinger discarica appare come:

Hardware Composer state (version 01030000): 
    mDebugForceFakeVSync=0 
    Display[0] configurations (* current): 
    * 0: 1080x1920, xdpi=442.450989, ydpi=439.351013, secure=1 refresh=16666667 
    numHwLayers=3, flags=00000000 
    type | handle | hint | flag | tr | blnd | format  |  source crop(l,t,r,b)  |   frame  |  dirtyRect   | name 
------------+----------+----------+----------+----+-------+----------+-----------------------------------+---------------------------+------------------- 
     HWC | b3b12ba0 | 0002 | 0000 | 00 | 0100 | RGB_888  | 0.0, 0.0, 1080.0, 1920.0 | 0, 0, 1080, 1920 | [ 0, 0, 1080, 1920] | SurfaceView 
     HWC | b3d12740 | 0002 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 1065.0, 1905.0 | 0, 0, 1065, 1905 | [ 0, 0, 1065, 1905] | com.mybundle.myapp/com.mybundle.myapp.activity.MyActivity 
FB TARGET | b6a55c40 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 1080.0, 1920.0 | 0, 0, 1080, 1920 | [ 0, 0, 0, 0] | HWC_FRAMEBUFFER_TARGET 

Layer 0xb4094000 (SurfaceView) 
    Region transparentRegion (this=0xb4094160, count=1) 
    [ 0, 0, 0, 0] 
    Region visibleRegion (this=0xb4094008, count=1) 
    [ 0, 0, 1920, 1080] 
     layerStack= 0, z= 21015, pos=(0,0), size=(1920,1080), crop=( 0, 0,1920,1080), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000002, tr=[1.00, 0.00][0.00, 1.00] 
     client=0xb66190c0 
     format= 4, activeBuffer=[1080x1920:1536, 3], queued-frames=0, mRefreshPending=0 
      mTexName=116 mCurrentTexture=0 
      mCurrentCrop=[0,0,0,0] mCurrentTransform=0x7 
      mAbandoned=0 
      -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=4, transform-hint=04, FIFO(0)={} 
      >[00:0xb1c18500] state=ACQUIRED, 0xb3b12ba0 [1080x1920:1536, 3] 

Camera codice anteprima dimensioni?

StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 

// Retrieve display size 
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 
Display display = wm.getDefaultDisplay(); 
Point displaySize = new Point(); 
display.getSize(displaySize); 

// Choose the sizes for camera preview 
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), 
        displaySize.x, displaySize.y, captureWidth, captureHeight); 

private static Size chooseOptimalSize(Size[] choices, int screenWidth, int screenHeight, int captureWidth, int captureHeight) 
    { 
     // Collect the supported resolutions that are at least as big as the screen && wanted capture size 
     List<Size> bigEnough = new ArrayList<>(); 
     // Collect the supported resolutions that are at least as big as the wanted capture size but < to screensize 
     List<Size> smallerButEnough = new ArrayList<>(); 

     for (Size option : choices) { 
      if (option.getHeight() == option.getWidth() * captureHeight/captureWidth) { 
       if(option.getWidth() >= screenWidth && option.getHeight() >= screenHeight) 
       { 
        bigEnough.add(option); 
       } 
       else 
       { 
        smallerButEnough.add(option); 
       } 
      } 
     } 

     // Pick the smallest of those, assuming we found any 
     if (bigEnough.size() > 0) 
     { 
      return Collections.min(bigEnough, new CompareSizesByArea()); 
     } 
     // Pick the biggest of those, assuming we found any 
     else if(smallerButEnough.size() > 0) 
     { 
      return Collections.max(smallerButEnough, new CompareSizesByArea()); 
     } 
     else 
     { 
      Log.e(TAG, "Couldn't find any suitable preview size"); 
      return choices[0]; 
     } 
    } 

Che cosa hai provato?

Inizialmente ho pensato che fosse un problema Camera2, quindi ho provato a utilizzare solo la vecchia API della fotocamera, ma il risultato è lo stesso.

Poi ho pensato che fosse un problema di rapporto, ma come potete vedere il rapporto qui è ok orizzontalmente e verticalmente.

La mia scommessa è che c'è una trasformazione OpenGL da applicare quando Surface viene ridimensionato, ma io sono un puro noob in OpenGL quindi non sono stato in grado di trovare nulla che funzioni. Provo aggiunto queste righe, ma non aiuta:

@Override 
public void onSurfaceChanged(GL10 gl, int width, int height) { 
    Log.d(TAG, "onSurfaceChanged " + width + "x" + height); 

    gl.glViewport(0, 0, width, height); 
    gl.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT); 
} 

Un altro esempio, fin dal Grafika:

Ecco un altro esempio del problema, direttamente dall'app Grafika.

Telefono: Galaxy S3 Neo (GT-I9301L) - Android 4.4.2

Il telefono ha uno schermo 1280x720, la macchina fotografica si è aperta con la risoluzione 640x480, visualizzato in un 573x430. Ecco come appare:

Stretching on GS3 Neo

tronchi SurfaceFlinger:

Hardware Composer state (version 1030000): 
    mDebugForceFakeVSync=0 
    Display[0] : 720x1280, xdpi=304.799011, ydpi=306.716003, refresh=16666667 
    numHwLayers=4, flags=00000000 
    type | handle | hints | flags | tr | blend | format |   source crop   |   frame   name 
------------+----------+----------+----------+----+-------+----------+---------------------------------+-------------------------------- 
     HWC | b84a3d18 | 00000002 | 00000000 | 00 | 00100 | 00000002 | [ 0.0, 0.0, 430.0, 573.0] | [ 32, 353, 462, 926] SurfaceView 
     HWC | b841b080 | 00000002 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 670.0, 1280.0] | [ 0, 0, 670, 1280] com.android.grafika/com.android.grafika.CameraCaptureActivity 
     HWC | b8423250 | 00000002 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 50.0, 1280.0] | [ 670, 0, 720, 1280] StatusBar 
    FB TARGET | b8412d50 | 00000000 | 00000000 | 00 | 00105 | 00000001 | [ 0.0, 0.0, 720.0, 1280.0] | [ 0, 0, 720, 1280] HWC_FRAMEBUFFER_TARGET 


+ Layer 0xb8416080 (SurfaceView) id=112 
    Region transparentRegion (this=0xb84169d0, count=1) 
    [ 0, 0, 0, 0] 
    Region visibleRegion (this=0xb8416088, count=1) 
    [353, 258, 926, 688] 
     layerStack= 0, z= 21015, pos=(353,258), size=(573, 430), crop=( 0, 0, 573, 430), isOpaque=1, invalidate=0, alpha=0xff, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00] 
     client=0xb841d7c8 
     format= 4, activeBuffer=[ 430x 573: 448, 2], queued-frames=0, mRefreshPending=0 
      mTexName=95 mCurrentTexture=1 
      mCurrentCrop=[0,0,0,0] mCurrentTransform=0x7 
      mAbandoned=0 
      -BufferQueue mMaxAcquiredBufferCount=1, mDequeueBufferCannotBlock=0, default-size=[573x430], default-format=4, transform-hint=04, FIFO(0)={} 
      [00:0xb84439a8] state=FREE , 0xb849a528 [ 430x 573: 448, 2] 
      >[01:0xb8421128] state=ACQUIRED, 0xb84a3d18 [ 430x 573: 448, 2] 
      [02:0xb84238e8] state=FREE , 0xb84432f8 [ 430x 573: 448, 2] 

registro app Grafika:

04-18 18:06:49.954 14383-14383/com.android.grafika D/Grafika: onCreate complete: [email protected] 
04-18 18:06:49.954 14383-14383/com.android.grafika D/Grafika: onResume -- acquiring camera 
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika: Camera preferred preview size for video is 1920x1080 
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika-AFL: Setting aspect ratio to 1.3333333333333333 (was -1.0) 
04-18 18:06:50.064 14383-14383/com.android.grafika D/Grafika: onResume complete: [email protected] 
04-18 18:06:50.064 14383-32312/com.android.grafika D/Grafika: setCameraPreviewSize 
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 526] 
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: new size=701x526 + padding 0x0 
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 430] 
04-18 18:06:50.094 14383-14383/com.android.grafika D/Grafika-AFL: new size=573x430 + padding 0x0 
04-18 18:06:50.124 14383-32312/com.android.grafika D/Grafika: onSurfaceCreated 
04-18 18:06:50.134 14383-32312/com.android.grafika D/Grafika: Created program 3 (TEXTURE_EXT) 
04-18 18:06:50.144 14383-32312/com.android.grafika D/Grafika: onSurfaceChanged 573x430 
04-18 18:06:50.144 14383-32312/com.android.grafika D/Grafika: Updating filter to 0 
04-18 18:06:50.154 14383-14383/com.android.grafika D/Grafika: onItemSelected: 0 
04-18 18:06:50.154 14383-14383/com.android.grafika D/Grafika: CameraHandler [Handler (com.android.grafika.CameraCaptureActivity$CameraHandler) {42aeec70}]: what=0 
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 526] 
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: new size=701x526 + padding 0x0 
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: onMeasure target=1.3333333333333333 width=[MeasureSpec: EXACTLY 1216] height=[MeasureSpec: EXACTLY 430] 
04-18 18:06:50.514 14383-14383/com.android.grafika D/Grafika-AFL: new size=573x430 + padding 0x0 
04-18 18:06:50.544 14383-14383/com.android.grafika D/AbsListView: onVisibilityChanged() is called, visibility : 4 
04-18 18:06:50.544 14383-14383/com.android.grafika D/AbsListView: unregisterIRListener() is called 

Quindi ...

Se uno di voi ragazzi avere un'idea di come farlo funzionare, Mi piacerebbe sentirlo da lui.

Grazie!

+0

Sto immaginando che qualcosa non stia usando la risoluzione che pensi che stia usando. Un approccio per capire questo è usare 'adb shell dumpys SurfaceFlinger' per scaricare i layer di HardwareComposer; questo mostrerà la trasformazione che viene applicata a SurfaceView Surface. https://source.android.com/devices/graphics/architecture.html#composition ha un esempio (utilizzando un lettore video di Grafika) della sezione che dovresti esaminare. Le trasformazioni GLES non dovrebbero essere rilevanti dal momento che stai disegnando l'intero fotogramma con un rect di dimensioni viewport. Vedi qualche distorsione in Grafika stessa? – fadden

+0

@fadden Ho aggiunto il registro di 'adb shell dumpsys SurfaceFlinger' sulla mia risposta: [# 36617782] (http://stackoverflow.com/a/36617782/2508174). Vedi qualcosa di strano? – Benoit

+0

L'output HWC mostra tutto a 1080x1920, quindi non c'è niente di sbagliato nella configurazione di SurfaceView. Questo lascia la configurazione della fotocamera. Puoi mostrare il codice che stai utilizzando per configurare le dimensioni dell'anteprima? – fadden

risposta

0

mi dispiace per la mia ultima risposta, è stato stupido e non ha risolto il problema. Ma ho fondato un'altra soluzione e l'ho testata su 5 dispositivi utilizzando diverse proporzioni della fotocamera. Come ho capito, stai usando il codice Grafika. Prova a rimuovere parms.setRecordingHint(true); Quindi ora sto usando solo param.setPictureSize() param.setPreviewSize() con lo stesso rapporto di aspetto nei parametri della fotocamera. Anche io ho impostato la dimensione della vista con quell'aspetto, l'ho fatto da solo. In grafika usava dimensioni fisse, afaik. Spero che ti possa aiutare.

+0

Hey Roman, grazie per la risposta. Il fatto è che la rimozione di 'setRecordingHint' può portare un sacco di lag e framerate drop per i video poiché la fotocamera sarà in modalità foto, quindi è probabilmente una cattiva idea farlo, non credi? – Benoit

+0

Sì, ho un frame inferiore ma ha risolto il problema con la risoluzione. Inoltre puoi usare una risoluzione di anteprima più bassa, non ho notato nessun cambiamento di framerate se uso 320x240 per previewSize wo flag su galaxy s3. Inoltre, prima di fondare questo, ho usato solo le stesse proporzioni per l'anteprima e la dimensione dell'immagine, come tasso predefinito, che ho ottenuto da getPreferredPreviewSizeForVideo(). –

+0

Ok, buono a sapersi, grazie. Il fatto è che ho bisogno di almeno 720p, quindi non posso disabilitare "setRecordingHint", ma è bene sapere come fallback di ultima istanza. Grazie ancora. – Benoit

Problemi correlati