我很好奇是否有人可以对我目前遇到的问题提供一些见解。
先说一下背景,我和妻子各有一部 Android 手机(Moto G5 Plus)。手机通过 SFTP 将 DCIM 文件夹中的所有项目同步到我的 Ubuntu 服务器。这些项目存储在“unsorted_pictures”目录中。每晚运行一次 cron 作业,执行一个脚本,该脚本会自动将内容从 unsorted_pictures 复制到 pictures/year/month。稍后(在手机空间达到最大容量后),我将清除 unsorted_pictures 目录作为维护步骤。
无论其价值如何,脚本如下:
#!/bin/bash
exiftool -overwrite_original_in_place -P -if 'not $CreateDate' '-CreateDate<FileModifyDate' -r /mnt/vault/unsorted_pictures/staging
exiftool -o . '-Directory<CreateDate' -d /mnt/vault/pictures/%Y/%m -r /mnt/vault/unsorted_pictures/staging
exit
因此,基本上,第一行 exiftool 检查 CreateDate 是否存在。如果不存在,则使用 FileModifyDate 创建 CreateDate 参数。这实际上仅适用于通过 Hangouts 对话保存的图片,因为 Google 似乎会删除 exif 数据。(?!) 之后,第二行 exiftool 执行复制和排序。
这个过程真是太棒了,我对此非常满意。不过有一个小问题——视频文件似乎是以 UTC 时间录制的,而图片似乎是以当地时间录制的。下面是一个拍摄的视频文件,它立即传输到我的服务器,然后对它运行 exiftool 来检查所有的时间戳。
administrator@vault:/mnt/vault/unsorted_pictures$ exiftool -time:all -s VID_20171225_214456599.mp4
FileModifyDate : 2017:12:25 21:47:02-05:00
FileAccessDate : 2017:12:25 21:47:00-05:00
FileInodeChangeDate : 2017:12:25 21:47:02-05:00
CreateDate : 2017:12:26 02:45:00
ModifyDate : 2017:12:26 02:45:00
TrackCreateDate : 2017:12:26 02:45:00
TrackModifyDate : 2017:12:26 02:45:00
MediaCreateDate : 2017:12:26 02:45:00
MediaModifyDate : 2017:12:26 02:45:00
administrator@vault:/mnt/vault/unsorted_pictures$ date
Mon Dec 25 21:47:23 EST 2017
如您所见,CreateDate 似乎设置为未来时间。下面我运行了“date”命令,以便您可以看到发生此操作时的当前本地时间。在上面几行中,您可以看到以 05:00 结尾的时间戳,据我了解,这是与 UTC 的时间差。
关于我的实际问题:
1) 我尝试了摩托罗拉手机上的多个相机应用程序,但所有应用程序都产生了完全相同的行为。这表明这不是应用程序特定的设置。有没有办法阻止我的视频以 UTC 格式录制?照片很好,但只是视频。我觉得这有点奇怪,但网上搜索表明这很常见,但我还没有听说并理解为什么。
2) 我确信我可以在我的脚本中添加一些逻辑,只需通过 CreateDate 对图片进行排序,通过 FileModifyDate 对视频文件类型进行排序,甚至可以添加一些额外的参数,系统地将所有视频重新日期回溯 5 小时。但我想知道,有没有办法让 exiftool 查看 mp4 文件并确认 UTC 时间差异?我知道视频文件是另一回事,exiftool 主要关注图片,但即便如此,鉴于 exiftool 在确认这些视频的元数据方面做得如此出色,这让我想到可能有一种方法可以对其进行调整以查看非 UTC 时间。或者,如果手机以 UTC 时间录制,也许就没有希望了。/耸耸肩
也许这更能说明按年/月而不是按年/月/日排序的原因,因为我甚至不会注意到视频被移动了 5 个小时,因为它们都位于该月的目录中。但我仍然对此很感兴趣,想知道...为什么?
任何帮助或见解都将不胜感激!
答案1
根据 Phil Harvey(exiftool 的创建者)的说法,Quicktime 时间戳应该按照标准设置为 UTC 时间。但似乎很多相机都没有这样做,所以 exiftool 不假设时区并接受书面时间。请参阅Quicktime 标签下的第四段
Exiftool 包含一个选项来纠正这个问题。如果您运行的是 exiftool 9.40 或更高版本,您可以将其添加-api QuickTimeUTC
到命令中,它将假定时间戳正确地写为 UTC 并将其转换为本地时间。
答案2
我建议您创建一个新的“CreateDateLocal”标签,其中将创建时间存储为本地时间。
您可以通过 config.xml 来实现。在 中'Image::ExifTool::XMP::xmp'
添加:
CreateDateLocal => { Groups => { 2 => 'Time' }, Shift => 'Time' }, # Stores the create date in local time (for videos)
插入后可能看起来像这样:
# XMP tags may be added to existing namespaces:
'Image::ExifTool::XMP::xmp' => {
# Example 5. XMP-xmp:NewXMPxmpTag
NewXMPxmpTag => { Groups => { 2 => 'Author' } },
# add more user-defined XMP-xmp tags here...
CreateDateLocal => { Groups => { 2 => 'Time' } }, # Stores the create date in local time (for videos)
},
对于带有 UTC 的视频,运行以下命令:
exiftool -r -ext mp4 -api QuickTimeUTC "-CreateDateLocal<CreateDate" .
对于当地时间的视频,请运行以下命令:
exiftool -r -ext mp4 "-CreateDateLocal<CreateDate" .
您还可以在图像上运行它,然后只需使用“CreateDateLocal”而不是“CreateDate”进行组织即可。简单解决方案结束
更高级的解决方案:
您可以创建一个新的复合标签,当 CreateDateLocal 缺失时,该标签将返回到 CreateDate。有了这个,您只需要使用 UTC 时间戳标记视频(也就是说:它将节省您标记所有图像的时间,也将节省您标记带有本地时间戳的视频的时间)。
方法如下:
"'Image::ExifTool::Composite'"
在配置中搜索。在 {} 内插入以下内容:
# TheDateTaken is best attempt to get the date the photo was taken - preferrably in local time
# First the custom tag "CreateDateLocal" is checked. This is expected to be set manually on all videos.
# - For videos with UTC, run this: `exiftool -ext mp4 -api QuickTimeUTC "-CreateDateLocal<CreateDate" .`
# - For videos in local time, run this: `exiftool -ext mp4 "-CreateDateLocal<CreateDate" .`
# If CreateDateLocal isn't set, we asume it is an image. Images are always set in local time.
# There are multiple tags used for storing creation time. We check them all (listed in Desire)
CreateDateLocalWithFallback => {
Desire => {
0 => 'CreateDateLocal',
1 => 'DateTimeOriginal',
2 => 'CreationDate',
3 => 'CreateDate',
},
Groups => { 2 => 'Time' },
ValueConv => sub {
$val = shift;
# Loop through dates
foreach $date (@$val) {
next if not defined $date;
return $date if ($date =~ /^[12]\d\d\d/); # if it doesn't start with four digits, skip, as it is not a valid date
}
return undef;
},
Shift => 'Time',
Validate => 'ValidateExifDate($val)',
PrintConv => '$self->ConvertDateTime($val)',
},
通过解析文件名中的日期来扩展解决方案
三星将创建日期存储在文件名中。它可以用作后备。此复合标签可以提取日期(要在 CreateDateLocalWithFallback 中使用它,只需将“DateFromFilename”添加到“Desire”数组中)
DateFromFilename => {
Desire => {
0 => 'OriginalFileName',
1 => 'FileName',
},
Groups => { 2 => 'Time' },
ValueConv => sub {
$val = shift;
foreach $filename (@$val) {
# See if filename resembles date (it does on Samsung)
# Samsung naming: "20150827_165859.jpg"
if ($filename =~ /^\d{8}_\d{6}/) {
$year = substr($filename, 0, 4);
$month = substr($filename, 4, 2);
$day = substr($filename, 6, 2);
$hour = substr($filename, 9, 2);
$minute = substr($filename, 11, 2);
$second = substr($filename, 13, 2);
$y = int($year);
$mo = int($month);
$d = int($day);
$h = int($hour);
$mi = int($minute);
$s = int($second);
#return '2015:08:27 16:58:59';
#return @$val[0];
if (
(($y > 1900) && ($y < 2400)) &&
(($mo >= 1) && ($mo <= 12)) &&
(($d >= 1) && ($d <= 31)) &&
(($h >= 0) && ($h <= 24)) &&
(($mi >= 0) && ($mi <= 60)) &&
(($s >= 0) && ($s <= 60))
) {
# '2015:08:27 16:58:59';
return $year . ':' . $month . ':' . $day . ' ' . $hour . ':' . $minute . ':' . $second;
}
}
}
return undef;
},
Shift => 'Time',
Validate => 'ValidateExifDate($val)',
PrintConv => '$self->ConvertDateTime($val)',
#PrintConvInv => '$self->InverseDateTime($val,0)',
},