Чтение онлайн

ЖАНРЫ

Графика DirectX в Delphi

Краснов Михаил

Шрифт:

procedure TfrmDD.FirstFrame;

var

wrkDC : HDC;

begin

AVIFilelnit; // Инициализация библиотеки

// Открываем AVI-файл для чтения

AVIStreamOpenFromFile(AviStream, AviName, streamtypeVIDEO,

0, OF_READ, nil);

// Загружаем поток

Frame := AVIStreamGetFrameOpen(AviStream, nil);

// Получаем первый кадр видео

pbmi := AVIStreamGetFrame(Frame, CurrFrame);

// Получаем указатель на картинку кадра

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).

Файл видео для этого примера также взят мною из пакета DirectX SDK.

При воспроизведении файла с помощью модуля 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 не содержит, конечно, пояснения по этим ошибкам.

Поделиться с друзьями: