2012-04-02 5 views
4

У меня есть много файлов MPEG-4, транскодированных из различных форматов цифровых камер, для которых дата изменения файловой системы верна. Я бы хотел установить тег «Media Created» для соответствия. Это можно сделать вручную в проводнике Windows на вкладке «Сведения» окна «Свойства». Настройка Media Created полезна, потому что Windows Live Photo Gallery отключает это поле для свойства Date Taken. К сожалению, количество файлов делает установку всех своих дат вручную непрактичной.Как установить дату «Media created» в файле MPEG-4

У пары возможностей автоматизации есть потенциал. TagLib#, похоже, поддерживает все теги MP4, но API для получения более основных тегов неясен. Другим углом является оболочка Windows. Предположительно, Windows Explorer использует его для написания тегов. В оболочке есть example for reading, но API для написания не существует.

ответ

3

Используйте Windows Property System. Для начала ознакомьтесь с инструкцией Property Edit Sample. Установите следующие свойства:

  • System.DateImported
  • System.Media.DateEncoded
  • System.ItemDate
1

Я решил эту проблему путем написания чтения/записи формат файла MP4 напрямую. Вот код в VB:

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 
4

Я имел успех с exiftool. Вот команды, которые я использовал для исправления одного файла. Однако exiftool может использоваться для исправления метаданных пакетами.

C:\>exiftool.exe -s test.mp4 

ExifToolVersion     : 10.01 
FileName      : test.mp4 
Directory      : . 
FileSize      : 14 MB 
FileModifyDate     : 2015:09:04 22:33:16+05:00 
FileAccessDate     : 2015:09:05 14:10:08+05:00 
FileCreateDate     : 2015:09:05 14:10:08+05:00 
FilePermissions     : rw-rw-rw- 
FileType      : MP4 
FileTypeExtension    : mp4 
MIMEType      : video/mp4 
MajorBrand      : MP4 Base Media v1 [IS0 14496-12:2003] 
MinorVersion     : 0.2.0 
CompatibleBrands    : isom, iso2, avc1, mp41 
MovieHeaderVersion    : 0 
CreateDate      : 0000:00:00 00:00:00 
ModifyDate      : 0000:00:00 00:00:00 
TimeScale      : 1000 
Duration      : 0:01:22 
-- snip -- 
TrackHeaderVersion    : 0 
TrackCreateDate     : 0000:00:00 00:00:00 
TrackModifyDate     : 0000:00:00 00:00:00 
-- snip -- 
MediaHeaderVersion    : 0 
MediaCreateDate     : 0000:00:00 00:00:00 
MediaModifyDate     : 0000:00:00 00:00:00 
-- snip -- 

C:\>exiftool.exe^
-Quicktime:CreateDate="2007-01-02 03:04:05"^
-Quicktime:ModifyDate="2007-01-02 03:04:05"^
    -TrackCreateDate="2007-01-02 03:04:05"^
    -TrackModifyDate="2007-01-02 03:04:05"^
    -MediaCreateDate="2007-01-02 03:04:05"^
    -MediaModifyDate="2007-01-02 03:04:05"^
test.mp4 

C:\>exiftool.exe -s test.mp4 

FileModifyDate     : 2015:09:05 14:20:54+05:00 
FileAccessDate     : 2015:09:05 14:20:54+05:00 
FileCreateDate     : 2015:09:05 14:10:08+05:00 
-- snip -- 
CreateDate      : 2007:01:02 03:04:05 
ModifyDate      : 2007:01:02 03:04:05 
-- snip -- 
TrackCreateDate     : 2007:01:02 03:04:05 
TrackModifyDate     : 2007:01:02 03:04:05 
-- snip -- 
MediaCreateDate     : 2007:01:02 03:04:05 
MediaModifyDate     : 2007:01:02 03:04:05 
-- snip --