Графика DirectX в Delphi
Шрифт:
bits := Pointer(Integer(pbmi) + SizeOf(TBITMAPINFOHEADER));
// Получаем контекст для воспроизведения кадра на поверхность
if FDDSImage.GetDC (wrkDC) = DD_OK then begin
// Воспроизводим кадр во вспомогательный растр
TmpBmp.Handle := CreateDIBitmap(
// Вспомогательным контекстом служит HDC поверхности
wrkDC,
pbmi^, // Адрес размера растра и формата данных
CBM_INIT, // Флаг инициализации
bits, // Данные для инициализации
PBITMAPINFO(pbmi)^, // Данные о формате цвета
DIB RGB_COLORS); //
// Переносим картинку из вспомогательного растра на поверхность
BitBlt (wrkDC, О, О, AVIWidth, AVIHeight,
TinpBmp. Canvas .Handle, 0, 0, SRCCOPY);
FDDSImage.ReleaseDC (wrkDC);
end;
AVIClock := GetTickCount; // Инициализация вспомогательного таймера
end;
Действия по воспроизведению очередного кадра аналогичны, но тратить время на получение адресов теперь не нужно:
procedure ТfrmDD,NextFrame;
var
wrkDC : HDC;
begin
// Настало время воспроизвести следующий кадр AVI
if GetTickCount - AVIClock > AVIDelay then begin
pbmi := AVIStreamGetFrame(Frame, CurrFrame);
if FDDSImage.GetDC (wrkDC) = DD_OK then begin
TmpBmp.Handle := CreateDIBitmap(wrkDC, pbmi^, CBM_INIT,
bits, PBITMAPINFO(pbmi) Л, DIB_RGB__COLORS) ;
BitBlt (wrkDC, 0, 0, AVIWidth, AVIHeight,
TmpBmp.Canvas.Handle, 0, 0, SRCCOPY);
FDDSImage.ReleaseDC (wrkDC);
end;
// Увеличиваем счетчик кадров
CurrFrame := (CurrFrame + 1) mod AVILength;
AVIClock := GetTickCount;
end;
end;
В этом примере AVI-файл воспроизводится бесконечно, вслед за последним кадром все повторяется с начала.
Кадр воспроизведен на поверхности FDDSimage, блиттинг которой осуществляется тривиальным способом.
По завершении работы добавились ожидаемые действия:
AVIStreamRelease(AviStream); // Закрытие потока
AVIFileExit; // Завершение работы с библиотекой
TmpBmp.Free; // Удаление вспомогательного растра
Итак, теперь вы способны делать видео частью ваших игр, но я должен предупредить, что библиотека может корректно работать не с каждым типом сжатия. По этой причине я рекомендую заставки игр воспроизводить стандартным для Delphi способом.
Модуль DirectShow
Поскольку изложенный в предыдущем разделе способ годится не для каждого видео, нам придется бегло рассмотреть еще один способ воспроизведения видео, основанный на использовании модуля DirectShow. Эта библиотека также входит в состав DirectX, включает набор функций для работы с мультимедиа. Подробно рассматривать ее не будем, познакомимся с ее использованием на конкретном примере, проекте каталога Ех02, воспроизводящем AVI-файл на поверхности (рис. 6.2).
Файл
При воспроизведении файла с помощью модуля VFW картинка получается искаженной, поэтому и приходится прибегать к иному способу. Отказаться от первого способа мы также не можем, поскольку DirectShow тоже годится не для любого файла. Другая причина, по которой мы не можем усердствовать в изучении упомянутого модуля, состоит в том, что он может применяться лишь с интерфейсами ранних версий.
Модуль использует СОМ-модель, поэтому здесь мы встретим знакомые понятия главного объекта и дочерних интерфейсов:
var
AMStream : lAMMultiMediaStream; // Главный объект
PrimaryVidStream : IMediaStream; // Дочерний поток, связан с видео
Sample : IDirectDrawStreamSample; // Интерфейс для вывода на поверхность
В процедуру инициализации потока передается имя требуемого файла:
procedure TfrmDD.PlayMedia(const FileName: WideString);
var
hRet : HRESULT;
begin
// Создание главного объекта ('filter graph1)
AMStream:=IAMMultiMediaStream(CreateComObject
(CLSID_AMMultiMediaStream));
// Инициализация потока для чтения
hRet := AMStream.Initialize(STREAMTYPE_READ, 0, nil);
if Failed (hRet) then ErrorOut (hRet, 'Stream Initialize');
// Добавление потока видео к главному объекту
hRet := AMStream.AddMediaStream(FDD, MSPID_PrimaryVideo,
0, IMediaStream(ni!A));
if Failed (hRet) then ErrorOut (hRet, 'Add Video Stream');
// Открытие файла
hRet := AMStream.OpenFile(PWideChar(FileName) , 0);
if Failed (hRet) then ErrorOut (hRet, 'Open AVI File');
// Следующие действия предназначены для связывания потока и поверхности
// Получение дочернего потока
hRet := (AMStream as IMultiMediaStream).
GetMediaStream(MSPID_PrimaryVideo, PrimaryVidStream);
if Failed (hRet) then ErrorOut (hRet, 'GetMediaStream');
// Преобразование интерфейса в тип Isample
//и связывание его с поверхностью
hRet := (PrimaryVidStream as IDirectDrawMediaStream).
CreateSample (FDDS Image, TRect(nil/4), 0, Sample);
if Failed (hRet) then ErrorOut (hRet, 'CreateSample');
// Запуск потока
hRet := (AMStream as IMultiMediaStream).SetState(STREAMSTATE_RUN);
if Failed (hRet) then ErrorOut (hRet, 'SetState');
end;
Обработку возможных ошибок я оставил прежней, но коды ошибок не будут расшифровываться. Модуль DirectDraw не содержит, конечно, пояснения по этим ошибкам.