Previously

继上次写了《如何导出正确的照片拍摄时间》这篇文章之后,下面有两个读者提了同一个问题:如何对视频拍摄时间进行修正?在那篇文章中我提到可以使用 jhead 命令修正照片的拍摄时间。但是jhead 的全称是 jpeg head,正如其名它是专门用于处理 jpeg 格式的图片信息,并不适用于其他格式,那么我们就需要另寻工具来解决这个问题。本文涉及到的命令可通过下面这条命令一键安装:

brew install mediainfo jq parallel coreutils

思路

既然我们要修正视频的拍摄时间,我们可以先假设正确的拍摄时间就藏在视频文件信息里面,只不过导出的时候拍摄时间变成了导出时间。那么我们第一步的任务就是把视频的所有信息都挖掘出来,看看是不是真的存在正确的拍摄时间。我从照片里面拖出一个拍摄于去年的视频,使用 mdls (metadata list) 命令查看元数据信息:

➜ mdls IMG_0713.mov
_kMDItemDisplayNameWithExtensions      = "IMG_0713.mov"
kMDItemAudioBitRate                    = 97
kMDItemAudioChannelCount               = 1
kMDItemCodecs                          = (
    AAC,
    "H.264",
    "Timed Metadata"
)
kMDItemContentCreationDate             = 2021-02-06 14:17:27 +0000
kMDItemContentCreationDate_Ranking     = 2021-02-06 00:00:00 +0000
kMDItemContentModificationDate         = 2021-02-06 14:17:54 +0000
kMDItemContentModificationDate_Ranking = 2021-02-06 00:00:00 +0000
kMDItemContentType                     = "com.apple.quicktime-movie"
kMDItemContentTypeTree                 = (
    "com.apple.quicktime-movie",
    "public.movie",
    "public.audiovisual-content",
    "public.data",
    "public.item",
    "public.content"
)
kMDItemDateAdded                       = 2021-02-06 14:17:54 +0000
kMDItemDateAdded_Ranking               = 2021-02-06 00:00:00 +0000
kMDItemDisplayName                     = "IMG_0713.mov"
kMDItemDocumentIdentifier              = 0
kMDItemDurationSeconds                 = 7.288333333333333
kMDItemEncodingApplications            = (
    "14.2"
)
kMDItemFSContentChangeDate             = 2021-02-06 14:17:54 +0000
kMDItemFSCreationDate                  = 2021-02-06 14:17:27 +0000
kMDItemFSCreatorCode                   = ""
kMDItemFSFinderFlags                   = 0
kMDItemFSHasCustomIcon                 = (null)
kMDItemFSInvisible                     = 0
kMDItemFSIsExtensionHidden             = 0
kMDItemFSIsStationery                  = (null)
kMDItemFSLabel                         = 0
kMDItemFSName                          = "IMG_0713.mov"
kMDItemFSNodeCount                     = (null)
kMDItemFSOwnerGroupID                  = 20
kMDItemFSOwnerUserID                   = 501
kMDItemFSSize                          = 35710907
kMDItemFSTypeCode                      = ""
kMDItemInterestingDate_Ranking         = 2021-02-06 00:00:00 +0000
kMDItemKind                            = "QuickTime影片"
kMDItemLastUsedDate                    = 2021-02-06 14:17:55 +0000
kMDItemLastUsedDate_Ranking            = 2021-02-06 00:00:00 +0000
kMDItemLogicalSize                     = 35710907
kMDItemMediaTypes                      = (
    Sound,
    Video,
    Metadata
)
kMDItemPhysicalSize                    = 36261888
kMDItemPixelHeight                     = 3840
kMDItemPixelWidth                      = 2160
kMDItemProfileName                     = "HD (1-1-1)"
kMDItemStreamable                      = 0
kMDItemTotalBitRate                    = 39185
kMDItemUseCount                        = 7
kMDItemUsedDates                       = (
    "2021-02-05 16:00:00 +0000"
)
kMDItemVideoBitRate                    = 39087

很遗憾的是,我们没有找到任何关于 2020 年的关键词,会不会是真实的拍摄时间信息隐藏在原数据里更深的地方?我在 Google 上搜索了一圈之后找到了 mediainfo 这样一个程序,或者也可以叫它命令。它可以列出媒体文件内相关的所有信息,我们使用它来查看一下去年拍摄的这条视频看看有什么发现:

➜ mediainfo IMG_0713.mov
General
Complete James Hopbourn                            : IMG_0713.mov
Format                                   : MPEG-4
Format profile                           : QuickTime
Codec ID                                 : qt   0000.00 (qt  )
File size                                : 34.1 MiB
Duration                                 : 7 s 288 ms
Overall bit rate mode                    : Variable
Overall bit rate                         : 39.2 Mb/s
Encoded date                             : UTC 2021-02-06 14:17:27
Tagged date                              : UTC 2021-02-06 14:17:53
Writing library                          : Apple QuickTime
com.apple.quicktime.location.accuracy.ho : 12.606383
com.apple.quicktime.make                 : Apple
com.apple.quicktime.model                : iPhone 11
com.apple.quicktime.software             : 14.2
com.apple.quicktime.creationdate         : 2020-11-11T09:14:02+0800
com.apple.photos.originating.signature   : ATFrhl5a6BHZz41K7+dRX0DyTt9h

Video
ID                                       : 2
Format                                   : AVC
Format/Info                              : Advanced Video Codec
Format profile                           : High@L5.2
Format settings                          : CABAC / 2 Ref Frames
Format settings, CABAC                   : Yes
Format settings, Reference frames        : 2 frames
Format settings, GOP                     : M=2, N=30
Codec ID                                 : avc1
Codec ID/Info                            : Advanced Video Coding
Duration                                 : 7 s 288 ms
Bit rate mode                            : Variable
Bit rate                                 : 39.1 Mb/s
Maximum bit rate                         : 768 kb/s
Width                                    : 2 160 pixels
Height                                   : 3 840 pixels
Display aspect ratio                     : 0.562
Frame rate mode                          : Variable
Frame rate                               : 59.940 (59940/1000) FPS
Minimum frame rate                       : 54.545 FPS
Maximum frame rate                       : 60.000 FPS
Color space                              : YUV
Chroma subsampling                       : 4:2:0
Bit depth                                : 8 bits
Scan type                                : Progressive
Bits/(Pixel*Frame)                       : 0.079
Stream size                              : 34.0 MiB (100%)
Title                                    : Core Media Video
Encoded date                             : UTC 2021-02-06 14:17:27
Tagged date                              : UTC 2021-02-06 14:17:53
Color range                              : Limited
Color primaries                          : BT.709
Transfer characteristics                 : BT.709
Matrix coefficients                      : BT.709
Codec configuration box                  : avcC

Audio
ID                                       : 1
Format                                   : AAC LC
Format/Info                              : Advanced Audio Codec Low Complexity
Codec ID                                 : mp4a-40-2
Duration                                 : 7 s 242 ms
Source duration                          : 7 s 268 ms
Bit rate mode                            : Variable
Bit rate                                 : 97.9 kb/s
Channel(s)                               : 1 channel
Channel layout                           : C
Sampling rate                            : 44.1 kHz
Frame rate                               : 43.066 FPS (1024 SPF)
Compression mode                         : Lossy
Stream size                              : 86.6 KiB (0%)
Source stream size                       : 86.8 KiB (0%)
Title                                    : Core Media Audio
Encoded date                             : UTC 2021-02-06 14:17:27
Tagged date                              : UTC 2021-02-06 14:17:53

Other #1
Type                                     : meta
Duration                                 : 7 s 287 ms

Other #2
Type                                     : meta
Duration                                 : 7 s 287 ms

大概扫过去看一眼,看到了 com.apple.quicktime.creationdate : 2020-11-11T09:14:02+0800 正如其名,com.apple.quicktime.creationdate 正是对应着我的照片应用里的拍摄时间,确定了它就是视频的真正拍摄时间而不是导出时间,我们的假设成立,至此第一步完成。顺便通过查阅 Apple Metadata 开发者文档也得知了创建时间确实是属于元数据的,只是 mdls 列出是一些基础数据,并不会把所有元信息都列出才导致了之前找不到真正的拍摄时间。

过滤拍摄时间

现在我们已经确认真正的拍摄时间就存在视频里面,接下来就是要过滤出这个正确时间了。用 awksed 这些老牌文本处理工具吗?不,先看看 mediainfo 这个命令自己能不能支持以指定格式输出,查看帮助信息:

➜ mediainfo --help
MediaInfo Command line,
MediaInfoLib - v20.09

...
--Output=JSON
                    Full information Display using JSON
...

在输出信息里的我看到了 JSON 字样心中就吃下了一颗定心丸,因为我们有 jq 这样的工具可以很方便地处理 JSON ,具体分析过程不再赘述,直接看我如何使用 jq 来处理输出的 JSON 信息:

➜ mediainfo IMG_0713.mov --Output=JSON|jq -c '[.media .track[0].extra.com_apple_quicktime_creationdate]'|cut -d '"' -f 2
2020-11-11T09:14:02+0800

格式化拍摄时间

在 macOS 上可以通过 Setfile 命令修改任何文件的创建时间,但是有一个前提是必须按照 Setfile 命令指定的格式传入日期时间。我们在上一步过滤出了视频真正的拍摄时间,现在要使用 date 命令对这个时间进行格式化,例子和实例如下:

➜ echo '2020-11-11T09:14:02+0800'|xargs gdate +'%m/%d/%Y %H:%M:%S' -d
11/11/2020 09:14:02

➜ mediainfo IMG_0713.mov --Output=JSON|jq -c '[.media .track[0].extra.com_apple_quicktime_creationdate]'|cut -d '"' -f 2|xargs gdate +'%m/%d/%Y %H:%M:%S' -d
11/11/2020 09:14:02

修正拍摄时间

趁热打铁,最后一步使用 Setfile 命令修正视频拍摄时间,命令如下:

➜ mediainfo IMG_0713.mov --Output=JSON|jq -c '[.media .track[0].extra.com_apple_quicktime_creationdate]'|cut -d '"' -f 2|xargs gdate +'%m/%d/%Y %H:%M:%S' -d|parallel Setfile -d {} IMG_0713.mov

 

视频拍摄时间修正前后对比
视频拍摄时间修正前后对比

 

适用人群

因为一些原因需要知道精确的视频拍摄时间的用户,比如说我使用 SSD 来整理存储我的照片和视频,那么就有可能会有知道某个视频精确拍摄时间的需求。至于 vlog 博主,不知道有没有这个需求,可供参考。

技术总结

开头使用假说演绎法验证了正确的拍摄时间存储在视频内部,正是这一步的成功才能为后续修正时间打下基础。虽然使用 mdls 第一次没有获取到准确的拍摄时间,但是多努力了一下,在网上找到了 mediainfo 命令解决了这个最重要的问题。使用 JSON 格式输出给 jq 处理过滤出正确的拍摄时间传递给 date 命令将时间格式化。最后通过 parallel 将格式化处理之后的日期参数传递给 Setfile 修改为正确的时间,思路总体来说还是非常清楚的。
可改进之处:将这条命令封装成 Automator 快速操作添加到到右键选项就可以不用每次打开终端去执行这条命令了。
另一种思路:不要对视频的时间进行修改,获取正确的拍摄时间之后,将这个拍摄时间作为视频文件的前缀会更加直观。

参考文章

使用Setfile命令修改MacOS文件创建时间(creation date),非touch命令,附Linux文件时间属性介绍