1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
System.DateUtils,
Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Déclarations privées }
function MP4Duration(const AFileName: string): string;
public
{ Déclarations publiques }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function LSwap(C: Cardinal): Cardinal;
begin
Result := Swap(C) shl 16 + Swap(C shr 16);
end;
function LLSwap(L: UInt64): UInt64;
begin
Result := LSwap(L) shl 32 + LSwap(L shr 32);
end;
function GetMP4Duration(const AFileName: string; var Duration: Int64): Boolean;
type
TMP4Chunk = packed record
Size: Cardinal;
Tag : array[0..3] of AnsiChar;
end;
TMP4Mvhd = packed record
Ver: Byte;
Flags: array[0..2] of Byte;
case Boolean of
True: (
Creation1, Modified1: UInt64;
Timescale1: Cardinal;
Duration1: UInt64;
);
False: (
Creation2, Modified2: Cardinal;
Timescale2: Cardinal;
Duration2: Cardinal;
);
end;
var
S: TFileStream;
H: TMP4Chunk;
M: TMP4Mvhd;
begin
Result := False;
S := TfileStream.Create(AFileName, fmOpenRead or fmShareDenyNone);
try
S.ReadBuffer(H, SizeOf(H)); // lecture d'un entête MP4
if H.Tag <> 'ftyp' then // vérification du type
Exit(False);
repeat
H.Size := LSwap(H.Size);
S.Seek(H.Size - SizeOf(H), TSeekOrigin.soCurrent); // sauter la section
S.ReadBuffer(H, SizeOf(H)); // lire la suivante
until H.Tag = 'moov'; // jusqu'au "moov"
S.ReadBuffer(H, SizeOf(H)); // lire dans "moov"
while H.Tag <> 'mvhd' do // jusque "mvhd"
begin
H.Size := LSwap(H.Size);
S.Seek(H.Size - SizeOf(H), TSeekOrigin.soCurrent);
S.ReadBuffer(H, SizeOf(H));
end;
S.ReadBuffer(M, SizeOf(M)); // lire son contenu
if M.Ver = 1 then // en fonction de la version
begin
M.Duration2 := LLSwap(M.Duration2); // non testé !
M.Timescale1 := LSwap(M.Timescale1);
Duration := M.Duration1 div M.Timescale1;
end else begin
M.Duration2 := LSwap(M.Duration2);
M.Timescale2 := LSwap(M.Timescale2);
Duration := M.Duration2 div M.Timescale2; // calculé la durée en secondes
end;
Result := True;
finally
S.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Str: string;
begin
if PromptForFileName(Str, '*.mp4') then
Label1.Caption := MP4Duration(Str);
end;
function TForm1.MP4Duration(const AFileName: string): string;
var
Duration: Int64;
H,M,S : Word;
Date : TDateTime;
begin
if GetMP4Duration(AFileName, Duration) then
begin
M := Duration div 60;
S := Duration - 60 * M;
H := M div 60;
Dec(M, H * 60);
Date := Encodetime(H, M, S, 0); // durée en Time
Result := TimeToStr(Date); // pour faciliter le formatage
end else begin
Result := 'Unknown';
end;
end;
end. |