首页 > 解决方案 > 从 avi 文件中提取正确的创建日期

问题描述

我正在使用 Delphi 10 和 Windows 10 Home Edition 64 位。我有一个名为 MVI_0640.AVI 的视频文件。文件资源管理器中显示的日期是 15/04/04,对应于“属性”窗口中的媒体创建日期。

我正在使用以下代码来提取日期。

procedure TForm1.Button1Click(Sender: TObject);
var
  ADate: TDateTime;
  FlHandle: integer;
  MyData: TWin32FindData;
  FlTime: TFileTime;
  MySysTime: TSystemTime;
begin
  {get date using GetCreationTime}
  ADate := TFile.GetCreationTime(FlName);
  Memo1.Lines.Add('GetCreationTime ' + DateToStr(ADate));

  {get date using FileGetDate}
  FlHandle := FileOpen(FlName,fmOpenRead);
  ADate := FileDateToDateTime(FileGetDate(FlHandle));
  FileClose(FlHandle);
  Memo1.Lines.Add('FileGetDate ' + DateToStr(ADate));

  {get date using FindFirstFile}
  FindFirstFile(PChar(FlName), MyData);

  FlTime := MyData.ftCreationTime;
  FileTimeToSystemTime(FlTime, MySysTime);
  ADate := SystemTimeToDateTime(MySysTime);
  Memo1.Lines.Add('ftCreationTime ' + DateToStr(ADate));

  FlTime := MyData.ftLastAccessTime;
  FileTimeToSystemTime(FlTime, MySysTime);
  ADate := SystemTimeToDateTime(MySysTime);
  Memo1.Lines.Add('ftLastAccessTime ' + DateToStr(ADate));

  FlTime := MyData.ftLastWriteTime;
  FileTimeToSystemTime(FlTime, MySysTime);
  ADate := SystemTimeToDateTime(MySysTime);
  Memo1.Lines.Add('ftLastWriteTime ' + DateToStr(ADate));

end;

结果如下所示:

没有任何日期反映媒体创建日期。我怎样才能提取它?

为了回答 Tom Brunberg 的评论,我附上了使用十六进制编辑器获取的文件的摘录。 在此处输入图像描述

标签: filedatedelphiextractavi

解决方案


您要查找的日期位于名为IDIT. 例如,在本文档中提及

结构很简单,(我的文件中的示例数据):

chunk id:     IDIT  // 4 ASCII chars
chunk length: 0000001A // 26 bytes
chunk data:   Sun Aug 31 12:15:22 2008/n/0 // date as ascii string

Microsoft 概述AVI了文件的结构,如下所示,并添加了 IDIT 块的位置(如果存在)

RIFF ('AVI '
      LIST ('hdrl'
            'avih'(<Main AVI Header>)
            LIST ('strl'
                  'strh'(<Stream header>)
                  'strf'(<Stream format>)
                  [ 'strd'(<Additional header data>) ]
                  [ 'strn'(<Stream name>) ]
                  ...
                 )
             ... (note, if present, the IDIT chunk appears here)
           )
      LIST ('movi'
            {SubChunk | LIST ('rec '
                              SubChunk1
                              SubChunk2
                              ...
                             )
               ...
            }
            ...
           )
      ['idx1' (<AVI Index>) ]
     )

上述文件还概述了各种结构。

样本数据: 在此处输入图像描述

获取日期(如果文件中存在)的函数可能如下所示:

// Note! finetuned to search only the main TLIST 'hdrl' 
function GetOriginalDate(AviFileName: TFileName; out s: string): boolean;
type
  TChunkId = array[0..3] of AnsiChar;

  TChunk = record
    chid: TChunkId;
    size: cardinal;
    form: TChunkId;
  end;
var
  fs: TFileStream;
  Root: TChunk;
  Chnk: TChunk;
  Done: boolean;
  Date: ansistring;
  endpos: integer;
begin
  s := 'not found';
  Done := False;
  result := False;

  fs:= TFileStream.Create(AviFileName, fmOpenRead or fmShareDenyWrite);

  try
    fs.Read(Root, SizeOf(Root));
    if Root.chid <> 'RIFF' then exit;
    if Root.form <> 'AVI ' then exit;

    fs.Read(Chnk, SizeOf(TChunk)); // main LIST
    if Chnk.chid <> 'LIST' then exit;
    if Chnk.form <> 'hdrl' then exit;

    endpos := fs.Position + Chnk.size;
    repeat
      fs.Read(Chnk, SizeOf(TChunk));
      if Chnk.chid = 'IDIT' then
      begin
        fs.Seek(-4, TSeekOrigin.soCurrent);
        SetLength(Date, Chnk.size);
        fs.Read(Date[1], Length(Date));
        s := Date;
        Done := True;
      end
      else
        fs.Seek(Chnk.size-4, TSeekOrigin.soCurrent);
    until Done or (fs.Position > endpos);

  finally
    fs.Free;
  end;
end;

调用它,例如:

procedure TForm1.Button2Click(Sender: TObject);
var
  s: string;
begin
  GetOriginalDate('F:\My Video\2008-08-31\MVI_1279.AVI', s);
  Memo1.Lines.Add(s);
end;

结果是Memo1

Sun Aug 31 12:15:22 2008

推荐阅读