главная продукты downloads форум тех. поддержка

 

Главная страница
 

  www.bousoft.com

   главная страница
   новости СМИ
   ссылки
   о проекте
   добавить в Избранное
   сделать стартовой
 

   наши разработки

   shareware
   freeware
   регистрация
 

справка и FAQ   

   статьи
   книги
   FAQ: WinForms
   FAQ: GDI+
   MS Office
   web-технологии
   wap-технологии
 

   программирование

   visual basic: ActiveX
   visual basic: примеры
   .net framework
   c++
   delphi
   rapidQ
 

   наши компакт-диски

   диск BouSoft #3
   диск Windows PE

Работа с файлами формата AVI.

Часть 4. Создание новых AVI-файлов из существующих потоков.

 

Код этого примера показывает как создать новый AVI-файл из существующих потоков. Он использует класс cFileDlg для того, чтобы пользователь мог выбрать существующий файл. Использование этого класса достаточно подробно было описано в первой части цикла, поэтому здесь останавливаться на этом не будем. Этот класс был включен только для того, чтобы максимально упростить код, в то же время сохранив полную свободу в выборе файла. После того, как имя файла принято от пользователя, программа получает указатель PAVIFILE, и затем находит указатель PAVISTREAM для видео потока в файле.

 

Затем я вновь использую класс cFileDlg для получения имени сохраняемого файла, так как мы будем создавать новый файл. Большинство необходимых параметров класса уже установлено, нам требуется добавить 3 строки:

 

ofd.DlgTitle = "Choose Location and Name to Save New AVI File"
ofd.DefaultExt = "avi"
szFileOut = "MyFile.avi"
'имя файла по умолчанию

 

 Теперь просто вызываем метод VBGetSaveFileName:

 

res = ofd.VBGetSaveFileName(szFileOut)

 

После этого у нас имеются имя исходного файла (существующего) и имя выходного файла (не существующего), и можно вызывать некоторые AVIFile-функции. Функции в этом примере достаточно сложны для вызова из Visual Basic. Все три функции AVISave требуют указатель на указатель на массив структур AVI_COMPRESS_OPTIONS. По-моему, единственный способ выполнить такой вызов - в объявлении функции указать ByRef AVI_COMPRESS_OPTIONS и затем использовать недокументированную функцию VarPtr(), чтобы получить указатель на эту структуру. Затем я передаю этот указатель в API-функцию и все вроде бы работает. Вероятно, нужно написать и откомпилировать библиотеку типов (TypeLibrary), но так как моей целью является написание наиболее простого и понятного кода, здесь я использую прямые вызовы функций.

 

Другая проблема с которой я столкнулся, оказалась более неприятной. Ведь функция AVISave объявлена в модуле Vfw.h с использованием преобразования CDECL. Как Вы должно быть знаете, это одна из самых худших ситуаций, с которой встречаются программисты VB API. VB понимает только преобразование STDCALL (также оно называется Паскаль- или Фортран- преобразованием). Так как параметры помещаются в стек в другом порядке, а выборка происходит также не по порядку, VB не может вызвать экспортированные таким способом функции. К счастью, системные программисты из Microsoft обеспечили совместимость библиотек не только с C/C++, и включили аналогичную функцию AVISaveV, которая объявляется через STDCALL. Это едиснтвенная функция, которую мы можем вызывать из VB, поэтому я использовал AVISaveV для вызова AVISave, однако если вы посмотрите MSDN по данному вопросу, то заметите, что последний параметр этих двух функций различен.

 

Теперь, когда я рассказал о некоторых встретившихся трудностях, давайте займемся кодом. Нам нужно показать диалог параметров сжатия, чтобы пользователь мог выбрать кодек, которым будет сжат полученный AVI-файл. Прежде всего, я получаю указатель на структуру:

 

pOpts = VarPtr(opts)

 

Затем я передаю этот параметр в функцию по ссылке, что означает получение указателя на указатель, а это и требуется для вызова API-функции. 3 флага, указанных во втором параметре функции, определяют, как будет выглядеть диалог параметров сжатия:

 

res = AVISaveOptions(Me.hWnd, _
        ICMF_CHOOSE_KEYFRAME Or ICMF_CHOOSE_DATARATE Or ICMF_CHOOSE_PREVIEW, _
        1, _
        pAVIStream, _
        pOpts)
'возвращает истину, если пользователь нажал OK, ложь если Cancel, или код ошибки

 

Если функция возвращает 1 (что означает в C/C++ ИСТИНА), то можно быть уверенным, что структура AVI_COMP_OPTIONS верно инициализирована. Теперь у нас имеется вся информация, чтобы создать новый сжатый поток из видео-потока файла, открытого в самом начале программы. Если исходный поток уже был сжат, он будет пересжат с использованием другого кодека (и возможно с потерей качества). Этот пример будет полезен при обработке несжатого потока (например, с ТВ-тюнера) или при подготовке видео ролика без звука для проигрывания в Win32 Animation Control (замечание: Animation Control позволяет воспроизводить несжатый поток или поток с RLE сжатием). Для создания сжатого видео-потока нам потребуется всего дна строчка кода:

 

'пересжимаем видео-поток с использованием настроек пользователя
res = AVIMakeCompressedStream(pAVIStreamOut, pAVIStream, opts, 0&)

 

Теперь мы имеем новый интерфейс видео-потока, и все готово для записи его в новый AVI-файл. Так как это может занять много времени, функция AVISave позволяет в реальном времени отображать текущий статус обработки и позволяет прервать обработку если это необходимо. Шаблон такой функции обратного вызова я поместил в файл AviDecs.bas вместе с информацией, необходимой для данного конкретного примера, поэтому Вы можете посмотреть там пример использования функции. Также я использовал глобальный флаг "abort", чтобы дать возможность пользователю прервать процесс обработки нажатием кнопки. Вот пример вызова функции AVISave:

 

pOpts = VarPtr(opts) 'убедимся, что указатель задан корректно
res = AVISave(szFileOut, 0&, AddressOf AVISaveCallback, 1, pAVIStreamOut, pOpts)

 

Если Вы используете функцию обратного вызова, включающую в себя DoEvents, Вы можете перехватить состояние, при котором пользователь пытается завершить приложение в процессе сохранения файла. В данном простом приложении я препятствую завершению работы приложения пользователем, используя одну дополнительную строчку кода в событии Query_Unload формы. Другой способ решения проблемы - прекратить сохранение и очистить ресурсы в тот момент, когда пользователь завершает приложение.

 

После завершения сохранения файла Вам нужно освободить ресурсы, занятые AVISaveOptions, используя функцию AVISaveOptonsFree:

 

Call AVISaveOptionsFree(1, pOpts)

 

На этом мы завершаем статью, посвященную созданию новых AVI-файлов из существующих потоков. Готовый проект можно скачать здесь.

 

   Перевод и редактура: Буторкин Сергей  Источник: http://www.shrinkwrapvb.com

 

e-mail:

 

bousoft@mail.ru