Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read first and last 64kb of a video file in Delphi?

I want to use a subtitle API. It requires a md5 hash of first and last 64kb of the video file. I know how to do the md5 part just want to know how will I achieve to get the 128kb of data.

Here is the solution to the problem in Java which I am unable to implement in Delphi. How to read first and last 64kb of a video file in Java?

My Delphi code so far:

function TSubdbApi.GetHashFromFile(const AFilename: string): string;
var
  Md5: TIdHashMessageDigest5;
  Filestream: TFileStream;
  Buffer: TByteArray;
begin
  Md5 := TIdHashMessageDigest5.Create;
  Filestream := TFileStream.Create(AFilename, fmOpenRead, fmShareDenyWrite);
  try
    if Filestream.Size > 0 then begin
      Filestream.Read(Buffer, 1024 * 64);
      Filestream.Seek(64, soFromEnd);
      Filestream.Read(Buffer, 1024 * 64);
      Result := Md5.HashStreamAsHex(Filestream);
    end;
  finally
    Md5.Free;
    Filestream.Free;
  end;
end;

I am not getting the accurate md5 hash as stated by the official API.API url here. I am using Delphi XE8.

like image 444
Rabi Jayasawal Avatar asked Mar 16 '23 01:03

Rabi Jayasawal


1 Answers

The hash function used by that API is described as:

Our hash is composed by taking the first and the last 64kb of the video file, putting all together and generating a md5 of the resulting data (128kb).

I can see a few problems in your code. You are hashing the file stream, not your Buffer array. Except that you were overwriting that array by subsequent reading from the file stream. And you were trying to seek only 64 bytes, and beyond the end of the stream (you need to use a negative value to seek from the end of the stream). Try something like this instead:

type
  ESubDBException = class(Exception);

function TSubdbApi.GetHashFromFile(const AFileName: string): string;
const
  KiloByte = 1024;
  DataSize = 64 * KiloByte;
var
  Digest: TIdHashMessageDigest5;
  FileStream: TFileStream;
  HashStream: TMemoryStream;
begin
  FileStream := TFileStream.Create(AFileName, fmOpenRead, fmShareDenyWrite);
  try
    if FileStream.Size < DataSize then
      raise ESubDBException.Create('File is smaller than the minimum required for ' +
        'calculating API hash.');

    HashStream := TMemoryStream.Create;
    try
      HashStream.CopyFrom(FileStream, DataSize);
      FileStream.Seek(-DataSize, soEnd);
      HashStream.CopyFrom(FileStream, DataSize);

      Digest := TIdHashMessageDigest5.Create;
      try
        HashStream.Position := 0;
        Result := Digest.HashStreamAsHex(HashStream);
      finally
        Digest.Free;
      end;
    finally
      HashStream.Free;
    end;
  finally
    FileStream.Free;
  end;
end;
like image 136
TLama Avatar answered Mar 23 '23 08:03

TLama