Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: smok1Ответов: 2

Я использую модуль 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 ответил на этот вопрос.

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

metadatadelphiwinapimultimediaavi

Ответы

Ответ 1 · рейтинг 3 · mghie

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

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

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

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

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

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

Ответ 2 · рейтинг 1 · Ken White

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

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

lFile := nil;

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы