Александр Бусаров дата публикации 02-03-2007 05:18 IMediaDet — интерфейс для захвата видео и аудио информации
В данной статье я хочу рассмотреть интерфейс IMediaDet, который нам любезно предоставил DirectShow.
Интерфейс специально разработан для того, чтобы захватить часть видео или аудио информации.
Тема небольшая, да и напишу я немного, но думаю, что информация полезная, потому что лично я сталкивался с такой проблемой раньше и не один раз. Выкручивался как всегда какими-нибудь модулями, которые поддерживали от силы 2-3 формата сжатия. Причем один из них позволял сделать одно, скажем, вытащить картинку, другой - сделать видеосэмпл, третий - аудио.
Прежде чем работать с интерфейсом, нужно подключить заголовочный модуль DirectShow (см. файлы к статье).
Еще нужно подключить модуль ActiveX. Он идет "в комплекте" с Delphi.
Итак, прежде всего этот интерфейс нужно создать. Создается он с нуля, т.е. не методом какого либо объекта, а прямо с помощью CoCreateInstance.
Объявляем переменную:
Detector:IMediaDet;
И создаем ее:
CoCreateInstance (CLSID_MediaDet,nil, CLSCTX_INPROC_SERVER, IID_IMediaDet, Detector);
После того как детектор создан, мы должны открыть какие то данные. Детектор позволяет нам открывать файлы.
Открываем файл методом
put_Filename(name: PWideChar)
заметьте, что передается юникод-строка.
Получить имя открытого файла можно похожим способом: get_Filename
Далее нам нужно получить информацию о видеофайле.
Для этого у нашего детектора есть метод get_StreamMediaType. Вызывается он всего лишь c одним аргументом типа _AMMediaType. В него он возвращает значение.
Тип _AMMediaType объеденил в себе ниформацию об аудио- и видео-данных.
Для того, чтобы получить информацию о видеофайле можно просто использовать приведение типов.
Вот пример для наглядности:
var
info:_AMMediaType;
height, width:word;
Begin
Detector.get_StreamMediaType(info);
Width:=VIDEOINFOHEADER(info.pbFormat^).bmiHeader.biWidth;
Height:=VIDEOINFOHEADER(info.pbFormat^).bmiHeader.biHeight;
End;
Тип VIDEOINFOHEADER предоставляет нам очень много различной информации. И размер изображения, и сжатие, и много еще всего, но он не предоставляет нам длительность ролика. Поэтому используем метод get_StreamLength(out length:double);
Здесь длина представлена в секундах, что очень удобно.
Итак, мы подготовились к получению скриншотов нашего видеофайла. Получить скриншот мы можем 2-мя способами.
Используем метод (опять юникод в параметрах)
WriteBitmapBits(time:double; width, height:integer; FIleName:WideString)
Просто передаем этому методу время в секундах, высоту, ширину, полученную, когда мы вызывали get_StreamMediaType, и имя файла, куда все это добро напишется.
Понятно, что все это запишется сразу же в файл, а вот как получить скриншот сразу в память?
Делается это с помощью метода
GetBitmapBits (time:Double; buffersize:PLongint; buffer:PByte; width, height:integer);
ВНИМАНИЕ!
DirectShow возвращает картинку всегда в 24-битном формате цвета. По байту на каждый канал RGB.
Вызвать метод нужно 2 раза. 1-ый, чтобы определить размер буфера, второй — чтобы записать в него данные. Определять размер можно 1 раз сразу после получения информации по файлу. (Это для оптимизации), так же можно сразу выделять память в буфере под скриншот.
Метод GetBitmapBits для определения размеров буфера нужно вызывать передавая ему параметр nil в качестве buffer. Тогда в переменную buffersize поместится размер буфера. После этого можно выделять память под buffer, и вызывать второй раз метод GetBitmapBits, теперь уже передавая ему в качестве buffer-а наш буфер. (при этом в параметр buffersize передаем nil. Работает вроде даже если передавать не nil, но так советует Microsoft). Height и width передаем все те же, какие были получены через get_StreamMediaType.
Итак, все, в буфере у нас содержится наш рисунок. Осталось только понять как с ним работать, т.е. в каком формате он там хранится. Это формат BITMAPINFOHEADER, который объявлен в Windows.pas.
Битовая информация о каждом пикселе содержится по адресу:
bitinfo:=Pointer(integer(buffer)+SizeOf(BITMAPINFOHEADER));
Так же можно создать HBitmap с нашего buffer используя CreateDIBitmap из Windows.pas
В общем, теперь мы с этой памятью можем делать, что захотим.
IMediaDet так же нам предоставляет возможность работать с отрывком (сэмплом) видеофайла.
Для этого у него есть метод GetSampleGrabber(grabber: ISampleGrabber). Скажу лишь, что вызывая этот метод, мы создаем объект интерфейса ISampleGrabber. Ну а поскольку это уже другой интерфейс, то о нем я расскажу в другой статье.
К материалу прилагаются файлы:
[DirectShow]
Обсуждение материала [ 09-05-2011 06:49 ] 6 сообщений |