Google Pixel "Motion Photo"

From LinuxReviews
Jump to navigationJump to search
Mobile.png

A "motion photo" is a special kind of "picture" that has a short video clip embedded. The Google Pixel line of smartphones supports taking "Motion Photos" using the bundled photo application. The image part of "motion photo" files can be opened in any image viewer capable of opening JPEG files, the video part can't. GNU/Linux users can easily extract the video files embedded in "motion photo" files using a few very simple commands.

The "Motion Photo" Format[edit]

"Motion Photo" files are seemingly regular .jpg image files; and to some degree they are. The regular image is in the first part of the file. This makes it possible to open the static image embedded in "smart photos" in any program with support or JPEG images (that would be all image viewers, editors and other photo-related programs). The video portion is embedded in JPEG file right after the end of the still image within it.

"Motion Photo" image files can be identified in two different ways:

  • Current versions of the Pixel's photo application creates filenames the PXL_[datetime].MP.jpg pattern.
    • Older versions created files using the MVIMG_[datetime].jpg pattern.
  • "Motion Photo" files contain a lot of special photo metadata. exiv2 and exiftool can be used to look at the meta-data in a JPEG file.
    • Newer "Motion Photo" files following the PXL_[datetime].MP.jpg file naming pattern contain Xmp.GCamera.MotionPhoto, Xmp.GCamera.MotionPhotoVersion tags that are not found any other kinds of JPEG files.
    • Older "Motion Photo" files following the MVIMG_[datetime].jpg pattern contain Xmp.GCamera.MicroVideo, Xmp.GCamera.MicroVideoVersion and Xmp.GCamera.MicroVideoOffset. These tags are, like the newer ones, unique to older "Motion Photo" files.

Just looking at the file name is obviously the simplest way to identify these images (unless someone renames it before they send you one).

HOWTO Extract The Video Part Of Google Pixel "Motion Photo" Image Files On Linux[edit]

Newer "motion Photo" files (following the PXL_[datetime].MP.jpg naming scheme) can be extracted with:

File: extract_pixel_motionphotovideo.sh
#!/bin/sh
#
## Extract the video from a MotionPhoto file to PXL_*.MP.mp4
#
# Find out where in the file the video part starts
extractposition=$(grep --binary --byte-offset --only-matching --text \
-P "\x00\x00\x00\x18\x66\x74\x79\x70\x6d\x70\x34\x32" $1 | sed 's/^\([0-9]*\).*/\1/')
# Actually extract the video
dd if="$1" skip=1 bs=$extractposition of="$(basename -s .jpg $1).mp4"

Videos from older "motion photo" files following the MVIMG_[datetime].jpg pattern can be extracted with:

File: extract_oldpixel_motionphotovideo.sh
#!/bin/bash
#
# Extracts the microvideo from a MVIMG_*.jpg file

# The offset is from the ending of the file, so calculate accordingly
offset=$(exiv2 -p X "$1" | grep MicroVideoOffset | sed 's/.*\"\(.*\)"/\1/')
filesize=$(du --apparent-size --block=1 "$1" | sed 's/^\([0-9]*\).*/\1/')
extractposition=$(expr $filesize - $offset)
echo offset: $offset
echo filesize: $filesize
echo extractposition=$extractposition
dd if="$1" skip=1 bs=$extractposition of="$(basename -s .jpg $1).mp4"

The above shown method for extracting newer files use the MP4 video header to find the start of the embedded video files. The older format had a Xmp.GCamera.MicroVideoOffset with the offset where the video file starts, so the script for older files used instead (though it is possible to extract those too by looking for the MP4 video file header).

"Motion Photo" files are not fully supported by any image viewer or editor that we are aware of, so you will have to extract the video file if you want to view the video part of such files on GNU/Linux operating systems. This will hopefully change in the future as it would not be very hard to implement support in image viewers built on libraries with video capabilities (It should, for example, be very easy if the application uses KDE frameworks).


avatar

Anonymous (55278249f3)

16 months ago
Score 0

Ouch! It looks like it changed recently. Your hex pattern is matching "ftypmp42", but my Pixel 4a is running Android 12 and I need to find the offset at "ftypisom":

$ grep -F --byte-offset --only-matching --text ftypisom PXL_20210915_163833955.MP.jpg 2840255:ftypisom

Cheers!
avatar

Anonymous (fb60b77a6e)

6 months ago
Score 0

In my files, the hex value before ftypisom has also changed; it works for me with:

extractposition=$(grep --binary --byte-offset --only-matching --text \

-P "\x00\x00\x00\x1c\x66\x74\x79\x70\x69\x73\x6f\x6d" $1 | sed 's/^\([0-9]*\).*/\1/')
avatar

Anonymous (2c856fdcd5)

5 months ago
Score 0

Please would you be able to post in full what your script looks like now? I really appreciate it.

I have a pixel 6a and am trying to do this, but unable to see success. Thank you
avatar

Anonymous (af007c3b58)

one month ago
Score 0

The latest example doesn't work for me (Pixel 7). My working solution:

$ extractposition=$(grep --binary --byte-offset --only-matching --text "ftyp" $1 | sed 's/^\([0-9]*\).*/\1/')

-> the real beginning of the mp4 starts 4 bytes before "ftyp"

$ dd if="$1" skip=1 bs=$((extractposition-4)) of="$(basename -s .jpg $1).mp4"
avatar

Anonymous (3d794344a5)

one hour 2 minutes ago
Score 0

Sameish situation as the Anon user above had, here. However, I implemented it with a slightly different script that searches for the exact binary header that should start the MP4 file:

extractposition=$(grep --binary --byte-offset --only-matching --text -P "\x00\x00\x00\x1C\x66\x74\x79\x70\x69\x73\x6f\x6d" $1 | sed 's/^\([0-9]*\).*/\1/')

I also created a KDE service so I could just right click these files and extract the MP4 from now on.
Add your comment
LinuxReviews welcomes all comments. If you do not want to be anonymous, register or log in. It is free.