Как просмотреть движущиеся фотографии Google Camera на ПК с Windows?

Я могу загрузить файлы JPG из папки DCIM в свой Pixel 2 и знаю, что видео закодировано внутри JPG, но я не знаю, какую программу просмотра изображений я могу использовать для просмотра движения.

Обычно я использую Irfanview, но пока не могу понять, как заставить его показывать движение. И я не нашел никого, говорящего о том, как это сделать.

Кто-нибудь знает?

Ответы (5)

Я провел несколько экспериментов, основываясь на ответе Джеймса Хенстриджа , и придумал простой PHP-скрипт, который успешно разделил каждую фотографию движения камеры Google, которую я ей бросил.

24.01.2022 - Код обновлен. См. редактирование внизу этого поста. Я оставляю старый код здесь, чтобы избежать путаницы.

<?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";
  
?>

Он должен работать в Windows и Linux. Вы просто передаете путь в качестве первого аргумента, и он разделит все файлы, которые считает движущимися фотографиями. Вы можете использовать подстановочные знаки. Это неразрушающе - исходный файл(ы) не удаляются.

В некоторых примерах используется:

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 Как j3App упомянул в своем ответе , в какой-то момент Google решил добавить данные отладки между JPG и MP4 в некоторых случаях. В конце 2021 года я также начал видеть другие варианты (MP4 с разными начальными байтами, например: 0000001C вместо 00000018, дополнительные сегменты EOI JPG ранее на изображении рядом с тегами XMP и т. д.). В любом случае, я изменил код, чтобы сначала искать заголовок MP4, а затем работать в обратном направлении, чтобы найти сегмент JPG EOI. Это работало на всех вариантах, с которыми я сталкивался. Вот обновленный код:

<?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";
  
?>
Спасибо за хорошее решение. Поскольку мой Pixel 4a 5g добавляет отладочную информацию между фото и видео, мне пришлось внести небольшие коррективы в ваше решение (см. мой ответ ниже)

Я не видел никакого программного обеспечения для их просмотра, кроме как на веб-сайте Google Photos. Мне было любопытно, поэтому я начал разбирать одну из фотографий с моего телефона и вот что я нашел:

  1. Файл изображения выглядит как стандартное изображение JPEG, но продолжается после сегмента «Конец изображения» ( 0xFF 0xD9).

  2. exiftoolсообщает о нераспознанных MakerNotes. Я подозреваю, что эти пользовательские метаданные идентифицируют файл как движущуюся фотографию.

  3. Если вынести все данные после сегмента EOI в отдельный файл, получится стандартный контейнер MPEG-4. У меня произошел сбой GStreamer при попытке воспроизвести его, но ffmpeg, кажется, может справиться с этим и отобразил следующие метаданные:

    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
    

    Итак, это 1,87-секундное видео H.264 с разрешением 1024x768, которое, похоже, примерно совпадает с тем, что я вижу в приложениях/веб-сайте Google (падение разрешения и изменение соотношения сторон).

Я знаю, что это не полное решение, но этого может быть достаточно, чтобы начать работу с инструментом для извлечения видео.

Хотя вопрос для Windows, я думаю, что уместно опубликовать мой скрипт для его воспроизведения из командной строки в 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[@]}"

Возможно, его можно использовать и в Windows, с достаточным количеством хакерских атак Mingw/Cygwin.

Я попробовал ответ от Кори - спасибо, Кори. Поскольку мой Pixel 4a 5G добавляет значительный объем отладочной информации между jpg и mp4, мои извлеченные mp4 не воспроизводятся.

Поэтому мне пришлось добавить немного дополнительной функциональности в решение 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";
?>
Спасибо, что опубликовали это. Я также видел это, а также некоторые другие новые варианты. Я обновил свой исходный пост, чтобы он работал таким образом, чтобы, надеюсь, он смог продолжить работу с любыми будущими изменениями, которые Google решит внести.

Также есть Motion-Photo-Viewer . Можно либо разместить самостоятельно, либо использовать в Интернете для воспроизведения сингла *.MP.jpg(и извлечения mp4 через файлы right-click-save-as.

index.htmlВам не нужен веб-сервер, поэтому достаточно клонировать проект и открыть его .