Last active
April 8, 2023 11:30
-
-
Save lclibardi/382292b2ddd786159dfa16d93955eea1 to your computer and use it in GitHub Desktop.
Get Quicktime Media DateEncoded Exif data
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
These are 5 different methods that attempt to retrieve the Quicktime property metadata "Media DateEncoded" from an 'mp4' file. | |
''' | |
import os | |
import re | |
import struct | |
import subprocess as sub | |
from datetime import datetime | |
from hachoir.parser import createParser | |
from hachoir.metadata import extractMetadata | |
from win32com.propsys import propsys, pscon | |
# Download ExifTool from https://exiftool.org/ | |
EXIF_TOOL = "exiftool.exe" | |
def method_1(fpath): | |
# On Windows ctime means "Creation time", on Linux "Changed time" | |
ctime = os.path.getctime(fpath) | |
dtime = datetime.fromtimestamp(ctime) | |
return dtime.strftime("%Y:%m:%d %H:%M:%S") | |
def method_2(fpath): | |
''' | |
Requires Hachoir installed. For Python3 run: | |
>> pip3 install hachoir==3.1.1 | |
>> pip3 install hachoir-parser | |
The property key 'Creation date' is a filesystem metadata, but | |
it was the only one returned by Hachoir. What I really need is | |
the Quicktime key 'Media_DateEncoded', which Windows Explorer | |
calls "Media Created" | |
''' | |
parser = createParser(fpath) | |
with parser: | |
metadata = extractMetadata(parser) | |
exif_dict = metadata.exportDictionary()['Metadata'] | |
return exif_dict['Creation date'] | |
def method_3(fpath): | |
''' | |
Runs this shell comand: | |
>> exiftool.exe -h VID_20190106_162804.mp4 | |
...which returns an HTML like string from stdout. | |
So using regular expression, we look for this section: | |
"Media Create Date</td><td>2019:01:07 00:28:08</td></tr>" | |
''' | |
p = sub.Popen( | |
[EXIF_TOOL, '-h',fpath], | |
stdout=sub.PIPE, | |
encoding='utf8') | |
res, err = p.communicate() | |
pattern = re.compile( | |
r'Media Create Date\</td\>\<td\>(\d{4}:\d{2}:\d{2}\s\d{2}:\d{2}:\d{2})' | |
) | |
match = re.findall(pattern, res) | |
if match: | |
return match[0] | |
def method_4(fpath): | |
''' | |
Here we look for the Quicktime property key: Media_DateEncoded, which | |
Windows Explorer calls "Media Created" | |
''' | |
fpath = fpath.replace('/', '\\') # Windows api does not work with posix paths | |
properties = propsys.SHGetPropertyStoreFromParsingName(fpath) | |
dtime = properties.GetValue(pscon.PKEY_Media_DateEncoded).GetValue() | |
return dtime.strftime("%Y:%m:%d %H:%M:%S") | |
def method_5(fpath): | |
ATOM_HEADER_SIZE = 8 | |
# Difference between Unix epoch and QuickTime epoch, in seconds | |
EPOCH_ADJUSTER = 2082844800 | |
# open file and search for moov item | |
f = open(fpath, "rb") | |
while 1: | |
atom_header = f.read(ATOM_HEADER_SIZE) | |
if atom_header[4:8] == b'moov': | |
break | |
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 Exception("moov atom is compressed") | |
elif atom_header[4:8] != b'mvhd': | |
raise Exception("expected to find 'mvhd' header") | |
else: | |
f.seek(4, 1) | |
creation_date = struct.unpack(">I", f.read(4))[0] | |
dtime = datetime.utcfromtimestamp(creation_date - EPOCH_ADJUSTER) | |
return dtime.strftime("%Y:%m:%d %H:%M:%S") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment