[android] Adapter un aperçu de la caméra à un SurfaceView plus grand que l'affichage


Answers

Question

J'ai une application Android qui doit afficher en plein écran un aperçu de la caméra, quelle que soit la taille de l'aperçu donnée par getSupportedPreviewSizes() sans distorsion. Je m'attends à ce que cela réduise l'aperçu d'une certaine quantité en hauteur ou en largeur, mais cela ne me concerne pas. La raison pour laquelle je cherche à le faire est que certaines caméras Android (par exemple, une caméra frontale Samsung Galaxy SII) ne renvoient aucun aperçu avec le même rapport d'aspect que l'affichage, et doivent donc être étirées et écrêtées.

Est-il possible d'élargir complètement l'aperçu de la caméra à une vue plus grande que la taille de l'écran? Il est possible d'agrandir SurfaceView par rapport aux dimensions de pixel d'aperçu renvoyées en définissant simplement les paramètres de disposition de la vue de surface sur match_parent, mais cela entraîne une distorsion dans certaines directions et n'est possible que lorsque l'aperçu remplit l'affichage. Cela semble indiquer que la prévisualisation en dehors de l'affichage est impossible et que le matériel (ou le système d'exploitation) limite ce comportement.

Il y a une autre question sur le sujet, mais cette question prétend qu'il n'est pas possible de créer un SurfaceView supérieur aux dimensions de l'écran, ce qui est faux, comme je l'ai constaté avec la journalisation. Cependant, ce qui semble être le cas, c'est que l'aperçu de la caméra ne peut cependant pas atteindre la taille d'une énorme SurfaceView.

Ma tentative:

J'ai une mise en page relative, à l'intérieur de celle-ci, un FrameLayout, et à l'intérieur de laquelle je crée un SurfaceView. La largeur de la disposition relative entière est définie ci-dessous à 635dp, ce qui représente ~ le double de la taille de l'écran du périphérique. Le FrameLayout correspond à ce dimensionnement, tout comme SurfaceView (ajouté par programmation ultérieurement)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/camera_activity_layout"
    android:layout_width="635dp"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

</RelativeLayout>

Voici le code qui obtient et définit la taille de l'aperçu. Ici, je souhaite que la prévisualisation de la caméra s’élargisse pour remplir la totalité de FrameLayout (double la largeur de l’écran). La vue apparaît et se détruit totalement normalement, donc je supprime le code non lié à cette question particulière car elle détourne l'attention de la question essentielle et ma tentative de faire facilement et simplement passer la vue à une taille supérieure à l'affichage.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    ...

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters parameters = mCamera.getParameters();
        final DisplayMetrics dm = this.getResources().getDisplayMetrics();
            //getBestPreviewSize returns the best preview size, don't worry
            //but some devices do not return one for all camera matching the aspect ratio
        cameraSize = getBestPreviewSize(parameters, dm.heightPixels, dm.widthPixels);

        if (cameraSize!=null) {
            parameters.setPreviewSize(cameraSize.width, cameraSize.height);
            mCamera.setParameters(parameters);
        }

        FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) this.getLayoutParams();

        frameParams.width = 800; //For argument's sake making this ~double the width of the display. Same result occurs if I use MATCH_PARENT
        frameParams.height = LayoutParams.MATCH_PARENT;
        this.setLayoutParams(frameParams);

        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

            Log.d("surfChange","W/H of CamPreview (child) is "+this.getWidth()+"/"+this.getHeight()+" while parent is ");
            Log.d("surfChange","W/H of holder (child) is "+mHolder.getSurfaceFrame().width()+"/"+mHolder.getSurfaceFrame().height()+" while parent is ");
        } catch (Exception e){
        }
    }
};

Je crains que la seule façon de réussir dans cette entreprise soit de rendre en quelque sorte une surface OpenGL, mais cela peut sembler trop lent en couleur. Il est également pénible que l’aperçu de la caméra puisse être simplement étiré et découpé.

Merci d'avance pour toute tentative de solution.




Links