{
  function Seek(const APTS: Int64; ASeekFlags: TSeekFlags = []): Boolean;
    if sfByte in ASeekFlags then
      APTS: Position in bytes, its bound is 0 to size of the file.
    else
      APTS: Presentation Time Stamp in microsecond, its bound is 0 to
        total duration of the file.
    ASeekFlags: TSeekFlags = set of TSeekFlag
      sfBackward: // seek backward
      sfByte:     // seeking based on position in bytes
      sfAny:      // seek to any frame, even non key-frames

  function Decode(AStreamIndex: Integer = -1): Boolean;
  function DecodeNextKeyFrame(AStreamIndex: Integer = -1): Boolean;
  function DecodePreviousFrame(AStreamIndex: Integer = -1): Boolean;
  function DecodePreviousKeyFrame(AStreamIndex: Integer = -1): Boolean;
    AStreamIndex: special video stream to decode, must be set as video stream's index.
      -1 means using the first video stream.
    if Decode() successfully, use property FrameInfo to get the information.
    NOTICE: after Decode() call, the position will change to next frame.

  function CopyToBitmap(ABitmap: TBitmap): Boolean;
    if Decode() successfully, copy the decoded frame picture to ABtimap.
  function GetBitmapPtr: PBitmap;
    if Decode() successfully, return the pointer of the BITMAP structure which
      defines the type, width, height, color format, and bit values of a bitmap.

  function ReadAudio(ABuffer: PByte; ACount: Integer; AStreamIndex: Integer = -1): Integer;
    ABuffer: copy audio data to this buffer.
    ACount: desire audio data size, it should be not great than the ABuffer size.
    AStreamIndex: special audio stream to decode, must be set as audio stream's index.
      -1 means using the first audio stream.
    Return: the actual audio data size, or -1 on error or EOF.
    NOTICE: if ABuffer is nil, return the audio data size only without reading.
}

type

  TFileStreamInfo = record
    StartTime: Int64;
    Duration: Int64;
    BitRate: Integer;
    Year: Integer;
    Track: Integer;
{$IF Defined(BCB)} // C++Builder
    Title: array[0..255] of AnsiChar;
    Author: array[0..255] of AnsiChar;
    Copyright: array[0..255] of AnsiChar;
    Comment: array[0..255] of AnsiChar;
    Album: array[0..255] of AnsiChar;
    Genre: array[0..255] of AnsiChar;
{$ELSE}
    Title: string;
    Author: string;
    Copyright: string;
    Comment: string;
    Album: string;
    Genre: string;
{$IFEND}
  end;

  TAudioStreamInfo = record
{$IF Defined(BCB)} // C++Builder
    Language: array[0..31] of AnsiChar;
    CodecName: array[0..63] of AnsiChar;
{$ELSE}
    Language: string;
    CodecName: string;
{$IFEND}
    StartTime: Int64;
    StartTimeScaled: Int64;
    Duration: Int64;
    DurationScaled: Int64;
    BitRate: Integer;
    Channels: Integer;
    SampleRate: Integer;
    SampleFormat: TAVSampleFormat;
  end;

  TVideoStreamInfo = record
{$IF Defined(BCB)} // C++Builder
    Language: array[0..31] of AnsiChar;
    CodecName: array[0..63] of AnsiChar;
{$ELSE}
    Language: string;
    CodecName: string;
{$IFEND}
    StartTime: Int64;
    StartTimeScaled: Int64;
    Duration: Int64;
    DurationScaled: Int64;
    BitRate: Integer;
    Height: Integer;
    Width: Integer;
    SampleAspectRatio: Single;
    DisplayAspectRatio: Single;
    SAR: TAVRational;
    DAR: TAVRational;
    PixFmt: TAVPixelFormat;
    FrameRate: TAVRational;
    Rotation: Double;
  end;

  TSubtitleStreamInfo = record
{$IF Defined(BCB)} // C++Builder
    Language: array[0..31] of AnsiChar;
    CodecName: array[0..63] of AnsiChar;
{$ELSE}
    Language: string;
    CodecName: string;
{$IFEND}
    SubFormat: Integer; // 0 -> bitmap based, 1 -> text based
  end;

  TCustomDecoder = class(TFFBaseComponent)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure SetLicenseKey(const AKey: AnsiString);

    function AVLibLoaded: Boolean;
    function LoadAVLib(const APath: TPathFileName): Boolean;
    procedure UnloadAVLib;

    function LoadFile(const AFileName: TPathFileName; const AOptions: string = ''): Boolean;
    procedure CloseFile; virtual;

    function IsAudioStream(AStreamIndex: Integer): Boolean;
    function IsVideoStream(AStreamIndex: Integer): Boolean;
    function IsSubtitleStream(AStreamIndex: Integer): Boolean;

    property FileHandle: PAVFormatContext read FFileHandle write SetFileHandle;
    property FileName: TPathFileName read GetFileName;
    property FileSize: Int64 read FFileSize;
    property FormatName: string read GetFormatName;
    property FormatLongName: string read GetFormatLongName;
    property GetLongCodecName: Boolean read FGetLongCodecName write FGetLongCodecName;

    property StreamCount: Integer read FStreamCount;
    property ProgramCount: Integer read FProgramCount;
    property Programs[Index: Integer]: TAVProgram read GetProgrames;

    property AudioStreamCount: Integer read FAudioStreamCount;
    property VideoStreamCount: Integer read FVideoStreamCount;
    property SubtitleStreamCount: Integer read FSubtitleStreamCount;

    property UTF8Metadata: Boolean read FUTF8Metadata write FUTF8Metadata;
    property FileStreamInfo: TFileStreamInfo read GetFileStreamInfo;
    property AudioStreamInfos[Index: Integer]: TAudioStreamInfo read GetAudioStreamInfos;
    property VideoStreamInfos[Index: Integer]: TVideoStreamInfo read GetVideoStreamInfos;
    property SubtitleStreamInfos[Index: Integer]: TSubtitleStreamInfo read GetSubtitleStreamInfos;

    property FileInfoText: string read GetFileInfoText;
    property FirstAudioStreamIndex: Integer read FFirstAudioStreamIndex;
    property FirstVideoStreamIndex: Integer read FFirstVideoStreamIndex;
    property FirstSubtitleStreamIndex: Integer read FFirstSubtitleStreamIndex;
    property FirstAudioStreamInfo: TAudioStreamInfo read GetAudioStreamInfo;
    property FirstVideoStreamInfo: TVideoStreamInfo read GetVideoStreamInfo;
    property FirstSubtitleStreamInfo: TSubtitleStreamInfo read GetSubtitleStreamInfo;

    property LastErrMsg: string read FLastErrMsg;
  published
    property TriggerEventInMainThread: Boolean read FTriggerEventInMainThread
      write FTriggerEventInMainThread default True;
    property OnBeforeFindStreamInfo: TBeforeFindStreamInfoEvent read FOnBeforeFindStreamInfo write FOnBeforeFindStreamInfo;
  end;

  TDecodeType = (dtBoth, dtVideo, dtAudio);
  TDecodeResult = (drVideo, drAudio, drError);

  TFrameInfo = record
    PixFmt: TAVPixelFormat;
    Width: Integer;
    Height: Integer;
    IsKeyFrame: Boolean;
    IsInterlaced: Boolean;
    IsTopFieldFirst: Boolean;
    PictureType: TAVPictureType;
    PTS: Int64;
    OriginalDTS: Int64;
    OriginalPTS: Int64;
    StreamIndex: Integer;
    Position: Int64;
    Ready: Boolean;
    Picture: TAVPicture;
    Buffer: PByte;
    Size: Integer;
    Frame: PAVFrame;
  end;

  // for decoding audio
  TWaveInfo = record
    Channels: Integer;
    SampleRate: Integer;
    SampleFormat: TAVSampleFormat;
    BytesPerSample: Integer;
    BytesPerSecond: Integer;
    PTS: Int64;
    OriginalDTS: Int64;
    OriginalPTS: Int64;
    StreamIndex: Integer;
    Ready: Boolean;
    Buffer: PByte;
    Size: Integer;
    Duration: Int64;
  end;

  TFFDecoder = class(TCustomDecoder)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    procedure CloseFile; override;

    function Seek(const APTS: Int64; ASeekFlags: TSeekFlags = []): Boolean; virtual;
    function Decode(AStreamIndex: Integer = -1): Boolean; overload;
    function Decode(AType: TDecodeType): TDecodeResult; overload;
    function DecodeNextKeyFrame(AStreamIndex: Integer = -1): Boolean;
    function DecodePreviousFrame(AStreamIndex: Integer = -1): Boolean;
    function DecodePreviousKeyFrame(AStreamIndex: Integer = -1): Boolean;
    function CopyToBitmap(ABitmap: TBitmap): Boolean;
{$IFDEF MSWINDOWS}
    function GetBitmapPtr: PBitmap;
{$ENDIF}

    function DecodeAudio(AStreamIndex: Integer = -1): Boolean;
    function ReadAudio(ABuffer: PByte; ACount: Integer; AStreamIndex: Integer = -1): Integer;

{$IFNDEF FFFMX}
    // specifies the number of adjacent color bits on each plane needed to define a pixel.
    // one of (8, 15[555, BI_RGB], 16[565, BI_BITFIELDS], 24, 32), default to 32
    property BitmapBitsPixel: Integer read GetBitmapBitsPixel write SetBitmapBitsPixel;
{$ENDIF}
    property {$IFDEF BCB}IsEOF{$ELSE}EOF{$ENDIF}: Boolean read FEOF;
    property FrameInfo: TFrameInfo read FPicture;
    property Position: Int64 read GetPosition;
    property VideoFilters: string read Fvfilters write Fvfilters;

    property WaveInfo: TWaveInfo read FWaveInfo;
    property DesireAudioChannels: Integer read FDesireAudioChannels write SetDesireAudioChannels;
    property DesireAudioSampleRate: Integer read FDesireAudioSampleRate write SetDesireAudioSampleRate;
    property DesireAudioSampleFormat: TAVSampleFormat read FDesireAudioSampleFormat write SetDesireAudioSampleFormat;
  end;
