从 avi 文件中提取正确的创建日期
Extract correct creation date from avi file
我正在使用 Delphi 10 和 Windows 10 家庭版 64 位。我有一个名为 MVI_0640.AVI 的视频文件。文件资源管理器中显示的日期是 15/04/04,对应于属性 window.
中的媒体创建日期
我正在使用以下代码提取日期。
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;
结果如下所示:
None 的日期反映了媒体创建日期。我怎样才能提取它?
为了回答 Tom Brunberg 的评论,我附上了用十六进制编辑器截取的文件的摘录。
您要查找的日期位于名为 IDIT
的数据块中。它被称为例如在 this document
结构简单,(来自我的文件的示例数据):
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
AVI
文件的结构是 outlined by Microsoft,如下所示,如果存在 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 Video08-08-31\MVI_1279.AVI', s);
Memo1.Lines.Add(s);
end;
并生成 Memo1
Sun Aug 31 12:15:22 2008
我找到了问题的答案。可能不是很优雅或节省,但它确实起作用了。我在 100 多个文件上对其进行了测试,并且没有问题。这是我的回答:
function TForm1.GetAviMediaCreationDate(AFile: string): TDateTime;
var
FS: TFileStream;
NumOfChar: integer;
i,d: integer;
ABuffer: array of byte;
AStr: string;
DateStr: string;
sdp: integer; //start date position
dn,mn,yn: integer; //used to encode date
begin
sdp := 0;
FS := TFileStream.Create(AFile,fmOpenRead);
NumOfChar := 400;
SetLength(ABuffer,NumOfChar);
FS.Read(Pointer(ABuffer)^, NumOfChar);
{find IDIT}
for i := 0 to NumOfChar-1 do
begin
AStr := Char(ABuffer[i]) +
Char(ABuffer[i+1]) +
Char(ABuffer[i+2]) +
Char(ABuffer[i+3]);
if AStr = 'IDIT' then sdp := i+7;
end;
{extract date}
for d := 1 to 24 do
DateStr := DateStr + Char(ABuffer[sdp+d]);
{assemble TDateTime}
//123456789 123456789 123456789
//Sun Jun 28 10:13:39 2015
dn := StrToInt(Copy(DateStr,9,2));
mn := IndexText(Copy(DateStr,5,3),ShortMonthNames)+1;
yn := StrToInt(Copy(DateStr,21,4));
Result := EncodeDate(yn, mn, dn);
FS.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
ADate: TDateTime;
begin
ADate := GetAviMediaCreationDate(FlName);
Memo1.Lines.Add(DateToStr(ADate));
end;
我正在使用 Delphi 10 和 Windows 10 家庭版 64 位。我有一个名为 MVI_0640.AVI 的视频文件。文件资源管理器中显示的日期是 15/04/04,对应于属性 window.
中的媒体创建日期我正在使用以下代码提取日期。
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;
结果如下所示:
None 的日期反映了媒体创建日期。我怎样才能提取它?
为了回答 Tom Brunberg 的评论,我附上了用十六进制编辑器截取的文件的摘录。
您要查找的日期位于名为 IDIT
的数据块中。它被称为例如在 this document
结构简单,(来自我的文件的示例数据):
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
AVI
文件的结构是 outlined by Microsoft,如下所示,如果存在 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 Video08-08-31\MVI_1279.AVI', s);
Memo1.Lines.Add(s);
end;
并生成 Memo1
Sun Aug 31 12:15:22 2008
我找到了问题的答案。可能不是很优雅或节省,但它确实起作用了。我在 100 多个文件上对其进行了测试,并且没有问题。这是我的回答:
function TForm1.GetAviMediaCreationDate(AFile: string): TDateTime;
var
FS: TFileStream;
NumOfChar: integer;
i,d: integer;
ABuffer: array of byte;
AStr: string;
DateStr: string;
sdp: integer; //start date position
dn,mn,yn: integer; //used to encode date
begin
sdp := 0;
FS := TFileStream.Create(AFile,fmOpenRead);
NumOfChar := 400;
SetLength(ABuffer,NumOfChar);
FS.Read(Pointer(ABuffer)^, NumOfChar);
{find IDIT}
for i := 0 to NumOfChar-1 do
begin
AStr := Char(ABuffer[i]) +
Char(ABuffer[i+1]) +
Char(ABuffer[i+2]) +
Char(ABuffer[i+3]);
if AStr = 'IDIT' then sdp := i+7;
end;
{extract date}
for d := 1 to 24 do
DateStr := DateStr + Char(ABuffer[sdp+d]);
{assemble TDateTime}
//123456789 123456789 123456789
//Sun Jun 28 10:13:39 2015
dn := StrToInt(Copy(DateStr,9,2));
mn := IndexText(Copy(DateStr,5,3),ShortMonthNames)+1;
yn := StrToInt(Copy(DateStr,21,4));
Result := EncodeDate(yn, mn, dn);
FS.Free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
ADate: TDateTime;
begin
ADate := GetAviMediaCreationDate(FlName);
Memo1.Lines.Add(DateToStr(ADate));
end;