Skip to content

Instantly share code, notes, and snippets.

@mohsenasm
Last active December 18, 2025 14:16
Show Gist options
  • Select an option

  • Save mohsenasm/d7e9e31521add91029428c5e28d24b3e to your computer and use it in GitHub Desktop.

Select an option

Save mohsenasm/d7e9e31521add91029428c5e28d24b3e to your computer and use it in GitHub Desktop.
Samsung Motion Photo extractor
#!/usr/bin/env python3
"""
Samsung Motion Photo extractor
This code is the minimal version of the work in https://github.com/joemck/ExtractMotionPhotos
Usage: python3 samsung_motion_photo_extractor.py <motion_photo_file>
"""
def init_search(magic):
"""
Initialize Boyer-Moore search tables d1 and d2.
"""
magic_len = len(magic)
d1 = [magic_len] * 256
d2 = [0] * magic_len
# Build d1 table
for i in range(magic_len - 1):
d1[magic[i]] = magic_len - 1 - i
# Build d2 table
last_prefix = magic_len - 1
for i in range(magic_len - 1, -1, -1):
suffix_len = magic_len - i - 1
j = 0
while j < suffix_len and magic[j] == magic[i + 1 + j]:
j += 1
if j == suffix_len:
last_prefix = i + 1
d2[i] = last_prefix + (magic_len - 1 - i)
# Update d2 for proper suffix matching
for i in range(magic_len - 1):
suffix_len = 0
while (suffix_len < i and
magic[i - suffix_len] == magic[magic_len - 1 - suffix_len]):
suffix_len += 1
if magic[i - suffix_len] != magic[magic_len - 1 - suffix_len]:
d2[magic_len - 1 - suffix_len] = magic_len - 1 - i + suffix_len
return d1, d2
def find_magic(data):
"""
Boyer-Moore string search to find the MotionPhoto_Data magic bytes.
Returns the position where the magic bytes were found, or -1 if not found.
"""
magic = bytes([
0x4D, 0x6F, 0x74, 0x69, 0x6F, 0x6E, 0x50, 0x68,
0x6F, 0x74, 0x6F, 0x5F, 0x44, 0x61, 0x74, 0x61
])
d1, d2 = init_search(magic)
magic_len = len(magic)
size = len(data)
i = magic_len - 1
while i < size:
j = magic_len - 1
while j >= 0 and data[i] == magic[j]:
i -= 1
j -= 1
if j < 0:
return i + 1
i += max(d1[data[i]], d2[j])
return -1
def split_motion_photo(input_file):
"""
Split a Samsung motion photo into photo and video files.
"""
# Read the input file
with open(input_file, 'rb') as f:
file_data = f.read()
# Find the magic bytes
split_pos = find_magic(file_data)
if split_pos < 0:
print(f"Error: {input_file} is not a motion photo (magic bytes not found)")
return False
# Generate output filenames
base_name = input_file.rsplit('.', 1)[0]
ext = input_file.rsplit('.', 1)[1]
photo_file = f"{base_name}_photo.{ext}"
video_file = f"{base_name}_video.mp4"
# Write the photo portion (before split)
with open(photo_file, 'wb') as f:
f.write(file_data[:split_pos])
print(f"Extracted: {photo_file}")
# Write the video portion (after split, skipping 16 magic bytes)
with open(video_file, 'wb') as f:
f.write(file_data[split_pos + 16:])
print(f"Extracted: {video_file}")
return True
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python3 samsung_motion_photo_extractor.py <motion_photo_file>")
print("Example: python3 samsung_motion_photo_extractor.py file.jpg")
sys.exit(1)
input_file = sys.argv[1]
split_motion_photo(input_file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment