Я могу загрузить файлы JPG из папки DCIM в свой Pixel 2 и знаю, что видео закодировано внутри JPG, но я не знаю, какую программу просмотра изображений я могу использовать для просмотра движения.
Обычно я использую Irfanview, но пока не могу понять, как заставить его показывать движение. И я не нашел никого, говорящего о том, как это сделать.
Кто-нибудь знает?
Я провел несколько экспериментов, основываясь на ответе Джеймса Хенстриджа , и придумал простой 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";
?>
Я не видел никакого программного обеспечения для их просмотра, кроме как на веб-сайте Google Photos. Мне было любопытно, поэтому я начал разбирать одну из фотографий с моего телефона и вот что я нашел:
Файл изображения выглядит как стандартное изображение JPEG, но продолжается после сегмента «Конец изображения» ( 0xFF 0xD9
).
exiftool
сообщает о нераспознанных MakerNotes. Я подозреваю, что эти пользовательские метаданные идентифицируют файл как движущуюся фотографию.
Если вынести все данные после сегмента 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";
?>
Также есть Motion-Photo-Viewer . Можно либо разместить самостоятельно, либо использовать в Интернете для воспроизведения сингла *.MP.jpg
(и извлечения mp4 через файлы right-click-save-as
.
index.html
Вам не нужен веб-сервер, поэтому достаточно клонировать проект и открыть его .
j3App