I can download the JPGs from my DCIM folder in my Pixel 2 and I know that the video is encoded inside the jpg, but I don't know what image viewer I can use to see the motion. I usually use Irfanview, but I haven't yet been able to find out how to make it show the motion. And I haven't found anyone talking about how to do it. Anyone know?
I did some experimenting based on the post by @jameshenstridge and came up with a simple PHP script that successfully split every google motion photo i threw at it.
<?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";
?>
It should work on Windows and Linux. You just pass a path as the first argument and it will split any files that it believes are motion photos. You can use wildcards. It's non-destructive - the source file(s) are not deleted.
Some example uses:
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\*
I haven't seen any software to view them other than on the Google Photos website. I was curious about this so started pulling apart one of the photos from my phone, and here's what I found:
The image file appears to be a standard JPEG image, but continues on after the End of Image segment (
0xFF 0xD9
).exiftool
reports unrecognised MakerNotes. I suspect this custom metadata identifies the file as a motion photo.If transfer all the data after the EOI segment to a separate file, you'll have a standard MPEG-4 container. I got a GStreamer crash when trying to play it, but ffmpeg seems to be able to handle it and displayed the following metadata:
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
So, that's a 1.87 second H.264 video with resolution 1024x768, which seems to roughly match up with what I see from Google's apps/website (a drop in resolution and change in aspect ratio).
I know it isn't a complete solution, but it might be enough to get started on a tool to extract the videos.
Although the question is for Windows, I think it's appropriate to post my script to play it from command line on Linux here:
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[@]}"
Maybe it can be used on Windows as well, with enough Mingw/Cygwin hackery.