главная продукты 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.

Часть 3. Работа с кадрами в существующем AVI-файле.

 

Следующий шаг при работе с AVI-файлом - получить кадр (сэмпл). В прошлых статьях мы уже открыли видео поток в AVI-файле, поэтому давайте попробуем сохранить каждый кадр потока как отдельный растровый файл. Это потребует написания большего количества кода, чем раньше, поэтому вместо копирования кода с этой страницы скачайте готовую программу отсюда, а я просто обращу Ваше внимание на некоторые основополагающие моменты.

 

После того, как Вы скачаете и откроете этот проект в VB5 или VB6, Вы заметите, что я добавил на форму текстовое поле (используется для вывода отладочной информации) и новый класс (cDIB.cls). Этот класс содержит вызовы некоторых API-функций при работе с DIB (Device Independent Bitmaps). Это специальный прием, используемый при работе со структурой BitmapInfo, имеющей изменяемую длину в зависимости от глубины цвета растра. В любом случае, опуская подробности реализации этого класса, Вы заметите, что он добавляет совсем немного новых строк кода в событие обработки нажатия кнопки.

 

В вначале процедуры объявляются пять новых переменных:

 

Dim dib As cDIB
Dim pGetFrameObj As Long
'указатель на интерфейс GetFrame
Dim pDIB As Long
'указатель на упакованный DIB в памяти
Dim bih As BITMAPINFOHEADER
'структура, передаваемая в функцию GetFrame
Dim i As Long

 

Переменная dib является объявлением экземпляра нашего нового класса cDIB. Переменная pGetFrameObj - новый вид указателя, который требуется для вызова функций AVIStreamGetFrame. Эти функции автоматически предоставляют ресурсы для распаковки одного кадра в любую структуру типа DIB, которую мы укажем, и возвращает указатель на нее, после чего мы можем обрабатывать эту структуру в дальнейшем так, как захотим. Для использования этих функций во-первых я выделяю ресурсы и получаю указатель в переменную pGetFrameObj:

 

'инициализация функций AVISTreamGetFrame* и создание объекта GETFRAME
pGetFrameObj = AVIStreamGetFrameOpen(pAVIStream, bih) 'получить 24-битные DIB

 

Перед этой строчкой необходимо инициализировать структуру BITMAPINFOHEADER, так, чтобы получить требуемые результаты (в данном случае 24-разрядный цвет, несжатый RGB):

 

With bih
    .biBitCount = 24
    .biClrImportant = 0
    .biClrUsed = 0
    .biCompression = BI_RGB
    .biHeight = streamInfo.rcFrame.bottom - streamInfo.rcFrame.top
    .biPlanes = 1
    .biSize = 40
    .biWidth = streamInfo.rcFrame.right - streamInfo.rcFrame.left
    .biXPelsPerMeter = 0
    .biYPelsPerMeter = 0
    .biSizeImage = (((.biWidth * 3) + 3) And &HFFFC) * .biHeight 
End With

 

Это позволяет узнать, какой формат DIB будет использоваться в дальнейшем, и моя структура DIB может ссылаться на него (в настоящее время класс DIB может ссылаться только на неструктурированные DIB - 16- и 24-разрядного цвета). Если Вы собираетесь передавать полученные DIB-указатели в другие функции, такие как DrawDIB, которые понимают любые форматы, Вам потребуется вызвать функцию следующим образом:

 

'функция AVIStream выбирает наилучший формат отображения автоматически
pGetFrameObj = AVIStreamGetFrameOpen(pAVIStream, ByVal AVIGETFRAMEF_BESTDISPLAYFMT) 

 

Это проще, чем инициализация структуры BITMAPINFOHEADER, но это означает, что Вам неизвестно, какой формат будет получен на выходе - он определяется текущими настройками экрана и "железом".

 

Теперь, после успешной инициализации функции GetFrame нужным нам форматом и получения корректного указателя в переменной pGetFrameObj, все что нам нужно сделать - это передать ссылку и номер необходимого кадра в функцию AVIStreamGetFrame. Затем я использую класс cDIB растровых ссылок и пикселов изображения и записи этой информации на диск как растровый файл. Это потребует еще нескольких строк кода:

 

'создать класс для загрузки в него кадров
Set dib = New cDIB
For i = firstFrame To (numFrames - 1) + firstFrame
    pDIB = AVIStreamGetFrame(pGetFrameObj, i)
'возвращает упакованные DIB
    If dib.CreateFromPackedDIBPointer(pDIB) Then
        Call dib.WriteToFile(App.Path & "\" & i & ".bmp")
        txtStatus = "Bitmap " & i + 1 & " of " & numFrames & " written to app folder"
        txtStatus.Refresh
    Else
        
    End If
Next
Set dib = Nothing

 

Вот и все! Как видите, переменная i - это счетчик, который я использую при формировании имени текущего файла. Будьте осторожны при использовании этого примера с большими AVI-файлами, так как процесс извлечения кадров невозможно остановить до тех пор, пока все кадры не будут записаны на диск. Если Вы запустите этот пример с каким-нибудь AVI-файлом, Вы получите в папке программы 24-разрядные растровые файлы с именами, соответствующими номерам кадров. Если Вы хотите узнать, как я записываю растры на диск, откройте класс cDIB. Для этого потребуются всего 2 функции - .CreateFromPackedDIBPointer и .WriteToFile. Другие функции класса cDIB служат для создания DIB из растровых файлов, что мы будем делать в следующей статье. В своей программе Вы можете создать hDC для каждого кадра и поместить его в PictureBox вместо записи в файл.

 

После завершения обработки потока не забывайте освобождать занятые ресурсы при помощи функции AVIStreamGetFrameClose:

 

Call AVIStreamGetFrameClose(pGetFrameObj)

 

После вызова этой функции указатель pGetFrameObj перестанет существовать. Неплохо было бы присвоить ему значение 0, если Вы собираетесь использовать его в дальнейшем.

 

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

 

e-mail:

 

bousoft@mail.ru