首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何设置MPEG-4文件的“媒体创建”日期

如何设置MPEG-4文件的“媒体创建”日期
EN

Stack Overflow用户
提问于 2012-04-03 02:17:13
回答 4查看 16.8K关注 0票数 9

我有许多从各种数码相机格式转码的MPEG-4文件,文件系统修改日期是正确的。我想将“媒体创建”标签设置为匹配。这可以通过“属性”窗口的“详细信息”选项卡在Windows资源管理器中手动完成。设置创建的媒体非常有用,因为Windows Live照片库将此字段作为其Date Taken属性的关键字。不幸的是,文件的数量使得手工设置所有的日期不切实际。

有几种自动化的途径是有潜力的。TagLib#似乎支持所有的MP4标签,但除了基本标签之外,获得更多标签的应用程序接口还不清楚。另一个角度是Windows shell。据推测,Windows资源管理器正在使用它来编写标记。有一个通过外壳的example for reading,但似乎没有一个用于编写的API。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-04-06 16:22:43

使用Windows Property System。请参阅Property Edit Sample以开始使用。设置以下属性:

  • System.DateImported
  • System.Media.DateEncoded
  • System.ItemDate
票数 3
EN

Stack Overflow用户

发布于 2015-09-05 19:16:38

我已经成功地使用了exiftool。以下是列出媒体文件中所有标签并更新所选标签的命令(也可以对文件进行批处理):

代码语言:javascript
复制
C:\>exiftool.exe -short -groupNames test.mp4

[ExifTool]      ExifToolVersion                 : 10.61
[File]          FileName                        : test.mp4
[File]          Directory                       : .
[File]          FileSize                        : 91 MB
[File]          FileModifyDate                  : 2018:06:30 19:25:34+05:00
[File]          FileAccessDate                  : 2018:07:15 14:12:50+05:00
[File]          FileCreateDate                  : 2018:07:15 14:12:50+05:00
[File]          FilePermissions                 : rw-rw-rw-
[File]          FileType                        : MP4
[File]          FileTypeExtension               : mp4
[File]          MIMEType                        : video/mp4
[QuickTime]     MajorBrand                      : MP4 v2 [ISO 14496-14]
[QuickTime]     MinorVersion                    : 0.0.0
[QuickTime]     CompatibleBrands                : isom, mp42
[QuickTime]     MovieDataSize                   : 95484206
[QuickTime]     MovieDataOffset                 : 32
[QuickTime]     MovieHeaderVersion              : 0
[QuickTime]     CreateDate                      : 2018:06:30 14:25:34
[QuickTime]     ModifyDate                      : 2018:06:30 14:25:34
[QuickTime]     TimeScale                       : 1000
[QuickTime]     Duration                        : 0:01:02
-- snip --
[QuickTime]     TrackCreateDate                 : 2018:06:30 14:25:34
[QuickTime]     TrackModifyDate                 : 2018:06:30 14:25:34
-- snip --
[QuickTime]     MediaCreateDate                 : 2018:06:30 14:25:34
[QuickTime]     MediaModifyDate                 : 2018:06:30 14:25:34
-- snip --

C:\>exiftool.exe ^
-QuickTime:CreateDate="2018:07:15 13:15:00" ^
-QuickTime:ModifyDate="2018:07:15 13:15:00" ^
-QuickTime:TrackCreateDate="2018:07:15 13:15:00" ^
-QuickTime:TrackModifyDate="2018:07:15 13:15:00" ^
-QuickTime:MediaCreateDate="2018:07:15 13:15:00" ^
-QuickTime:MediaModifyDate="2018:07:15 13:15:00" ^
test.mp4


C:\>exiftool.exe -short -groupNames test.mp4

-- snip --
[File]          FileModifyDate                  : 2018:07:15 14:19:52+05:00
[File]          FileAccessDate                  : 2018:07:15 14:19:51+05:00
[File]          FileCreateDate                  : 2018:07:15 14:19:39+05:00
-- snip --
[QuickTime]     CreateDate                      : 2018:07:15 13:15:00
[QuickTime]     ModifyDate                      : 2018:07:15 13:15:00
-- snip --
[QuickTime]     TrackCreateDate                 : 2018:07:15 13:15:00
[QuickTime]     TrackModifyDate                 : 2018:07:15 13:15:00
-- snip --
[QuickTime]     MediaCreateDate                 : 2018:07:15 13:15:00
[QuickTime]     MediaModifyDate                 : 2018:07:15 13:15:00
-- snip --
票数 10
EN

Stack Overflow用户

发布于 2013-12-09 14:38:33

我通过直接写读/写MP4文件格式解决了这个问题。下面是VB中的代码:

代码语言:javascript
复制
Sub Main()
    ' Retrieve creation-time and modification-time, embedded inside the metadata of MP4 files
    Dim ft = Mp4Times("a.mp4")
    Console.WriteLine(ft.CreationTime)
    Console.WriteLine(ft.ModificationTime)

    ' Update those times
    Mp4Times("a.mp4", Date.Now, Date.Now)
End Sub

Class FileTimes
    Public CreationTime As Date
    Public ModificationTime As Date
End Class

Function Mp4Times(fn As String, Optional newCreationTime As Date? = Nothing, Optional newModificationTime As Date? = Nothing) As FileTimes
    Dim ft As FileTimes
    Using f = If(newCreationTime.HasValue OrElse newModificationTime.HasValue, IO.File.Open(fn, IO.FileMode.Open), IO.File.OpenRead(fn))
        f.Seek(0, IO.SeekOrigin.End) : Dim fend = f.Position

        ' The file is made up of a sequence of boxes, with a standard way to find size and FourCC "kind" of each.
        ' Some box kinds contain a kind-specific blob of binary data. Other box kinds contain a sequence
        ' of sub-boxes. You need to look up the specs for each kind to know whether it has a blob or sub-boxes.
        ' We look for a top-level box of kind "moov", which contains sub-boxes, and then we look for its sub-box
        ' of kind "mvhd", which contains a binary blob. This is where Creation/ModificationTime are stored.
        Dim pos = 0L, payloadStart = 0L, payloadEnd = 0L, boxKind = ""
        While ReadNextBoxInfo(f, pos, fend, boxKind, payloadStart, payloadEnd) AndAlso boxKind <> "moov"
            pos = payloadEnd
        End While
        If boxKind <> "moov" Then Return Nothing
        pos = payloadStart : fend = payloadEnd
        While ReadNextBoxInfo(f, pos, fend, boxKind, payloadStart, payloadEnd) AndAlso boxKind <> "mvhd"
            pos = payloadEnd
        End While
        If boxKind <> "mvhd" Then Return Nothing

        ' The "mvhd" binary blob consists of 1byte (version, either 0 or 1), 3bytes (flags),
        ' and then either 4bytes (creation), 4bytes (modification)
        ' or 8bytes (creation), 8bytes (modification)
        ' If version=0 then it's the former, otherwise it's the later.
        ' In both cases "creation" and "modification" are big-endian number of seconds since 1st Jan 1904 UTC
        f.Seek(pos + 8, IO.SeekOrigin.Begin) : Dim version = f.ReadByte()
        f.Seek(pos + 12, IO.SeekOrigin.Begin)
        Dim creationTime As Date, modificationTime As Date
        '
        If newCreationTime.HasValue Then
            creationTime = newCreationTime.Value
            If version = 0 Then Write4byteDate(f, creationTime) Else Write8byteDate(f, creationTime)
        Else
            creationTime = If(version = 0, ReadNext4byteDate(f), ReadNext8byteDate(f))
        End If
        '
        If newModificationTime.HasValue Then
            modificationTime = newModificationTime.Value
            If version = 0 Then Write4byteDate(f, modificationTime) Else Write8byteDate(f, modificationTime)
        Else
            modificationTime = If(version = 0, ReadNext4byteDate(f), ReadNext8byteDate(f))
        End If
        ft = New FileTimes With {.CreationTime = creationTime, .ModificationTime = modificationTime}
    End Using

    If newCreationTime.HasValue Then IO.File.SetCreationTime(fn, newCreationTime.Value)
    If newModificationTime.HasValue Then IO.File.SetLastWriteTime(fn, newModificationTime.Value)
    Return ft
End Function

Function ReadNextBoxInfo(f As IO.Stream, pos As Long, fend As Long, ByRef boxKind As String, ByRef payloadStart As Long, ByRef payloadEnd As Long) As Boolean
    boxKind = "" : payloadStart = 0 : payloadEnd = 0
    If pos + 8 > fend Then Return False
    Dim b(3) As Byte
    f.Seek(pos, IO.SeekOrigin.Begin)
    f.Read(b, 0, 4) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
    Dim size = BitConverter.ToUInt32(b, 0)
    f.Read(b, 0, 4)
    Dim kind = ChrW(b(0)) & ChrW(b(1)) & ChrW(b(2)) & ChrW(b(3))
    If size <> 1 Then
        If pos + size > fend Then Return False
        boxKind = kind : payloadStart = pos + 8 : payloadEnd = payloadStart + size - 8 : Return True
    End If
    If size = 1 AndAlso pos + 16 <= fend Then
        ReDim b(7)
        f.Read(b, 0, 8) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
        Dim size2 = CLng(BitConverter.ToUInt64(b, 0))
        If pos + size2 > fend Then Return False
        boxKind = kind : payloadStart = pos + 16 : payloadEnd = payloadStart + size2 - 16 : Return True
    End If
    Return False
End Function

ReadOnly TZERO As Date = New Date(1904, 1, 1, 0, 0, 0, DateTimeKind.Utc)

Function ReadNext4byteDate(f As IO.Stream) As Date
    Dim b(3) As Byte
    f.Read(b, 0, 4) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
    Dim secs = BitConverter.ToUInt32(b, 0)
    Return TZERO.AddSeconds(secs)
End Function

Function ReadNext8byteDate(f As IO.Stream) As Date
    Dim b(7) As Byte
    f.Read(b, 0, 8) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
    Dim secs = BitConverter.ToUInt64(b, 0)
    Return TZERO.AddSeconds(secs)
End Function

Sub Write4byteDate(f As IO.Stream, d As Date)
    Dim secs = CUInt((d - TZERO).TotalSeconds)
    Dim b = BitConverter.GetBytes(secs) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
    f.Write(b, 0, 4)
End Sub

Sub Write8byteDate(f As IO.Stream, d As Date)
    Dim secs = CULng((d - TZERO).TotalSeconds)
    Dim b = BitConverter.GetBytes(secs) : If BitConverter.IsLittleEndian Then Array.Reverse(b)
    f.Write(b, 0, 8)
End Sub
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9981599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档