I' ve a .MOV video sent by a phone messanger app. Can I retrieve the real creation data of the file and the author? I tried with ffprobe, mediainfo and similar tool but give me only the date when I download it.
I wrote a quick Python 2 script that can obtain the creation and modification timestamps, since those are easy to find. Finding the author is a bit harder because it can be stored in several different ways. Example usage:
$ ./mov-timestamps.py file.mov
creation date: 2013-03-29 16:14:01
modification date: 2013-03-29 16:14:13
Sometimes you might see a date of 1/1/1904. That means the timestamp is 0. If you see a date of 1/1/1970, the file was probably generated by FFmpeg, which doesn't store this metadata for security reasons.
#!/usr/bin/python
import datetime
import struct
import sys
ATOM_HEADER_SIZE = 8
# difference between Unix epoch and QuickTime epoch, in seconds
EPOCH_ADJUSTER = 2082844800
if len(sys.argv) < 2:
print "USAGE: mov-length.py <file.mov>"
sys.exit(1)
# open file and search for moov item
f = open(sys.argv[1], "rb")
while 1:
atom_header = f.read(ATOM_HEADER_SIZE)
if atom_header[4:8] == 'moov':
break
else:
atom_size = struct.unpack(">I", atom_header[0:4])[0]
f.seek(atom_size - 8, 1)
# found 'moov', look for 'mvhd' and timestamps
atom_header = f.read(ATOM_HEADER_SIZE)
if atom_header[4:8] == 'cmov':
print "moov atom is compressed"
elif atom_header[4:8] != 'mvhd':
print "expected to find 'mvhd' header"
else:
f.seek(4, 1)
creation_date = struct.unpack(">I", f.read(4))[0]
modification_date = struct.unpack(">I", f.read(4))[0]
print "creation date:",
print datetime.datetime.utcfromtimestamp(creation_date - EPOCH_ADJUSTER)
print "modification date:",
print datetime.datetime.utcfromtimestamp(modification_date - EPOCH_ADJUSTER)
moov
and then close it. Clearly not the right way to do it. –
Rarotonga Traceback (most recent call last): File "mov_timestamp.py", line 22, in <module> atom_size = struct.unpack(">I", atom_header[0:4])[0] struct.error: unpack requires a buffer of 4 bytes
Any idea how to change it for Python3? Thanks! –
Circuitry if atom_header[4:8] == 'moov':
with if atom_header[4:8].decode('utf-8') == 'moov':
to make the first block match the 'moov' target in a .mp4 from Canon (Python 3.10) –
Edaedacious So, I updated MMM's code to Python3 and improved a few things.
def get_mov_timestamps(filename):
''' Get the creation and modification date-time from .mov metadata.
Returns None if a value is not available.
'''
from datetime import datetime as DateTime
import struct
ATOM_HEADER_SIZE = 8
# difference between Unix epoch and QuickTime epoch, in seconds
EPOCH_ADJUSTER = 2082844800
creation_time = modification_time = None
# search for moov item
with open(filename, "rb") as f:
while True:
atom_header = f.read(ATOM_HEADER_SIZE)
#~ print('atom header:', atom_header) # debug purposes
if atom_header[4:8] == b'moov':
break # found
else:
atom_size = struct.unpack('>I', atom_header[0:4])[0]
f.seek(atom_size - 8, 1)
# found 'moov', look for 'mvhd' and timestamps
atom_header = f.read(ATOM_HEADER_SIZE)
if atom_header[4:8] == b'cmov':
raise RuntimeError('moov atom is compressed')
elif atom_header[4:8] != b'mvhd':
raise RuntimeError('expected to find "mvhd" header.')
else:
f.seek(4, 1)
creation_time = struct.unpack('>I', f.read(4))[0] - EPOCH_ADJUSTER
creation_time = DateTime.fromtimestamp(creation_time)
if creation_time.year < 1990: # invalid or censored data
creation_time = None
modification_time = struct.unpack('>I', f.read(4))[0] - EPOCH_ADJUSTER
modification_time = DateTime.fromtimestamp(modification_time)
if modification_time.year < 1990: # invalid or censored data
modification_time = None
return creation_time, modification_time
and...
Wouldn't you know it, just as I finished I found how to do it with exiftool, which I use for similar tasks with .jpg files. :-/
⏵ exiftool -time:all img_3904.mov
I wrote a quick Python 2 script that can obtain the creation and modification timestamps, since those are easy to find. Finding the author is a bit harder because it can be stored in several different ways. Example usage:
$ ./mov-timestamps.py file.mov
creation date: 2013-03-29 16:14:01
modification date: 2013-03-29 16:14:13
Sometimes you might see a date of 1/1/1904. That means the timestamp is 0. If you see a date of 1/1/1970, the file was probably generated by FFmpeg, which doesn't store this metadata for security reasons.
#!/usr/bin/python
import datetime
import struct
import sys
ATOM_HEADER_SIZE = 8
# difference between Unix epoch and QuickTime epoch, in seconds
EPOCH_ADJUSTER = 2082844800
if len(sys.argv) < 2:
print "USAGE: mov-length.py <file.mov>"
sys.exit(1)
# open file and search for moov item
f = open(sys.argv[1], "rb")
while 1:
atom_header = f.read(ATOM_HEADER_SIZE)
if atom_header[4:8] == 'moov':
break
else:
atom_size = struct.unpack(">I", atom_header[0:4])[0]
f.seek(atom_size - 8, 1)
# found 'moov', look for 'mvhd' and timestamps
atom_header = f.read(ATOM_HEADER_SIZE)
if atom_header[4:8] == 'cmov':
print "moov atom is compressed"
elif atom_header[4:8] != 'mvhd':
print "expected to find 'mvhd' header"
else:
f.seek(4, 1)
creation_date = struct.unpack(">I", f.read(4))[0]
modification_date = struct.unpack(">I", f.read(4))[0]
print "creation date:",
print datetime.datetime.utcfromtimestamp(creation_date - EPOCH_ADJUSTER)
print "modification date:",
print datetime.datetime.utcfromtimestamp(modification_date - EPOCH_ADJUSTER)
moov
and then close it. Clearly not the right way to do it. –
Rarotonga Traceback (most recent call last): File "mov_timestamp.py", line 22, in <module> atom_size = struct.unpack(">I", atom_header[0:4])[0] struct.error: unpack requires a buffer of 4 bytes
Any idea how to change it for Python3? Thanks! –
Circuitry if atom_header[4:8] == 'moov':
with if atom_header[4:8].decode('utf-8') == 'moov':
to make the first block match the 'moov' target in a .mp4 from Canon (Python 3.10) –
Edaedacious Did you try hachoir? Install it with pip install hachoir
, and then, at the command line:
$ hachoir-metadata IMG_9395.MOV
which returns e.g.
Metadata:
- Duration: 2 sec 220 ms
- Image width: 1440 pixels
- Image height: 1080 pixels
- Creation date: 2020-04-15 20:22:57
- Last modification: 2020-04-15 20:22:58
- Comment: Play speed: 100.0%
- Comment: User volume: 100.0%
- MIME type: video/quicktime
- Endianness: Big endian
You can also use it in Python if you prefer:
from hachoir.parser import createParser
from hachoir.metadata import extractMetadata
def creation_date(filename):
parser = createParser(filename)
metadata = extractMetadata(parser)
return metadata.get('creation_date')
Here is a version that is not pure python but instead requires libmediainfo that is a part of the mediainfo tool.
import pymediainfo
import sys
media_info = pymediainfo.MediaInfo.parse(sys.argv[1])
#For the first track - otherwise iterate over each track
print(' Encoded date {}'.format(track[0].encoded_date))
print(' Tagged date {}'.format(track[0].tagged_date))
QuickTime stores the video creation date in the MediaCreateDate
XMP field or at least this is what Exiv2 thinks it is in. That said you can use py3exiv2 to read the creation date from the MOV
file metadata.
import time
import pyexiv2
from datetime import datetime
# The XMP field that QuickTime stores media creation date in
MEDIA_CREATE_KEY = 'Xmp.video.MediaCreateDate'
# HFS Epoch offset, difference between 01-01-1904 and 01-01-1970
HFS_EPOCH_OFFSET = 2082844800
def get_ctime_exiv2_mov(fpath: str) -> datetime:
ret = None
metadata = pyexiv2.ImageMetadata(fpath)
metadata.read()
if MEDIA_CREATE_KEY in metadata:
_ts_hfs = metadata[MEDIA_CREATE_KEY].raw_value.strip()
if _ts_hfs and _ts_hfs.isnumeric():
ts_hfs = int(_ts_hfs)
if ts_hfs > HFS_EPOCH_OFFSET:
ts_unix = ts_hfs - HFS_EPOCH_OFFSET
if ts_unix < time.time():
ret = datetime.fromtimestamp(ts_unix)
return ret
from @jeanggi90's comment and the addendum to Gringo Suave's answer, posting separately so it is easier to find:
exiftool -time:all img_3904.mov
I found that it can even set the file modification time accordingly, e.g. to the "Create Date":
exiftool '-FileModifyDate<CreateDate' img_3904.mov
© 2022 - 2024 — McMap. All rights reserved.
exiftool -time:all vid.mov
– Sorkin