raymedia: Интеграция мультимедиа в raylib с использованием FFmpeg (Delphi/Pascal)
В этой статье мы рассмотрим библиотеку raymedia, расширение для raylib, предоставляющее поддержку потоковой передачи аудио и видео через библиотеки FFmpeg. Мы обсудим особенности raymedia, процесс статической компиляции для Linux и подготовимся к компиляции для Windows, используя Object Pascal (Delphi).
Что такое raymedia?
raymedia – это удобное расширение для raylib, которое добавляет возможность потоковой передачи аудио и видео. Оно использует библиотеки FFmpeg (libav*) для интеграции мультимедиа контента в приложения raylib. Это позволяет разработчикам легко использовать видео текстуры и аудио потоки, а также поддерживать функции поиска и зацикливания. Библиотека предоставляет прямой доступ к видео текстурам и аудио потокам, что упрощает создание интерактивных мультимедийных приложений.
Преимущества использования raymedia:
Простота интеграции: raymedia предоставляет простой и понятный интерфейс для работы с мультимедиа контентом в raylib.
Широкая поддержка форматов: FFmpeg поддерживает широкий спектр аудио и видео форматов, что делает raymedia универсальным решением.
Поиск и зацикливание: Поддержка функций поиска и зацикливания позволяет создавать сложные мультимедийные приложения.
Прямой доступ к потокам: Предоставляет прямой доступ к видео текстурам и аудио потокам, что позволяет реализовать различные эффекты и взаимодействия.
Приведем фрагмент кода, демонстрирующий основные типы и константы:
unit raymedia;
{$mode objfpc}{$H+}
{$packrecords c}
{$ALIGN 8}
{$MINENUMSIZE 4}
// Include configuration file
{$I ../raylib.inc}
interface
uses
raylib;
{$IFNDEF RAY_STATIC}
const
{$ifdef linux}
cDllName = 'librmedia.so';
{$endif}
{$endif}
type
PMediaContext = ^TMediaContext;
TMediaContext = pointer; //record end;
PMediaStream = ^TMediaStream;
TMediaStream = record
videoTexture: TTexture; // Current video frame texture (if available)
audioStream: TAudioStream; // Audio stream for playback (if available)
ctx: PMediaContext; //???? // Internal use only
end;
TMediaProperties = record
durationSec: double; // Media duration in seconds
avgFPS: single; // Average video FPS
hasVideo: boolean; // True if video is present
hasAudio: boolean; // True if audio is present
end;
type
TReadFn = function(userData: Pointer; buffer: PByte; bufferSize: Integer): Integer; cdecl;
TSeekFn = function(userData: Pointer; offset: Int64; whence: Integer): Int64; cdecl;
PMediaStreamReader = ^TMediaStreamReader;
TMediaStreamReader = record
readFn: TReadFn;
seekFn: TSeekFn;
userData: Pointer;
end;
//Flags for LoadMediaEx() to customize media loading.
PMediaLoadFlag = ^TMediaLoadFlag;
TMediaLoadFlag = Integer;
const
MEDIA_LOAD_AV = TMediaLoadFlag(0); // Load audio and video (default)
MEDIA_LOAD_NO_AUDIO = TMediaLoadFlag(1 shl 1); // Do not load audio
MEDIA_LOAD_NO_VIDEO = TMediaLoadFlag(1 shl 2); // Do not load video
MEDIA_FLAG_LOOP = TMediaLoadFlag(1 shl 3); // Loop playback
MEDIA_FLAG_NO_AUTOPLAY = TMediaLoadFlag(1 shl 4); // Load without starting playback
type
PMediaState = ^TMediaState;
TMediaState = Integer;
const
MEDIA_STATE_INVALID = TMediaState(-1); // Not loaded or initialized
MEDIA_STATE_STOPPED = TMediaState(0); // Stopped
MEDIA_STATE_PAUSED = TMediaState(1); // Paused
MEDIA_STATE_PLAYING = TMediaState(2); // Playing (call UpdateMedia() each frame)
type
PMediaConfigFlag = ^TMediaConfigFlag;
TMediaConfigFlag = Integer;
const
MEDIA_VIDEO_QUEUE = TMediaConfigFlag(0); // Video packet queue capacity
MEDIA_AUDIO_QUEUE = TMediaConfigFlag(1); // Audio packet queue capacity
MEDIA_AUDIO_DECODED_BUFFER = TMediaConfigFlag(2); // Maximum decoded audio buffer size
MEDIA_AUDIO_STREAM_BUFFER = TMediaConfigFlag(3); // Audio stream buffer size
MEDIA_AUDIO_FORMAT = TMediaConfigFlag(4); // Output audio format (refer to MediaAudioFormat)
MEDIA_AUDIO_CHANNELS = TMediaConfigFlag(5); // Number of audio channels
MEDIA_VIDEO_MAX_DELAY = TMediaConfigFlag(6); // Maximum delay (ms) before discarding a video packet
MEDIA_AUDIO_MAX_DELAY = TMediaConfigFlag(7); // Maximum delay (ms) before discarding an audio packet
MEDIA_AUDIO_UPDATE = TMediaConfigFlag(8); // Max bytes uploaded to AudioStream per frame
type
PMediaAudioFormat = ^TMediaAudioFormat;
TMediaAudioFormat = Integer;
const
AUDIO_FMT_U8 = TMediaAudioFormat(0); // Unsigned 8-bit
AUDIO_FMT_S16 = TMediaAudioFormat(1); // Signed 16-bit (default)
AUDIO_FMT_S32 = TMediaAudioFormat(2); // Signed 32-bit
AUDIO_FMT_FLT = TMediaAudioFormat(3); // Float
AUDIO_FMT_DBL = TMediaAudioFormat(4); // Double
type
TMediaStreamIOResult = (
MEDIA_IO_EOF = -541478725, // Конец потока достигнут (соответствует AVERROR_EOF)
MEDIA_IO_INVALID = -22 // Некорректный вызов или операция (соответствует AVERROR(EINVAL))
);
function LoadMedia(const fileName: PChar): TMediaStream; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'LoadMedia';
function LoadMediaEx(const fileName: PChar; flags: Integer): TMediaStream; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'LoadMediaEx';
function LoadMediaFromStream(streamReader: TMediaStreamReader; flags: integer): TMediaStream; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'LoadMediaFromStream';
function IsMediaValid(media: TMediaStream): Boolean; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'IsMediaValid';
function GetMediaProperties(media: TMediaStream): TMediaProperties; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'GetMediaProperties';
function UpdateMedia(media: PMediaStream): Boolean; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'UpdateMedia';
function UpdateMediaEx(media: PMediaStream; deltaTime: Double): Boolean; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'UpdateMediaEx';
function GetMediaState(media: TMediaStream): Integer; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'GetMediaState';
function GetMediaPosition(media: TMediaStream): Double; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'GetMediaPosition';
function SetMediaPosition(media: TMediaStream; timeSec: Double): Boolean; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'SetMediaPosition';
function SetMediaLooping(media: TMediaStream; loopPlay: Boolean): Boolean; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'SetMediaLooping';
function SetMediaFlag(flag: Integer; value: Integer): Integer; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'SetMediaFlag';
function GetMediaFlag(flag: Integer): Integer; cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'GetMediaFlag';
procedure UnloadMedia(media: PMediaStream); cdecl; external {$IFNDEF RAY_STATIC}cDllName{$ENDIF} name 'UnloadMedia';
Статическая компиляция для Linux:
Для статической компиляции библиотеки raymedia для Linux необходимо выполнить следующие шаги:
Убедитесь, что у вас установлены необходимые библиотеки: В частности, требуется FFmpeg версии 7.1 или выше. Можно установить с помощью менеджера пакетов вашей системы.
Настройте параметры компиляции: В файле raymedia.pas убедитесь, что компилятор знает, где находятся библиотеки FFmpeg. Если вы используете статическую компиляцию, необходимо явно указать пути к библиотекам libavcodec, libavformat, libavutil, libswresample и libswscale.
Включите директивы компиляции: В секции implementation файла raymedia.pas добавьте следующие директивы:
Скомпилируйте проект: Используйте Delphi IDE или командную строку для компиляции проекта.
Подготовка к компиляции для Windows:
Для компиляции raymedia для Windows потребуется:
Получить библиотеки FFmpeg для Windows: Скачайте предварительно скомпилированные библиотеки FFmpeg для Windows (в формате .dll и .lib) или скомпилируйте их самостоятельно.
Настроить параметры компиляции: В файле raymedia.pas необходимо определить константу cDllName для Windows.
Добавить пути к библиотекам: Укажите пути к .lib файлам FFmpeg в настройках проекта Delphi.
Скомпилировать проект: Скомпилируйте проект для Windows.
Пример использования:
program project1;
{$mode objfpc}{$H+}
uses
cthreads,
Classes, SysUtils, CustApp, raylib, raymedia;
type
{ TRayApplication }
TRayApplication = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
end;
var videoMedia : TMediaStream;
constructor TRayApplication.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
InitWindow(800, 600, 'raylib - basic window');
InitAudioDevice();
SetWindowState( FLAG_VSYNC_HINT or FLAG_MSAA_4X_HINT or FLAG_WINDOW_RESIZABLE);
SetMediaLooping(videoMedia, true);
videoMedia := LoadMedia('123.mp4');
if (not IsMediaValid(videoMedia)) then
begin
TraceLog(LOG_ERROR, 'Failed to load media file: %s', '123.mp4');
CloseAudioDevice();
CloseWindow();
end;
SetMediaLooping(videoMedia, true);
end;
procedure TRayApplication.DoRun;
var srcRect, dstRect: TRectangle;
begin
while (not WindowShouldClose) do
begin
UpdateMedia(@videoMedia);
BeginDrawing();
ClearBackground(RAYWHITE);
DrawFPS(10,10);
srcRect.Create( 0, 0, videomedia.videoTexture.width, videomedia.videoTexture.height);
dstRect.Create(0,0, GetScreenWidth, GetScreenHeight);
DrawTexturePro(Videomedia.videoTexture,
srcRect, dstRect, Vector2Create( 0, 0 ), 0.0, WHITE);
EndDrawing();
end;
Terminate;
end;
destructor TRayApplication.Destroy;
begin
UnloadMedia(@videoMedia);
CloseWindow();
TraceLog(LOG_INFO, 'your first window is close and destroy');
inherited Destroy;
end;
var
Application: TRayApplication;
begin
Application:=TRayApplication.Create(nil);
Application.Title:='raylib - basic window';
Application.Run;
Application.Free;
end.
Заключение:
raymedia предоставляет удобный способ интеграции аудио и видео в приложения raylib. Статическая компиляция для Linux упрощает развертывание, а подготовка к компиляции для Windows позволит использовать raymedia на широком спектре платформ. Убедитесь, что используете FFmpeg версии 7.1 или выше для корректной работы библиотеки.
Статья о библиотеке raymedia, расширении для raylib, которое добавляет поддержку потоковой передачи аудио и видео с использованием FFmpeg, с инструкциями по статической компиляции для Linux и подготовке к компиляции для Windows, а также примером использо
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.