Краснов Михаил
Шрифт:
ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;
dwWidth := AviWidth;
dwHeight := AVIHeight;
end;
hRet := FDD.CreateSurface(ddsd, FDDSImage, nil);
if Failed(hRet) then ErrorOut(hRet, 'Create Second Surface');
В общем случае заводить отдельную поверхность для воспроизведения кадра, конечно, не обязательно, можно переносить содержимое вспомогательного растра прямо на первичную поверхность.
После инициализации DirectDraw подготавливаемся к работе с потоковым видео:
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 тоже годится не для любого файла. Другая причина, по которой мы не можем усердствовать в изучении упомянутого модуля, состоит в том, что он может применяться лишь с интерфейсами ранних версий.