12 votes

Comment puis-je afficher les photos animées de Google Camera sur mon PC Windows ?

Je peux télécharger les JPG à partir de mon dossier DCIM dans mon Pixel 2 et je sais que la vidéo est encodée dans le JPG, mais je ne sais pas quel visualiseur d'images je peux utiliser pour voir le mouvement.

J'utilise habituellement Irfanview, mais je n'ai pas encore réussi à trouver comment lui faire afficher le mouvement. Et je n'ai trouvé personne qui parle de la façon de le faire.

Quelqu'un le sait-il ?

8voto

Kory Points 71

J'ai fait quelques expériences basées sur la réponse de James Henstridge et j'ai créé un simple script PHP qui a réussi à diviser toutes les photos de mouvement de la Google Camera que je lui ai envoyées.

2022-01-24 - Le code a été mis à jour. Voir la modification au bas de ce message. Je laisse l'ancien code ici pour éviter toute confusion.

<?php

  $src_arg = $argv[1];
  $src_dir = realpath(pathinfo($src_arg, PATHINFO_DIRNAME)); 

  echo "Scanning for files...\n";

  foreach (glob($src_arg) as $src) {

    $file = realpath($src);

    if (!is_dir($file) && in_array(strtoupper(pathinfo($file, PATHINFO_EXTENSION)), ["JPEG", "JPG"])) {

      echo "\tProcessing: " . $file . "\n";

      $filesize = filesize($file);
      echo "\t\tFile size: " . $filesize . "\n";

      $handle = fopen($file, "rb");
      $data = fread($handle, $filesize);
      fclose($handle);

      $eoi_pos = strpos($data, "\xFF\xD9\x00\x00\x00\x18");
      echo "\t\tEOI segment position: " . $eoi_pos . "\n";

      if ($eoi_pos !== FALSE) {
        $output_base = $src_dir . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME);
        echo "\t\tSaving photo...\n";
        file_put_contents($output_base . "_photo.jpg", substr($data, 0, $eoi_pos + 2));
        echo "\t\tSaving video...\n";
        file_put_contents($output_base . "_video.mp4", substr($data, $eoi_pos + 2));
      } else {
        echo "\t\tSKIPPING - File does not appear to be a Google motion photo.\n";
      }

    }

  }

  echo "Done.\n";

?>

Il devrait fonctionner sous Windows et Linux. Il vous suffit de passer un chemin d'accès comme premier argument et il divisera tous les fichiers qu'il croit être des photos de mouvement. Vous pouvez utiliser des caractères génériques. C'est non-destructif - le(s) fichier(s) source(s) ne sont pas supprimés.

Quelques exemples d'utilisation :

php google_motion_photo_splitter.php c:\test\file.jpg
php google_motion_photo_splitter.php c:\test\*.jpg
php google_motion_photo_splitter.php c:\test\*

2022-01-24 Comme j3App a mentionné dans sa réponse A un moment donné, Google a décidé d'ajouter des données de débogage entre le JPG et le MP4 dans certains cas. À la fin de l'année 2021, j'ai également commencé à voir d'autres variations (MP4s avec des octets de départ différents - ex : 0000001C au lieu de 00000018, segments JPG EOI supplémentaires plus tôt dans l'image près des balises XMP, etc). Quoi qu'il en soit, j'ai modifié le code pour qu'il recherche d'abord l'en-tête MP4, puis le segment JPG EOI. Cela a fonctionné sur toutes les variantes que j'ai rencontrées. Voici le code mis à jour :

<?php

$src_arg = $argv[1];
$src_dir = realpath(pathinfo($src_arg, PATHINFO_DIRNAME)); 

echo "Scanning for files...\n";

foreach (glob($src_arg) as $src) {

  $file = realpath($src);

  if (!is_dir($file) && in_array(strtoupper(pathinfo($file, PATHINFO_EXTENSION)), ["JPEG", "JPG"])) {

    echo "\tProcessing: " . $file . "\n";

    $filesize = filesize($file);
    echo "\t\tFile size: " . $filesize . "\n";

    $handle = fopen($file, "rb");
    $data = fread($handle, $filesize);
    fclose($handle);

    $mp4_start_pos = strpos($data, "ftyp");

    if ($mp4_start_pos !== FALSE) {
      $mp4_start_pos -= 4; # the real beginning of the mp4 starts 4 bytes before "ftyp"

      $jpg_end_pos = strrpos(substr($data, 0, $mp4_start_pos), "\xFF\xD9");

      if ($jpg_end_pos !== FALSE) {
        $jpg_end_pos += 2; # account for the length of the search string

        $output_base = $src_dir . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME);
        echo "\t\tSaving photo...\n";
        file_put_contents($output_base . "_photo.jpg", substr($data, 0, $jpg_end_pos));
        echo "\t\tSaving video...\n";
        file_put_contents($output_base . "_video.mp4", substr($data, $mp4_start_pos));

      } else {
        echo "\t\tSKIPPING - File appears to contain an MP4 but the no valid JPG EOI segment could be found.\n";
      }

    } else {
      echo "\t\tSKIPPING - File does not appear to be a Google motion photo.\n";
    }

  }

}

echo "Done.\n";

?>

0 votes

Merci pour cette bonne solution. Comme mon Pixel 4a 5g ajoute des infos de débogage entre la photo et la vidéo, j'ai dû faire quelques petits ajustements à votre solution (voir ma réponse ci-dessous).

6voto

Dhawal Agarwal Points 41

Je n'ai pas vu de logiciel permettant de les visualiser autrement que sur le site de Google Photos. J'étais curieux de savoir ce qu'il en était et j'ai commencé à démonter l'une des photos de mon téléphone, et voici ce que j'ai trouvé :

  1. Le fichier d'image semble être une image JPEG standard, mais il continue après le bouton Fin du segment d'image ( 0xFF 0xD9 ).

  2. exiftool rapporte des MakerNotes non reconnues. Je soupçonne que ces métadonnées personnalisées identifient le fichier comme une photo de mouvement.

  3. Si vous transférez toutes les données après le segment EOI dans un fichier séparé, vous obtiendrez un conteneur MPEG-4 standard. J'ai eu un crash de GStreamer en essayant de le lire, mais ffmpeg semble être capable de le gérer et a affiché les métadonnées suivantes :

    Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'foo.mp4':
      Metadata:
        major_brand     : mp42
        minor_version   : 0
        compatible_brands: isommp42
        creation_time   : 2018-07-07T20:37:57.000000Z
        com.android.version: 8.1.0
      Duration: 00:00:01.87, start: 0.000000, bitrate: 20283 kb/s
        Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, smpte170m/smpte170m/unknown), 1024x768, 20161 kb/s, SAR 1:1 DAR 4:3, 30.01 fps, 30 tbr, 90k tbn, 180k tbc (default)
        Metadata:
          creation_time   : 2018-07-07T20:37:57.000000Z
          handler_name    : VideoHandle
        Stream #0:1(eng): Data: none (mett / 0x7474656D), 108 kb/s (default)
        Metadata:
          creation_time   : 2018-07-07T20:37:57.000000Z
          handler_name    : MetadHandle
        Stream #0:2(eng): Data: none (mett / 0x7474656D), 0 kb/s (default)
        Metadata:
          creation_time   : 2018-07-07T20:37:57.000000Z
          handler_name    : MetadHandle
    Unsupported codec with id 0 for input stream 1
    Unsupported codec with id 0 for input stream 2

    Il s'agit donc d'une vidéo H.264 de 1,87 seconde avec une résolution de 1024x768, ce qui semble correspondre à peu près à ce que je vois sur les applications/site Web de Google (une baisse de la résolution et un changement du rapport hauteur/largeur).

Je sais que ce n'est pas une solution complète, mais cela pourrait suffire pour démarrer un outil d'extraction des vidéos.

2voto

Flame Points 1138

Bien que la question soit pour Windows, je pense qu'il est approprié de poster ici mon script pour le jouer en ligne de commande sous Linux :

https://gist.github.com/vi/5de17bb8d4ea91b8c28e79e0bac6c3cb

#!/bin/bash

if [[ -z "$1"  || "$1" == --help || "$1" == "-?" ]]; then
    echo "Usage: mvimg_play MVIMG_20190806_183324.jpg [other files]"
    echo "Plays Google's Motion Photo using mpv. Depends on exiftool, mktemp, bash and mpv."
    exit 0
fi

FOUND=0
ARGS=()

TORM=()
TOKILL=()

function cleanup() {
    for i in "${TORM[@]}"; do
        rm -f "$i"
    done
    for p in ${TOKILL[@]}; do
        wait $p
    done
}

trap "cleanup" EXIT

for i in "$@"; do
    O=$(exiftool -t $i  | grep -F 'Micro Video Offset' | cut -f 2-2)
    if [[ -z "$O" ]]; then
        # wrong file? Just appending to playlist as is
        ARGS+=($i)
    else
        FOUND=1
        S=$(find $i -printf '%s')
        T=`mktemp`

        ARGS+=("$T")
        dd if="$i" skip=$((S-O)) iflag=skip_bytes of="$T" 2> /dev/null &
        TOKILL+=($!)
        TORM+=("$T")
    fi
done

if [[ $FOUND == 0 ]]; then
    echo "EXIF tag wasn't detected in specified files. Maybe exiftool does not work?" >&2
fi

mpv "${ARGS[@]}"

Peut-être qu'il peut être utilisé sous Windows également, avec suffisamment de piratage de Mingw/Cygwin.

2voto

Alex Points 101

Il y a aussi Motion-Photo-Viewer . Il peut être hébergé par lui-même ou utilisé en ligne pour jouer à un seul jeu. *.MP.jpg (et extraire le mp4 par right-click-save-as .

Vous n'avez pas besoin d'un serveur Web, donc cloner le projet et l'ouvrir index.html suffira.

1voto

j3App Points 121

J'ai essayé la réponse de Kory - Merci Kory. Comme mon Pixel 4a 5G ajoute une quantité importante d'informations de débogage entre le jpg et le mp4, mes mp4 extraits n'étaient pas lus.

J'ai donc dû ajouter une petite fonctionnalité supplémentaire à la solution de Kory.

<?php

/** execute like > php motionPhotoSplitter.php "Camera Roll/*.MP.jpg" < */
const MP4_TYPES = ["avc1", "iso2", "isom", "mmp4", "mp41", "mp42", "mp71", "msnv", "ndas", "ndsc", "ndsh", "ndsm", "ndsp", "ndss", "ndxc", "ndxh", "ndxm", "ndxp", "ndxs"];
$src_arg = $argv[1];
$src_dir = realpath(pathinfo($src_arg, PATHINFO_DIRNAME));

echo "Scanning for files...\n";

foreach (glob($src_arg) as $src) {

    $file = realpath($src);

    if (!is_dir($file) && in_array(strtoupper(pathinfo($file, PATHINFO_EXTENSION)), ["JPEG", "JPG"])) {

        echo "\tProcessing: " . $file . "\n";

        $filesize = filesize($file);
        echo "\t\tFile size: " . $filesize . "\n";

        $handle = fopen($file, "rb"); // binary read
        $data = fread($handle, $filesize);
        fclose($handle);

        $eoi_pos = strpos($data, "\xFF\xD9"); // end of image in a jpeg file: #FFD9
        echo "\t\tEOI segment position: " . $eoi_pos . "\n";

        if ($eoi_pos !== FALSE) {
            $output_base = $src_dir . DIRECTORY_SEPARATOR . pathinfo($file, PATHINFO_FILENAME);
            echo "\t\tSaving photo...\n";
            file_put_contents($output_base . "_photo.jpg", substr($data, 0, $eoi_pos + 2));

/** an mp4 block starts with 4 bytes for length, then "ftyp", then a valid mp4-type as defined in the array MP4_TYPES */

            $mp4Pos = strpos($data, "ftyp", $eoi_pos);
            if ($mp4Pos && in_array(substr($data, $mp4Pos + 4, 4), MP4_TYPES)) {
                echo "\t\tSaving video...\n";
                file_put_contents($output_base . "_video.mp4", substr($data, $mp4Pos - 4));
            }
        } else {
            echo "\t\tSKIPPING - File does not appear to be a Google motion photo.\n";
        }
    }
}
echo "Done.\n";
?>

0 votes

Merci d'avoir posté ce message. J'ai également vu cela ainsi que d'autres nouvelles variations. J'ai mis à jour mon message original pour qu'il fonctionne d'une manière qui, je l'espère, pourra continuer à fonctionner avec tous les changements futurs que Google décidera d'apporter.

androidalle.com

AndroidAlle est une communauté de androiders où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X