type
  TLibrary = (avUtil, swScale, swResample, avCodec, avFormat, avFilter, avDevice, myUtil, SDL2, libSoundTouch);
  TLibraries = set of TLibrary;

  TFFLoader = class
  public
    constructor Create;
    function  Load(ALibrary: TLibrary): Boolean; overload;
    function  Load(ALibraries: TLibraries): Boolean; overload;
    function  Loaded(ALibrary: TLibrary): Boolean; overload;
    function  Loaded(ALibraries: TLibraries): Boolean; overload;
    procedure CheckLibAV(ALibraries: TLibraries);
    procedure Unload(ALibrary: TLibrary); overload;
    procedure Unload(ALibraries: TLibraries); overload;

    function GetLibBuildVer(ALibrary: TLibrary): Integer;     // library version number of the components
    function GetLibBuildVerStr(ALibrary: TLibrary): string;   // library version string of the components

    function GetLibFileVer(ALibrary: TLibrary): Integer;      // library version number of the loaded library file
    function GetLibFileVerStr(ALibrary: TLibrary): string;    // library version string of the loaded library file

    function GetLibLicense(ALibrary: TLibrary): string;       // library license of the loaded library file
    function GetLibConfiguration(ALibrary: TLibrary): string; // library configuration of the loaded library file

    function CheckLibConfigurations(): Boolean;               // all libraries configuration are matched

    function GetFormats(AList: TStrings): Integer;            // available formats in the loaded libraries
    function GetMuxers(AList: TStrings): Integer;             // available muxers in the loaded libraries
    function GetDemuxers(AList: TStrings): Integer;           // available demuxers in the loaded libraries
    function GetDevices(AList: TStrings): Integer;            // available devices in the loaded libraries
    function GetCodecs(AList: TStrings): Integer;             // available codecs in the loaded libraries
    function GetDecoders(AList: TStrings): Integer;           // available decoders in the loaded libraries
    function GetEncoders(AList: TStrings): Integer;           // available encoders in the loaded libraries
    function GetBSFs(AList: TStrings): Integer;               // available bit stream filters in the loaded libraries
    function GetProtocols(AList: TStrings): Integer;          // available protocols in the loaded libraries
    function GetFilters(AList: TStrings): Integer;            // available filters in the loaded libraries
    function GetPixFmts(AList: TStrings): Integer;            // available pixel formats in the loaded libraries
    function GetLayouts(AList: TStrings): Integer;            // available standard channel layouts in the loaded libraries
    function GetSampleFmts(AList: TStrings): Integer;         // available audio sample formats in the loaded libraries
    function GetDispositions(AList: TStrings): Integer;       // available stream dispositions in the loaded libraries
    function GetColors(AList: TStrings): Integer;             // available color names in the loaded libraries

    property LastErrMsg: string read GetLastErrMsg;
    property LibraryPath: TPathFileName read GetLibraryPath write SetLibraryPath;
    property LibraryNames[Index: TLibrary]: TPathFileName read GetLibraryName write SetLibraryName;
    property InstallLogger: Boolean read FInstallLogger write FInstallLogger;
  end;

  // refer to libavutil_log.pas or ffmpeg's (libavutil)log.h
  TLogLevel = (
    llQuiet,
    (**
     * Something went really wrong and we will crash now.
     *)
    llPanic,
    (**
     * Something went wrong and recovery is not possible.
     * For example, no header was found for a format which depends
     * on headers or an illegal combination of parameters is used.
     *)
    llFatal,
    (**
     * Something went wrong and cannot losslessly be recovered.
     * However, not all future data is affected.
     *)
    llError,
    (**
     * Something somehow does not look correct. This may or may not
     * lead to problems. An example would be the use of '-vstrict -2'.
     *)
    llWarning,
    llInfo,
    llVerbose,
    (**
     * Stuff which is only useful for libav* developers.
     *)
    llDebug,
    (**
     * Extremely verbose debugging, useful for libav* development.
     *)
    llTrace
  );

  TLogEvent = procedure(Sender: TObject; AThreadID: Integer; // THandle;
    ALogLevel: TLogLevel; const ALogMsg: string) of object;

  TFFLogWorker = class
  public
    constructor Create;
    destructor  Destroy; override;
    procedure ClearLogFile;
    procedure InstallAVLogCallback;
    procedure FlushRepeats;
    procedure Log(const ALogMsg: string); overload;
    procedure Log(Sender: TObject; ALogLevel: TLogLevel; const ALogMsg: string); overload;
    procedure Log(Sender: TObject; ALogLevel: TLogLevel; const AFormat: string; const Args: array of const); overload;
    property Active: Boolean read GetActive write SetActive default True;
    property LogFile: string read GetLogFile write SetLogFile;
    property LogFlags: Integer read GetLogFlags write SetLogFlags;
    property LogLevel: TLogLevel read GetLogLevel write SetLogLevel default llInfo;
    property LogToFile: Boolean read GetLogToFile write SetLogToFile default False;
    property LogWithLevel: Boolean read GetLogWithLevel Write SetLogWithLevel default True;
    property LogWithThreadID: Boolean read GetLogWithThreadID Write SetLogWithThreadID default True;
    property LogWithTime: Boolean read GetLogWithTime Write SetLogWithTime default True;
    property Synchronous: Boolean read GetSynchronous write SetSynchronous default False;
    property TriggerEventInMainThread: Boolean read FTriggerEventInMainThread write FTriggerEventInMainThread default True;
    property OnLog: TLogEvent read FOnLog write SetOnLog;
  end;

// TLogLevel to Integer
function LogLevelToInt(ALogLevel: TLogLevel): Integer; {$IFDEF USE_INLINE}inline;{$ENDIF}
// Integer to TLogLevel
function IntToLogLevel(ALogLevel: Integer): TLogLevel; {$IFDEF USE_INLINE}inline;{$ENDIF}

var
  // global instance of TFFLoader
  FFLoader: TFFLoader = nil;
  // global instance of TFFLogWorker
  FFLogger: TFFLogWorker = nil;

const
  CAllLibraries    : TLibraries = [avCodec, avDevice, avFilter, avFormat, avUtil, swResample, swScale, myUtil, SDL2, libSoundTouch];
  CDecoderLibraries: TLibraries = [avCodec, avDevice, avFilter, avFormat, avUtil, swResample, swScale, myUtil];
  CEncoderLibraries: TLibraries = [avCodec, avDevice, avFilter, avFormat, avUtil, swResample, swScale, myUtil];
  CPlayerLibraries : TLibraries = [avCodec, avDevice, avFilter, avFormat, avUtil, swResample, swScale, myUtil, SDL2];
  CFFmpegLibraries : TLibraries = [avCodec, avDevice, avFilter, avFormat, avUtil, swResample, swScale];

implementation

initialization
  FFLoader := TFFLoader.Create;
  FFLogger := TFFLogWorker.Create;

finalization
  if Assigned(FFLogger) then
    FreeAndNil(FFLogger);
  FreeAndNil(FFLoader);

end.
