Я хочу использовать API субтитров. Для этого требуется хэш md5 первых и последних 64 КБ видеофайла. Я знаю, как сделать часть md5, просто хочу знать, как мне получить 128 КБ данных.

Вот решение проблемы на Java, которое я не могу реализовать в Delphi. Как читать первым и последним 64кб видеофайла на Java?

Мой код Delphi до сих пор:

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;

Я не получаю точный хэш md5, как указано в официальном API. URL-адрес API здесь. Я использую Delphi XE8.

4
Rabi Jayasawal 14 Май 2015 в 00:04
Вы бы обнаружили ошибку, если бы проверили возвращаемое значение Read или использовали ReadBuffer
 – 
David Heffernan
14 Май 2015 в 08:25

1 ответ

Лучший ответ

hash function, используемый этим API, описывается следующим образом:

Наш хэш состоит из первых и последних 64 КБ видеофайла, объединения всех вместе и генерации md5 результирующих данных (128 КБ).

Я вижу несколько проблем в вашем коде. Вы хешируете файловый поток, а не массив Buffer. За исключением того, что вы перезаписывали этот массив путем последующего чтения из файлового потока. И вы пытались искать только 64 байта и за пределами конца потока (вам нужно использовать отрицательное значение для поиска с конца потока). Попробуйте вместо этого что-нибудь вроде этого:

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;
7
TLama 14 Май 2015 в 11:58
Большое спасибо за ваше терпение. Работает как положено. Моя плохая, как студентка.
 – 
Rabi Jayasawal
14 Май 2015 в 00:49
Разве нет необходимости проверять, что входной поток имеет длину не менее 128 КБ?
 – 
David Heffernan
14 Май 2015 в 11:05
@David, добавлена ​​минимальная проверка, чтобы избежать ошибки чтения потока из-за меньшего размера файла (64 КБ).
 – 
TLama
14 Май 2015 в 12:01