2012-12-23 44 views
1

我最近发现我的一台摄像机的内部时钟设置比实际日期/时间差几乎两年,这颠倒了我的库中照片和视频的排序时间线。我很快发现了exiftooldate/time shift feature的精彩批量更新功能。然而不幸的是它还不支持的MP4视频文件的修改:如何在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视频文件执行类似批次日期移功能可以自由使用实用工具?

回答

1

基础上QuickTime File Format Specification我放在一起的时间戳的原油转移证明了概念的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') 
相关问题