Ошибка при получении продолжительности файла AVI

Я использую модуль VFW из оболочки JEDI на WinAPI.

Код, который я пишу, предназначен для поиска пользовательских дисков и обнаружения вареза. Мы делаем поиск MP3, WMA и некоторых графических файлов. Теперь мы хотим обнаружить нелегальные фильмы. Я хочу открыть файл AVI, прочитать некоторые детали из него и закрыть его. У меня есть следующий код:

uses WFV; //from JEDI api wrappers

procedure TForm1.Button1Click(Sender: TObject);
var
  lInfo : TAVIFILEINFO      lFile : IAVIFILE;
  lFileType : string;
  lLenMinutes : integer;
  lFPS : integer;
begin
  {init file}
  AVIFileInit;
  {Open file - note: since we search for warez this is perfely "warezy" file}
  AVIFileOpen(lFile, 'e:\Sideways KLAXXON\Sideways KLAXXON.avi', OF_READ, nil);
  {Get file info}
  AVIFileInfoW(lFile, lInfo, sizeof(lInfo));
  lFPS:=Round(lInfo.dwRate /lInfo.dwScale);
  lLenMinutes := Round(lInfo.dwLength  / lFPS / 60);
  lFileType := lInfo.szFileType;
  {just for show: prepare some memo to see what we get}
  memo1.Lines.Clear;

  memo1.Lines.Add('File lenght [min]: ' + IntToStr(lLenMinutes));
  memo1.Lines.Add('Width: ' + IntToStr(lInfo.dwWidth));
  memo1.Lines.Add('Height: ' + IntToStr(lInfo.dwHeight));
  memo1.Lines.Add('File type: ' + lFileType);

  {Closing the file}
  AVIFileRelease (lFile);
  {and here goes the crash}
  FreeAndNil(lFile);

end;

Есть две проблемы:

  1. lLenMinutes — это что-то равное 98, в то время как фильм длится около двух часов. dwRate — 1 миллион, а dwScale — 40 тыс., поэтому FPS идеально равен 25. MSDN говорит: "Единицы определяются dwRate и dwScale".
  2. Код падает на строке FreeAndNil. Почему? Я предполагаю, что я несу ответственность за освобождение lFile (и, по крайней мере, я чувствую, что должен освободить файл). Без строки с FreeAndNil у меня есть нарушение прав доступа при выходе из процедуры.

Итак, вы знаете, как правильно получить продолжительность фильма из файла AVI? А почему крах?

Изменить

Фильм длится 2 часа одна минута, поэтому результат должен быть действительно близок к 120. Файл lFile объявлен в Jedi как:

IAVIFile = interface(IUnknown)

AVIFileOpen объявляется в JEDI как:

функция AVIFileOpen (var ppfile: IAVIFILE; szFile: LPCWSTR; uMode: UINT; lpHandler: PCLSID): HResult; стандартный вызов; внешнее имя AVIFIDLL 'AVIFileOpenW';

и в MSDN:

STDAPI AVIFileOpen( PAVIFILE *ppfile, LPCTSTR szFile, режим UINT, CLSID pclsidHandler );

MSDN говорит:

«Функция AVIFileOpen открывает файл AVI и возвращает адрес файлового интерфейса, используемого для доступа к нему».

поэтому я предполагаю, что объект создается этой функцией.

Изменить 2

Длина файла avi была перемещена в новый вопрос, так как mghie ответил на этот вопрос.


person smok1    schedule 19.11.2009    source источник
comment
Нелегальные фильмы? Что, если пользователь скопировал его со своего собственного DVD?   -  person Anders    schedule 19.11.2009
comment
@Anders: Это сильно зависит от правовой системы, но в большинстве стран наличие частного мультимедийного контента на рабочем компьютере не является законным или, по крайней мере, запрещено трудовым договором (никто не использует наше программное обеспечение на частных компьютерах).   -  person smok1    schedule 19.11.2009


Ответы (2)


Функции парные, AVIFileOpen() и AVIFileRelease() принадлежат друг другу. До вызова AVIFileOpen() переменная lFile имеет значение nil, после чего (если все прошло хорошо) содержит указатель на интерфейс. Он имеет счетчик ссылок 1. После вызова AVIFileRelease() переменная должна снова содержать nil, но это не так. Теперь, когда ваш метод выходит из предоставленного компилятором кода для освобождения указателей интерфейса, он попытается уменьшить счетчик ссылок уже выпущенного интерфейса.

У вас есть два основных способа исправить это:

  • Увеличьте счетчик ссылок указателя интерфейса после AVIFileOpen().

  • Сбросьте переменную, не пытаясь уменьшить счетчик ссылок. Используйте приведение типа к указателю:

    указатель(lFile) := ноль;

Кроме того, добавьте вызов AVIFileExit(), чтобы он соответствовал вашему вызову AVIFileInit().

person mghie    schedule 19.11.2009

98 минут это час и 38 минут. Что такое "около двух часов"?

Что касается сбоя FreeAndNil(), он предназначен для освобождения потомка TObject и установки переменной, содержащей его, в nil. Где вы создаете потомка TObject в своем коде? Похоже, что lFile — это интерфейс, поэтому простой установки переменной в nil должно быть достаточно, чтобы уменьшить счетчик ссылок:

lFile := nil;

Вызов Free внутри FreeAndNil(), вероятно, является причиной сбоя.

РЕДАКТИРОВАТЬ: Основываясь на изменениях исходного вопроса, очевидно, что вышеизложенное неверно. Однако я подозреваю, что вызов AVIFileRelease() уже освободил интерфейс, и поэтому вам больше нечего делать. lFile в любом случае выходит за рамки, и счетчик ссылок будет автоматически уменьшаться.

Что касается цитаты MSDN на AVIFileOpen(), обратите внимание, что в ней говорится, что она «возвращает адрес файлового интерфейса». Это COM-интерфейс, который никоим образом не является потомком Delphi TObject. Фрагмент из кода JEDI также говорит об этом, поскольку он говорит, что IAviFile является interface(IUnknown)

person Ken White    schedule 19.11.2009
comment
IMDB сообщает, что Sideways длится 126 минут. - person Rob Kennedy; 19.11.2009
comment
Фильм длится 2 часа и 1 минуту... Кстати: установка lFile на ноль также приводит к сбою кода... - person smok1; 19.11.2009
comment
@Роб: Спасибо. Впрочем, плевать, что говорит IMDB. Если OP говорит, что продолжительность фильма возвращается неправильно, OP также должен указать, каким должно быть правильное значение. Я не должен исследовать файл, выяснять, где взять информацию, и сам находить эту информацию. (Это, конечно, при условии, что IMDB находится где-то, откуда я публикую сообщения.) - person Ken White; 19.11.2009
comment
Хорошо, но когда я удаляю весь niling, FreeAndNil и т. д., я получаю нарушение прав доступа просто тогда, когда lFile выходит за рамки... - person smok1; 19.11.2009
comment
Думаю, он нашел причину и решение. Я только что проголосовал за его ответ. - person Ken White; 19.11.2009
comment
Кен, я бы не ожидал, что ты будешь это искать. Впрочем, я посмотрел и сказал вам. Учитывая выбор между 1:38 и 2:06 для значения примерно двух часов, я думаю, вы согласитесь, что последний вариант является лучшим выбором, поэтому я просто пытался сказать, что 98-минутный результат, который получил Смок, действительно был неправильное значение. (Лично я бы никогда не назвал 1:38 примерно двумя часами. Это явно около полутора часов.) - person Rob Kennedy; 20.11.2009
comment
@Роб: я согласен на 100%. Лично я бы никогда не сказал о двух часах на 1:38. Однако я не опубликовал исходный вопрос. ‹g› Я указывал, что, хотя было приятно, что вы разместили информацию с IMDB, ОП должен был ее предоставить. (Я действительно не смотрел на имя файла, потому что мне было все равно, что это за файл. Я также не уверен, что узнал бы это как фильм «На обочине», даже если это имя файла.) - person Ken White; 20.11.2009
comment
@Rob, @Ken - я попытался написать это более осмысленно по второму вопросу, так как проблема нарушения прав доступа была решена mghie. А насчет имени файла - да, оно Боком. У нас есть некоторые возражения против загрузки нелегальных фильмов (чтобы иметь больше испытуемых), потому что наличие вареза на рабочем месте вызывает проблемы (хотя наше программное обеспечение предназначено для обнаружения вареза...). Таким образом, наши испытуемые ограничены. - person smok1; 21.11.2009