3

我最近发现我的一台相机的内部时钟设置比实际日期/时间晚了近两年,这打乱了我图书馆时间轴中照片和视频的顺序。我很快发现了日期/时间转换功能exiftool的美妙的批量更新功能。然而不幸的是,它还不支持修改 MP4 视频文件:

$ exiftool -AllDates+="0:0:729 3:17:0" test.mp4
Error: Writing of MP4 files is not yet supported - test.mp4
    0 image files updated
    1 files weren't updated due to errors

如何为 MP4 视频文件执行类似的批处理日期转换功能?

4

2 回答 2

1

基于QuickTime 文件格式规范,我整理了一个概念验证 Python 脚本,用于粗略地转换时间戳,让我现在可以通过:

#!/usr/bin/env python
import datetime
import sys

def int_bytes(raw):
    value = 0
    for byte in raw:
        value <<= 8
        value += ord(byte)
    return value

def bytes_int(value, size=4):
    raw = []
    for byte in range(size):
        raw.append(chr((value >> 8*byte) % 256))
    return ''.join(reversed(raw))


ATOM_FORMAT = (
    ('atom_size', 4, int_bytes),
    ('type', 4, str),
    ('version', 1, int_bytes),
    ('flags', 3, int_bytes),
    ('creation_time', 4, int_bytes),
    ('modification_time', 4, int_bytes),
    # that's all I need for now, and is common
    # between tkhd, mvhd and mdhd
    # ...
)

ATOM_TYPES = ('tkhd', 'mvhd', 'mdhd')

TIMESTAMP_EPOCH = datetime.datetime(1904, 1, 1, 0, 0)

def from_timestamp(timestamp):
    return TIMESTAMP_EPOCH + datetime.timedelta(0, timestamp)

def to_timestamp(datetime_obj):
    return int((datetime_obj - TIMESTAMP_EPOCH).total_seconds())

def shift_dates(mp4, atom_type, delta):
    # TODO: refactor
    mp4.seek(0)
    data = mp4.read() # TODO: don't load whole file
    type_index = -1
    while True:
        try:
            type_index = data.index(atom_type, type_index+1)
        except ValueError:
            if type_index < 0:
                raise RuntimeError('Cannot find atom: {}'.format(atom_type))
            else:
                break
        else:
            sys.stdout.write(
                '  Found {} at {}\n'.format(atom_type, type_index))
        offset = type_index - ATOM_FORMAT[0][1]

        header_data = {}
        offsets = {}
        for field, size, convert in ATOM_FORMAT:
            offsets[field] = offset
            offset += size
            header_data[field] = convert(data[offsets[field]:][:size])

        for field in ('creation_time', 'modification_time'):
            original = from_timestamp(header_data[field])
            shifted = original + delta
            mp4.seek(offsets[field])
            mp4.write(bytes_int(to_timestamp(shifted)))
            sys.stdout.write(
                '    {}: {} -> {}\n'.format(field, original, shifted))


if __name__ == '__main__':
    try:
        filename = sys.argv[1]
        days, seconds = map(int, sys.argv[2:])
    except (IndexError, TypeError, ValueError):
        sys.stderr.write(
            "USAGE: {} mp4_file days seconds\n".format(
                sys.argv[0]
            )
        )
        sys.exit(1)

    try:
        f = open(filename, 'rwb+')
    except IOError:
        sys.stderr.write("ERROR: cannot open {}\n".format(filename))
        sys.exit(1)
    else:
        delta = datetime.timedelta(days, seconds)
        sys.stdout.write(
            'Shifting timestamps of {} by {!r}:\n'.format(filename, delta))
        for atom_type in ATOM_TYPES:
            shift_dates(f, atom_type, delta)
        f.close()
        sys.stdout.write('Done.\n')
于 2012-12-23T07:28:07.833 回答
0

ExifTool 现在能够编辑 MP4/MOV 视频文件中的时间戳和许多其他标签。但由于AllDates标签只编辑三个特定标签,其中两个不经常出现在视频文件中,因此上述命令很可能只编辑视频文件中的一个标签(参见快捷方式标签名称页面AllDates上的注释) .

要编辑所有与时间相关的标签,可以使用以下命令:
exiftool -Time:All+="0:0:729 3:17:0" test.mp4

于 2019-12-13T20:10:37.930 回答