4 votes

L'écran clignote et se redimensionne lors du démarrage de l'enregistrement vidéo.

Je suis en train d'intégrer la capture photo/vidéo dans mon application et j'ai un problème avec la capture vidéo. Chaque fois que l'enregistrement vidéo démarre, l'écran clignote, j'ai une courte pause, puis la capture vidéo commence. Cependant, en utilisant l'application caméra du téléphone, il n'y a aucun clignotement/pause du tout.

Aussi, l'affichage de l'aperçu de ma caméra est redimensionné dès que recorder.start() est appelé. Je ne vois pas pourquoi. Cela rend l'aperçu déformé (tout semble écrasé et plus large).

Mes questions : Comment empêcher le clignotement/pause lors du démarrage de l'enregistrement vidéo ? Comment empêcher recorder.start() de redimensionner mon affichage d'aperçu ?

Chaque fois que le "mode vidéo" est activé, initRecording() est immédiatement appelé. Une fois que l'utilisateur appuie sur un bouton, startRecording() est appelé. Enfin, lorsque le bouton est à nouveau pressé, stopRecording() est appelé. Moins important, lors du retour au "mode image", destroyRecorder() est appelé.

@Override
public void onResume() {

    super.onResume();

    Camera camera = null;
    try {
        camera = Camera.open();
    }
    catch (Exception e) {
        // La caméra n'est pas disponible
        Toast.makeText( getActivity(), "La caméra n'est pas disponible pour le moment.", Toast.LENGTH_SHORT ).show();
        getActivity().finish();
        return;
    }

    if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD ) {
        setCameraDisplayOrientation( camera );
    }
    else {
        camera.setDisplayOrientation( 90 );
    }

    setCamera( camera );
    setCameraZoomDisplay( camera );

    if ( getSurfaceHolder() != null ) {
        startPreview();

        if ( getMode() == MODE_VIDEO ) {
            initRecording();
        }
    }
}

private void setCameraDisplayOrientation( Camera camera ) {

    CameraInfo info = new CameraInfo();
    Camera.getCameraInfo( 0, info );

    int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
    }

    int result = ( info.orientation - degrees + 360 ) % 360;
    camera.setDisplayOrientation( result );
}

private void initRecording() {

    MediaRecorder recorder = new MediaRecorder();
    setRecorder( recorder );

    Camera camera = getCamera();
    camera.unlock();
    recorder.setCamera( camera );

    recorder.setAudioSource( MediaRecorder.AudioSource.MIC );
    recorder.setVideoSource( MediaRecorder.VideoSource.CAMERA );

    CamcorderProfile cp = CamcorderProfile.get( CamcorderProfile.QUALITY_HIGH );
    recorder.setProfile( cp );

    String extension;
    switch (cp.fileFormat) {
        case MediaRecorder.OutputFormat.MPEG_4:
            extension = "mp4";
            break;
        case MediaRecorder.OutputFormat.THREE_GPP:
            extension = "3gp";
            break;
        default:
            extension = "tmp";
    }

    setVideoMimeType( MimeTypeMap.getSingleton().getMimeTypeFromExtension( extension ) );

    File toFile = new File( getActivity().getCacheDir(), "tempvideo.tmp" );
    if ( toFile.exists() ) {
        toFile.delete();
    }
    setTempFile( toFile );

    recorder.setOutputFile( toFile.getPath() );
    recorder.setPreviewDisplay( getSurfaceHolder().getSurface() );

    try {
        recorder.prepare();
        setRecorderInitialized( true );
    }
    catch (IllegalStateException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

private boolean startRecording() {

    try {
        getRecorder().start();
        setRecording( true );

        ImageView actionImageView = getActionImageView();
        actionImageView.setImageResource( R.drawable.record_red );
    }
    catch (Exception e) {
        getCamera().lock();
    }

    return true;
}

private void stopRecording() {

    MediaRecorder recorder = getRecorder();
    if ( recorder != null && isRecording() ) {
        recorder.stop();
        setRecording( false );
        setRecorderInitialized( false );

        try {
            insertVideo();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        initRecording();

        ImageView actionImageView = getActionImageView();
        actionImageView.setImageResource( R.drawable.record_green );
    }
}

private void destroyRecorder() {

    MediaRecorder recorder = getRecorder();
    recorder.release();
    setRecorder( null );
    getCamera().lock();
}

7voto

MattDavis Points 3022

La raison du léger zoom lors de l'appel de MediaRecorder.start() est due au redimensionnement de la caméra de prévisualisation pour correspondre à la résolution de la vidéo en cours d'enregistrement. Ce problème peut être résolu en définissant la résolution de prévisualisation et de la vidéo lors de la configuration. Je pense avoir aussi trouvé un moyen d'arrêter le scintillement, bien que j'aie constaté que lorsqu'on travaille avec la caméra et MediaRecorder, un peu de retard ou de scintillement peut provenir de plusieurs endroits, il peut donc être un peu plus difficile à suivre. La documentation Android pour configurer une caméra/enregistreur vidéo est un bon point de départ pour s'assurer que les principaux éléments sont configurés correctement, mais j'ai constaté qu'il est nécessaire de plonger dans certaines parties de la documentation de l'API de classe pour déboguer et rendre l'expérience vraiment fluide.

La classe Camera.Parameters est la clé pour maintenir une expérience d'enregistrement vidéo fluide. Une fois que vous avez un objet Camera, vous pouvez utiliser Camera.getParameters() pour obtenir les paramètres actuels à modifier. Camera.setParameters(Camera.Parameters) peut alors être utilisé pour déclencher les changements qui ont été apportés.

Pour empêcher le redimensionnement de la vidéo, nous devons nous assurer que la taille de prévisualisation des paramètres correspond à la résolution de la vidéo à enregistrer. Pour obtenir une liste des tailles de prévisualisation vidéo prises en charge, nous pouvons utiliser Camera.Parameters.getSupportedPreviewSizes() sur notre objet Parameters actuel, qui renverra une liste d'objets Camera.Size. Chacun de ces objets aura une propriété de largeur et de hauteur, accessible directement via Camera.Size.width et Camera.Size.height (pas de méthodes de getter). La méthode getSupportedPreviewSizes() est garantie de renvoyer au moins un résultat, et il semble que les résultats sont ordonnés de la plus haute à la plus basse résolution.

(Pour un niveau d'API > 11, il y a aussi une méthode getSupportedVideoSizes(), mais il semble que ce soit seulement si l'appareil possède des tailles de vidéo différentes des tailles de prévisualisation, sinon elle renvoie null. Je n'ai pas eu de succès avec cette méthode, donc je resterais avec l'utilisation de PreviewSizes pour l'instant car cela garantit de renvoyer une taille bonne à la fois pour la vidéo et la prévisualisation, mais il est bon d'en être conscient à l'avenir.)

Une fois que nous avons la Camera.Size qui correspond à la résolution vidéo souhaitée, nous pouvons définir cette taille en utilisant Camera.Parameters.setPreviewSize(largeur, hauteur). De plus, pour aider avec le scintillement, j'utilise Camera.Parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO). Une fois ces étapes prises, utilisez Camera.setParameters() pour notifier la caméra de vos changements. J'ai réussi en définissant ces paramètres une seule fois juste après avoir obtenu la caméra, car définir les paramètres pendant que l'utilisateur interagit avec cette activité a provoqué un certain retard. Si vous utilisez la même activité pour la capture vidéo et photo, vous pouvez également définir les paramètres d'image ici, l'objet Camera utilisera les paramètres appropriés pour chaque mode.

Presque terminé ! Maintenant que la prévisualisation est prise en charge, tout ce qui reste est de s'assurer que le MediaRecorder utilise la même résolution que la prévisualisation. Lors de la préparation de votre enregistreur multimédia, entre les appels à MediaRecorder.setProfile() (ou le paramétrage des encodeurs, pour un niveau d'API < 8) et MediaRecorder.setOutputFile(), placez un appel à MediaRecorder.setVideoSize(largeur, hauteur) en utilisant les mêmes valeurs que votre prévisualisation. Maintenant, la transition de la prévisualisation à l'enregistrement en utilisant MediaRecorder.start() devrait être sans couture, car ils utilisent tous les deux la même résolution.

Voici quelques extraits de code rapides pour que vous puissiez voir tout en action :

Obtention et réglage des paramètres :

Camera.Parameters params = camera.getParameters();

params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);

//myVideoSize est une instance de Camera.Size
List previewSizes = params.getSupportedPreviewSizes();
myVideoSize = previewSizes.get(0);
params.setPreviewSize(myVideoSize.width, myVideoSize.height);

camera.setParameters(params);

Ensuite, réglez la taille sur l'enregistreur multimédia :

//Après avoir défini le profil....
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

//Utilisez myVideoSize ci-dessus
mediaRecorder.setVideoSize(myVideoSize.width, myVideoSize.height);

//Avant de définir le fichier de sortie
mediaRecorder.setOutputFile(myFile);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X