[Android] Ajuster un aperçu de 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 caméra indépendamment de la taille d'aperçu donnée par getSupportedPreviewSizes() sans distorsion. Je m'attends à ce que cela recadre l'aperçu d'une certaine quantité dans la hauteur ou la largeur, mais cela ne me concerne pas. La raison pour laquelle je cherche à faire cela est parce que certaines caméras Android (par exemple Samsung Galaxy SII face à la caméra) ne renvoient pas de prévisualisation avec le même rapport d'aspect que l'affichage, et doivent donc être étirés et coupés.

Est-il possible d'agrandir complètement l'aperçu de la caméra pour obtenir une vue plus grande que la taille de l'affichage? Il est possible de faire grossir le SurfaceView plus grand que les dimensions de pixel de prévisualisation renvoyées en réglant simplement les params de disposition de la vue de surface sur match_parent, mais cela entraîne une distorsion dans certains sens et n'est possible que jusqu'à ce que l'aperçu remplisse 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 un tel 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 pas atteindre la taille d'un énorme SurfaceView.

Ma tentative:

J'ai une disposition relative, à l'intérieur d'un FrameLayout, et à l'intérieur je crée un SurfaceView. La largeur de l'ensemble de la disposition relative est définie ci-dessous à 635dp, soit environ le double de la taille de l'écran de l'appareil. Le FrameLayout correspond à ce dimensionnement, tout comme le SurfaceView (ajouté par programmation plus tard)

<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>

Ce qui suit est le code qui obtient et définit la taille de l'aperçu. Ici, je veux agrandir l'aperçu de la caméra pour remplir tout le FrameLayout (doubler la largeur de l'écran). La vue apparaît et détruit tout à fait normalement donc je supprime le code non lié à cette question particulière parce qu'il détourne de la question essentielle, et ma tentative de facilement et simplement augmenter la vue à une taille plus grande que 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 est de rendre en quelque sorte à une surface openGL, mais cela pourrait être trop lent en couleur. Il est également pénible si l'aperçu de la caméra peut simplement être étiré et coupé.

Merci d'avance pour toute tentative de solution.