{
    Copyright (c) 2012 by Michael Van Canneyt
    member of the Free Pascal development team

    This is a OOP wrapper around the VLC libraries.
    
    See the file COPYING.FPC, included in this distribution,
    for details about the copyright.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 **********************************************************************}
unit vlc;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, ctypes, libvlc, syncobjs;

Type

  { TVLCLibrary }

  TVLCLibrary = class(TComponent)
  private
    FInstance : plibvlc_instance_t;
    FLibraryArgs: TStrings;
    FLibraryPath : String;
    function GetI: Boolean;
    function GetLastError: String;
    Function GetVersion : String;
    Function GetCompiler : String;
    Function GetChangeSet : String;
    Procedure SetLibraryPath(Const AValue : String);
  Protected
    Function GetInstance : plibvlc_instance_t; virtual;
    property Instance : plibvlc_instance_t read GetInstance;
  public
    constructor Create (AOwner : TComponent); override;
    destructor Destroy; override;
    Procedure Initialize;
    Procedure Release;
    property LastError : String read GetLastError;
    property Version : String read GetVersion;
    property Compiler : String read GetCompiler;
    property ChangeSer : String read GetChangeSet;
    property LibraryPath : String read FLibraryPath write SetLibraryPath;
    Property LibraryArgs : TStrings read FLibraryArgs Write FLibraryArgs;
    Property Initialized : Boolean Read GetI;
  end;

  TVLCLibraryClass = Class of TVLCLibrary;

  TCustomVLCMediaPlayer = Class;
  TVLCMediaItems = Class;

  { TVLCMediaItem }
  TSnapShotFormat = (ssfPNG,ssfJPG);
  TDeinterlaceMode   = (dmBlend, dmDiscard, dmBob, dmLinear, dmMean, dmX, dmYadif, dmYadif2x);

  TVLCMediaItem = Class(TCollectionItem)
  private
    FDIM: TDeinterlaceMode;
    FInstance : plibvlc_media_t;
    FOpts : Array [0..3] of Boolean; // Keep in sync with property indexes
    FPath: String;
    FSS: TSNapshotFormat;
    FFD: Integer;
    function GetInstance: plibvlc_media_t;
    function GetM(AIndex: Integer): Boolean;
    function GetMD(AMeta : libvlc_meta_t): String;
    function GetMRL: String;
    function GetParsed: Boolean;
    function GetUD: Pointer;
    procedure SetDIM(AValue: TDeinterlaceMode);
    procedure SetFSS(AValue: TSNapshotFormat);
    procedure SetM(AIndex: Integer; AValue: Boolean);
    Function GetBoolOpt(AIndex : Integer; AValue : Boolean) : String;
    procedure SetMD(AMeta : libvlc_meta_t; AValue: String);
    procedure SetUD(AValue: Pointer);
    function GetState : libvlc_state_t;
    function GetDuration : TDateTime;
  Protected
    Procedure RegisterInstance;
    Procedure UnRegisterInstance;
    procedure SetMRL(AValue: String); virtual;
    procedure SetPath(AValue: String); virtual;
    procedure SetFD(AValue: Integer); virtual;
    Function GetVLC : TVLCLibrary; virtual;
    function GetEventManager : plibvlc_event_manager_t;
    Procedure SetInstance( Avalue : plibvlc_media_t);
    Property Instance : plibvlc_media_t Read GetInstance;
  Public
    Destructor Destroy; override;
    Procedure AddOption(Const AValue : String);
    procedure Parse;
    procedure ParseAsync;
    Procedure SaveMetaData;
    Function GetStats(Var AStats : libvlc_media_stats_t) : Boolean;
    Function Duplicate : TVLCMediaItem;
    Property Parsed : Boolean Read GetParsed;
    Property ShowTitle : Boolean Index 0 Read GetM Write SetM;
    Property VideoOnTop : Boolean Index 1 Read GetM Write SetM;
    Property UseOverlay : Boolean Index 2 Read GetM Write SetM;
    Property FullScreen : Boolean Index 3 Read GetM Write SetM;
    Property DeinterlaceFilter : Boolean Index 4 Read GetM Write SetM;
    Property DeInterlaceMode : TDeinterlaceMode Read FDIM Write SetDIM;
    Property SnapShotFormat : TSNapshotFormat Read FSS Write SetFSS;
    Property UserData : Pointer Read GetUD Write SetUD;
    Property State :  libvlc_state_t Read GetState;
    Property Duration : TDateTime Read GetDuration;
    Property MetaData[AMeta : libvlc_meta_t] : String Read GetMD Write SetMD;
    // These must be set prior to using any of the above.
    Property MRL : String Read GetMRL Write SetMRL;
    Property Path : String Read FPath Write SetPath;
    property FileDescriptor : Integer Read FFD Write SetFD;
  end;

  TVLCMediaItemClass = Class of TVLCMediaItem;

  { TVLCMediaItems }
  TVLCPlayMode = (pmNormal,pmLoop,pmRepeat);

  TVLCMediaItems = Class(TCollection)
  Private
    FPlayer: TCustomVLCMediaPlayer;
    FPlayMode: TVLCPlayMode;
    FVLC : TVLCLibrary;
    FInstance : Plibvlc_media_list_t;
    function GetI(AIndex : Integer): TVLCMediaItem;
    function GetInstance: Plibvlc_media_list_t;
    function GetIsReadOnly: Boolean;
    procedure SetI(AIndex : Integer; AValue: TVLCMediaItem);
  Protected
    Function GetVLC : TVLCLibrary; virtual;
  Public
    Constructor Create(ALibrary : TVLCLibrary;AItemClass: TVLCMediaItemClass = Nil); overload;
    Constructor Create(AInstance : Plibvlc_media_list_t;AItemClass: TVLCMediaItemClass = Nil); overload;
    Procedure Lock;
    Procedure Unlock;
    Property Instance : Plibvlc_media_list_t read GetInstance;
    Property VLC : TVLCLibrary Read GetVLC Write FVLC;
    Property MediaItems[AIndex : Integer] : TVLCMediaItem Read GetI Write SetI; default;
    Property ReadOnly : Boolean Read GetIsReadOnly;
  end;

  { TCustomVLCMediaPlayer }
  TBooleanEvent = procedure(Sender : TObject; Const AValue : Boolean) of object;
  TTitleEvent = procedure(Sender : TObject; Const ATitle : Integer) of object;
  TSnapshotEvent = procedure(Sender : TObject; Const AfileName : string) of object;
  TErrorEvent = procedure(Sender : TObject; Const AError : string) of object;
  TTimeEvent = procedure(Sender : TObject; Const time : TDateTime) of object;
  TPositionEvent = procedure(Sender : TObject; Const APos : Double)  of object;

  TCustomVLCMediaPlayer = Class(TComponent)
  private
    FFitWindow: Boolean;
    FOnBackward: TNotifyEvent;
    FOnBuffering: TNotifyEvent;
    FOnEOF: TNotifyEvent;
    FOnError: TErrorEvent;
    FOnForward: TNotifyEvent;
    FOnLengthChanged: TTimeEvent;
    FOnMediaChanged: TNotifyEvent;
    FOnNothingSpecial: TNotifyEvent;
    FOnOpening: TNotifyEvent;
    FOnPausableChanged: TBooleanEvent;
    FOnPause: TNotifyEvent;
    FOnPlaying: TNotifyEvent;
    FOnPositionChanged: TPositionEvent;
    FOnSeekableChanged: TBooleanEvent;
    FOnSnapShot: TSnapShotEvent;
    FOnStop: TNotifyEvent;
    FOnTimeChanged: TTimeEvent;
    FOnTitleChanged: TTitleEvent;
    FUseEvents: Boolean;
    Finstance : Plibvlc_media_player_t;
    FVLC: TVLCLibrary;
    FECS : TCriticalSection;
    function GetAspectRatio: String;
    function GetAudioMuted: Boolean;
    function GetAudioTrack: Integer;
    function GetState: libvlc_state_t;
    function GetVideoDuration: TDateTime;
    function GetVideoFPS: Double;
    function GetVideoFractional: Double;
    function GetVideoHeight: Cardinal;
    function GetVideoLength: Int64;
    function GetVideoPos: Int64;
    function GetVideoScale: Double;
    function GetVideoWidth: Cardinal;
    function GetVLC: TVLCLibrary;
    procedure SetAspectRatio(AValue: String);
    procedure SetAudioMuted(AValue: Boolean);
    procedure SetFitWindow(AValue: Boolean);
    procedure SetUseEVents(AValue: Boolean);
    function GetAudioTrackCount : Integer;
    procedure SetAudioTrack(AValue: Integer);
    function GetAudioTrackDescriptions(AIndex : Integer) : String;
    function GetChannel: Integer;
    procedure SetChannel(AValue : Integer);
    function GetAudioDelay : Int64;
    procedure SetAudioDelay (AValue: Int64);
    function GetPlaying : Boolean;
    function GetChapter : Integer;
    procedure SetChapter(AValue : Integer);
    function GetChapterCount: Integer;
    Function GetPlayable : Boolean;
    Function GetPausable : Boolean;
    Function GetSeekable : Boolean;
    function GetAudioVolume : Integer;
    function GetPlayRate: Integer;
    procedure SetAudioVolume(AValue : Integer);
    procedure SetPlayRate(AValue: Integer);
    procedure SetFullScreenMode(AValue: Boolean);
    function  GetFullScreenMode: Boolean;
    procedure SetVideoFractional(AValue: Double);
    procedure SetVideoPos(AValue: Int64);
    procedure SetVideoScale(AValue: Double);
  Protected
    function GetInstance: Plibvlc_media_player_t; virtual;
    // Called to set parent window. Descendents must override this.
    Procedure SetParentWindow; virtual;
    // Called when FitWindow is true.
    Procedure SetParentWindowSize(AWidth,AHeight : Cardinal); Virtual;
    procedure DoMediaChanged; virtual;
    procedure DoNothingSpecial; virtual;
    procedure DoOnBackward; virtual;
    procedure DoOnBuffering;virtual;
    procedure DoOnEOF;virtual;
    procedure DoOnError;virtual;
    procedure DoOnForward;virtual;
    procedure DoOnOpening;virtual;
    procedure DoOnPause;virtual;
    procedure DoOnPlaying;virtual;
    procedure DoOnStop;virtual;
    procedure DoOnLengthChanged(const ATime: libvlc_time_t); virtual;
    procedure DoOnPausableChanged(const APausable: Boolean); virtual;
    procedure DoOnPositionChanged(const Aposition: Double); virtual;
    procedure DoOnSeekableChanged(const ASeekable: Boolean); virtual;
    procedure DoOnTimeChanged(const ATime: libvlc_time_t); virtual;
    procedure DoOnTitleChanged(const ATitle: cint); virtual;
    procedure DoOnSnapshot(const AFileName: PCChar); virtual;
    procedure HookupEvents; virtual;
    procedure UnHookEvents; virtual;
    procedure HandleVLCEvent(e: Plibvlc_event_t); virtual;
    Property VLC : TVLCLibrary Read GetVLC Write FVLC;
    Property Instance : Plibvlc_media_player_t Read GetInstance;
  Public
    Destructor Destroy; override;
    procedure Play;
    procedure SetMedia(M: TVLCMediaItem);
    Procedure Play(M : TVLCMediaItem);
    Procedure PlayFile(Const AFileName : String);
    Procedure Stop;
    procedure Pause;
    procedure Resume;
    procedure NextFrame;
    function Snapshot(Const AFileName: String): Boolean;
    function Snapshot(Const AFileName: String; AWidth, AHeight: Cardinal): Boolean;
    function GetVideoSize(Var AWidth, AHeight: Cardinal): Boolean;
  // These can be made public/published in descendents
  Protected
    Property Playable : Boolean Read GetPlayable;
    Property Pausable : Boolean Read GetPausable;
    Property Seekable : Boolean Read GetSeekable;
    Property Playing : Boolean Read GetPlaying;
    Property State : libvlc_state_t Read GetState;
    Property AudioTrackDescriptions [AIndex : Integer] : String Read GetAudioTrackDescriptions;
    Property ChapterCount : Integer Read GetChapterCount;
    Property AudioTrackCount : Integer Read GetAudioTrackCount;
    Property AudioTrack : Integer Read GetAudioTrack Write SetAudioTrack;
    Property AudioDelay : Int64 Read GetAudioDelay Write SetAudioDelay;
    Property AudioVolume : Integer Read GetAudioVolume Write SetAudioVolume;
    Property AudioMuted : Boolean Read GetAudioMuted Write SetAudioMuted;
    Property FitWindow : Boolean Read FFitWindow Write SetFitWindow;
    Property VideoWidth : Cardinal Read GetVideoWidth;
    Property VideoHeight : Cardinal Read GetVideoHeight;
    // In MS.
    Property VideoLength : Int64 Read GetVideoLength;
    Property VideoDuration : TDateTime Read GetVideoDuration;
    // In MS
    Property VideoPosition : Int64 Read GetVideoPos Write SetVideoPos;
    Property VideoFractionalPosition : Double Read GetVideoFractional Write SetVideoFractional;
    Property VideoFramesPerSecond : Double Read GetVideoFPS;
    Property VideoScale : Double Read GetVideoScale Write SetVideoScale;
    Property AspectRatio : String Read GetAspectRatio Write SetAspectRatio;
    Property Channel : Integer Read GetChannel Write SetChannel;
    Property Chapter : Integer Read GetChapter Write SetChapter;
    Property FullScreenMode : Boolean Read GetFullScreenMode Write SetFullScreenMode;
    Property UseEvents : Boolean Read FUseEvents Write SetUseEVents;
    // Events from VLC player
    Property OnMediaChanged : TNotifyEvent Read FOnMediaChanged Write FOnMediaChanged;
    Property OnNothingSpecial : TNotifyEvent Read FOnNothingSpecial Write FOnNothingSpecial;
    Property OnBackward : TNotifyEvent Read FOnBackward Write FOnBackward;
    Property OnBuffering : TNotifyEvent Read FOnBuffering Write FOnBuffering;
    Property OnEOF : TNotifyEvent Read FOnEOF Write FOnEOF;
    Property OnError : TErrorEvent Read FOnError Write FOnError;
    Property OnForward : TNotifyEvent Read FOnForward Write FOnForward;
    Property OnOpening : TNotifyEvent Read FOnOpening Write FOnOpening;
    Property OnPause : TNotifyEvent Read FOnPause Write FOnPause;
    Property OnPlaying : TNotifyEvent Read FOnPlaying Write FOnPlaying;
    Property OnStop : TNotifyEvent Read FOnStop Write FOnStop;
    Property OnLengthChanged : TTimeEvent Read FOnLengthChanged Write FOnLengthChanged;
    Property OnTimeChanged : TTimeEvent Read FOnTimeChanged Write FOnTimeChanged;
    Property OnPausableChanged : TBooleanEvent Read FOnPausableChanged Write FOnPausableChanged;
    Property OnPositionChanged : TPositionEvent Read FOnPositionChanged Write FOnPositionChanged;
    Property OnSeekableChanged : TBooleanEvent Read FOnSeekableChanged Write FOnSeekableChanged;
    Property OnTitleChanged : TTitleEvent Read FOnTitleChanged Write FOnTitleChanged;
    Property OnSnapshot : TSnapShotEvent Read FOnSnapShot Write FOnSnapShot;
  end;

  EVLC = Class(Exception);

  TVLCMediaPlayer = Class(TCustomVLCMediaPlayer)
  Public
    Property Playable ;
    Property Pausable ;
    Property Seekable ;
    Property PLaying ;
    Property State ;
    Property AudioTrackDescriptions;
    Property ChapterCount ;
    Property AudioTrackCount ;
    Property AudioTrack ;
    Property VideoWidth ;
    Property VideoHeight;
    Property VideoLength;
    Property VideoDuration ;
    Property VideoPosition ;
    Property VideoFractionalPosition ;
    Property VideoFramesPerSecond;
    Property VideoScale;
    Property AspectRatio;
  Published
    Property AudioDelay ;
    Property AudioVolume ;
    Property AudioMuted ;
    Property Channel ;
    Property Chapter ;
    Property FitWindow;
    Property FullScreenMode ;
    Property UseEvents ;
    Property OnMediaChanged ;
    Property OnNothingSpecial ;
    Property OnBackward ;
    Property OnBuffering ;
    Property OnEOF ;
    Property OnError ;
    Property OnForward ;
    Property OnOpening ;
    Property OnPause ;
    Property OnPlaying ;
    Property OnStop ;
    Property OnLengthChanged ;
    Property OnTimeChanged ;
    Property OnPausableChanged ;
    Property OnPositionChanged ;
    Property OnSeekableChanged ;
    Property OnTitleChanged ;
    Property OnSnapshot ;
  end;

  { TCustomVLCMediaListPlayer }

  TCustomVLCMediaListPlayer = Class(TComponent)
  Private
    FMediaItems: TVLCMediaItems;
    FPlayer: TCustomVLCMediaPlayer;
    FPlayMode: TVLCPlayMode;
    FInstance : plibvlc_media_list_player_t;
    FVLC: TVLCLibrary;
    function GetInstance: plibvlc_media_list_player_t;
    function  GetPlaying : Boolean;
    function  GetState: libvlc_state_t;
    function GetVLC: TVLCLibrary;
    procedure SetMediaItems(AValue: TVLCMediaItems);
    procedure SetPlayer(AValue: TCustomVLCMediaPlayer); virtual;
    procedure SetPlayMode(AValue: TVLCPlayMode);
  Protected
    Function CreateMediaItems : TVLCMediaItems; virtual;
    Property Instance : plibvlc_media_list_player_t Read GetInstance;
    Property Player : TCustomVLCMediaPlayer Read FPlayer write SetPlayer;
    Property PlayMode : TVLCPlayMode read FPlayMode write SetPlayMode;
    Property Playing : Boolean Read GetPLaying;
    Property State : libvlc_state_t Read GetState;
    Property MediaItems : TVLCMediaItems Read FMediaItems Write SetMediaItems;
    Property VLC : TVLCLibrary Read GetVLC Write FVLC;
  Public
    Constructor Create(AOwner : TComponent); override;
    Destructor Destroy; override;
    procedure Play(Item : TVLCMediaItem);
    procedure Play;
    procedure Pause;
    procedure Stop;
    procedure Next;
    procedure Prev;
  end;

  TVLCMediaListPlayer = Class(TCustomVLCMediaListPlayer)
  Public
    Property VLC;
  Published
    Property Player;
    Property PlayMode;
    Property Playing;
    Property State;
    Property MediaItems;
  end;

Function VLCLibrary  : TVLCLibrary;

Var
  VLCLibraryClass : TVLCLibraryClass = TVLCLibrary;

Function VLCTimeToDateTime (T : libvlc_time_t) : TDateTime;

implementation

{ TVLCLibrary }
Var
  LVLC : TVLCLibrary;

Function VLCLibrary  : TVLCLibrary;

begin
  If LVLC=Nil then
    LVLC:=VLCLibraryClass.Create(Nil);
  Result:=LVLC;
end;

Procedure DoneVLC;

begin
  If Assigned(LVLC) then
    FreeAndNil(LVLC);
end;

Function VLCTimeToDateTime (T : libvlc_time_t) : TDateTime;

  Function MD(Var MS : libvlc_time_t; D : Integer) : Word;  inline;

  begin
    Result:=MS Mod D;
    MS:=MS div D;
  end;

var
  d,h,m,s,ms: word;

begin
  ms:=MD(T,1000);
  s:=MD(T,60);
  m:=MD(T,60);
  h:=MD(T,24);
  d:=T;
  Result:=D+EncodeTime(h,m,s,ms);
end;

procedure PlayerEventHelper(event: Plibvlc_event_t; data: Pointer); cdecl;

begin
  if Not Assigned(data) then
    exit;
  TCustomVLCMediaPlayer(data).HandleVLCEvent(event);
end;

{ TCustomVLCMediaListPlayer }

function TCustomVLCMediaListPlayer.GetPlaying: Boolean;
begin
  Result:=libvlc_media_list_player_is_playing(Instance)<>0;
end;

function TCustomVLCMediaListPlayer.GetInstance: plibvlc_media_list_player_t;
begin
  if (FInstance=Nil) then
    begin
    Finstance:=libvlc_media_list_player_new(VLC.Instance);
    if Assigned(MediaItems) then
      begin
      libvlc_media_list_player_set_media_list(FInstance,MediaItems.Instance);
      end;
    If Assigned(FPlayer) then
      begin
      libvlc_media_list_player_set_media_player(FInstance, FPlayer.Instance);
      end;
    end;
  Result:=FInstance;
end;

function TCustomVLCMediaListPlayer.GetState: libvlc_state_t;
begin
  Result:=libvlc_media_list_player_get_state(Instance)
end;

function TCustomVLCMediaListPlayer.GetVLC: TVLCLibrary;
begin
  Result:=FVLC;
  If Result=Nil then
    Result:=VLCLibrary;
end;

procedure TCustomVLCMediaListPlayer.Play(Item: TVLCMediaItem);
begin
  libvlc_media_list_player_play_item(Instance, item.Instance);
end;

procedure TCustomVLCMediaListPlayer.SetMediaItems(AValue: TVLCMediaItems);
begin
  if FMediaItems=AValue then Exit;
  FMediaItems.Assign(AValue);
end;

procedure TCustomVLCMediaListPlayer.SetPlayer(AValue: TCustomVLCMediaPlayer);
begin
  if FPlayer=AValue then Exit;
  FPlayer:=AValue;
  If Assigned(FInstance) then
    begin
    libvlc_media_list_player_set_media_player(FInstance, FPlayer.Instance);
    end;
end;

procedure TCustomVLCMediaListPlayer.SetPlayMode(AValue: TVLCPlayMode);
Const
  M : Array  [TVLCPlayMode] of libvlc_playback_mode_t
    = (libvlc_playback_mode_default,
       libvlc_playback_mode_loop,
       libvlc_playback_mode_repeat);

begin
  if FPlayMode=AValue then Exit;
  FPlayMode:=AValue;
  libvlc_media_list_player_set_playback_mode(FInstance, M[AValue]);
end;

function TCustomVLCMediaListPlayer.CreateMediaItems: TVLCMediaItems;
begin
  Result:=TVLCMediaItems.Create(TVLCMediaItem);
end;

constructor TCustomVLCMediaListPlayer.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FMediaItems:=CreateMediaItems;
end;

destructor TCustomVLCMediaListPlayer.Destroy;
begin
  If Assigned(Finstance) then
    libvlc_media_list_player_release(FInstance);
  FreeAndNil(FMediaItems);
  inherited Destroy;
end;

procedure TCustomVLCMediaListPlayer.Play;
begin
  libvlc_media_list_player_play(Instance);
end;

procedure TCustomVLCMediaListPlayer.Pause;
begin
  libvlc_media_list_player_pause(Instance);
end;

procedure TCustomVLCMediaListPlayer.Stop;
begin
  libvlc_media_list_player_stop(Instance);
end;

procedure TCustomVLCMediaListPlayer.Next;
begin
  libvlc_media_list_player_next(Instance);
end;

procedure TCustomVLCMediaListPlayer.Prev;
begin
  libvlc_media_list_player_previous(Instance);
end;


{ TCustomVLCMediaPlayer }

function TCustomVLCMediaPlayer.GetVLC: TVLCLibrary;
begin
  Result:=FVLC;
  if Result=Nil then
    Result:=VLCLibrary;
end;

procedure TCustomVLCMediaPlayer.SetAspectRatio(AValue: String);

begin
  libvlc_video_set_aspect_ratio(Instance,Pcchar(PChar(AValue)));
end;

function TCustomVLCMediaPlayer.GetAudioMuted: Boolean;
begin
  if Assigned(Finstance) then
    Result:=libvlc_audio_get_mute(instance)<>0
  else
    Result:=False;
end;

function TCustomVLCMediaPlayer.GetAspectRatio: String;

Var
  P : Pcchar;

begin
  P:=libvlc_video_get_aspect_ratio(Instance);
  if (P<>Nil) then
    Result:=StrPas(PChar(P))
  else
    Result:='';
end;

function TCustomVLCMediaPlayer.GetAudioTrack: Integer;
begin
  if Assigned(FInstance) then
    Result := libvlc_audio_get_track(FINstance)
  else
    Result:=-1;
end;

function TCustomVLCMediaPlayer.GetState: libvlc_state_t;
begin
  If Assigned(FInstance) then
    Result:=libvlc_media_player_get_state(FInstance)
  else
    Result:=libvlc_NothingSpecial;
end;

function TCustomVLCMediaPlayer.GetVideoDuration: TDateTime;
begin
  Result:=VLCTimeToDateTime(GetVideoLength);
end;

function TCustomVLCMediaPlayer.GetVideoFPS: Double;
begin
  Result:=libvlc_media_player_get_fps(FInstance);
end;

function TCustomVLCMediaPlayer.GetVideoFractional: Double;
begin
  Result:=libvlc_media_player_get_Position(FInstance);
end;

function TCustomVLCMediaPlayer.GetVideoHeight: Cardinal;
begin
  Result:=libvlc_video_get_height(FInstance);
end;

function TCustomVLCMediaPlayer.GetVideoLength: Int64;
begin
  Result:=libvlc_media_player_get_length(Finstance);
end;

function TCustomVLCMediaPlayer.GetVideoPos: Int64;
begin
  Result:=libvlc_media_player_get_time(FInstance);
end;

function TCustomVLCMediaPlayer.GetVideoScale: Double;
begin
  Result:=libvlc_video_get_scale(Finstance);
end;

function TCustomVLCMediaPlayer.GetVideoWidth: Cardinal;
begin
  Result:=libvlc_video_get_width(FInstance);
end;


procedure TCustomVLCMediaPlayer.SetAudioMuted(AValue: Boolean);
begin
  libvlc_audio_set_mute(instance, ord(AValue));
end;

procedure TCustomVLCMediaPlayer.SetFitWindow(AValue: Boolean);

Var
  W,H : Cardinal;

begin
  if FFitWindow=AValue then Exit;
  FFitWindow:=AValue;
  If FFitWindow and Playing then
    begin
    if GetVideoSize(W,H) then
      SetParentWindowSize(W,H);
    end;
end;

procedure TCustomVLCMediaPlayer.SetUseEVents(AValue: Boolean);
begin
  if FUseEvents=AValue then Exit;
  FUseEvents:=AValue;
  If Assigned(Finstance) then
    If AValue then
      HookupEvents
    else
      UnhookEvents;
end;

function TCustomVLCMediaPlayer.GetAudioTrackCount: Integer;
begin
  if Assigned(FInstance) then
    Result := libvlc_audio_get_track_count(FINstance)
  else
    Result:=-1;
end;


procedure TCustomVLCMediaPlayer.SetAudioTrack(AValue: Integer);
begin
  if Assigned(FInstance) then
    begin
    if (AValue<0) then
      AValue:=0;
    libvlc_audio_set_track(FInstance,AValue);
    end;
end;

function TCustomVLCMediaPlayer.GetAudioTrackDescriptions(AIndex: Integer): String;

var
  t : plibvlc_track_description_t;

begin
  Result := '';
  If (AIndex>=0) And Assigned(FInstance) then
    begin
    T:=libvlc_audio_get_track_description(Finstance);
    while (AIndex>0) and Assigned(t) do
      begin
      Dec(Aindex);
      t:=t^.p_next;
      end;
    If Assigned(t) and Assigned(t^.psz_name) then
      Result:=StrPas(PChar(t^.psz_name));
    end;
end;

function TCustomVLCMediaPlayer.GetChannel: Integer;
begin
  If Assigned(Finstance) then
    Result:=libvlc_audio_get_channel(FInstance)
 else
   Result:=-1;
end;

procedure TCustomVLCMediaPlayer.SetChannel(AValue: Integer);
begin
  If Assigned(Finstance) then
    libvlc_audio_set_channel(Finstance,AValue)
end;

function TCustomVLCMediaPlayer.GetAudioDelay: Int64;
begin
  if Assigned(FInstance) then
    Result:=libvlc_audio_get_delay(FInstance)
  else
    Result:=-1;
end;

procedure TCustomVLCMediaPlayer.SetAudioDelay(AValue: Int64);
begin
  if Assigned(FInstance) then
    libvlc_audio_set_delay(FInstance,AValue)
end;

function TCustomVLCMediaPlayer.GetPlaying: Boolean;
begin
  Result:=(State=libvlc_Playing);
end;

function TCustomVLCMediaPlayer.GetChapter: Integer;
begin
  if Assigned(FInstance) then
    Result:=libvlc_media_player_get_chapter(FInstance)
  else
    Result:=-1;
end;

procedure TCustomVLCMediaPlayer.SetChapter(AValue: Integer);
begin
  if Assigned(FInstance) then
    libvlc_media_player_set_chapter(FInstance,AValue);
end;

function TCustomVLCMediaPlayer.GetChapterCount: Integer;
begin
  if Assigned(FInstance) then
    Result:=libvlc_media_player_get_chapter_count(FInstance)
  else
    Result:=-1;
end;

function TCustomVLCMediaPlayer.GetPlayable: Boolean;
begin
  if Assigned(FInstance) then
    Result:=(libvlc_media_player_will_play(FInstance)<>0)
  else
    Result:=False
end;

function TCustomVLCMediaPlayer.GetPausable: Boolean;
begin
  if Assigned(FInstance) then
    Result:=(libvlc_media_player_can_pause(FInstance)<>0)
  else
    Result:=False
end;

function TCustomVLCMediaPlayer.GetSeekable: Boolean;
begin
  if Assigned(FInstance) then
    Result:=(libvlc_media_player_is_seekable(FInstance)<>0)
  else
    Result:=False
end;

function TCustomVLCMediaPlayer.GetAudioVolume: Integer;
begin
  if Assigned(FInstance) then
    Result:=libvlc_audio_get_volume(FInstance)
  else
    Result:=-1
end;

procedure TCustomVLCMediaPlayer.SetAudioVolume(AValue: Integer);
begin
  if Assigned(FInstance) then
    begin
    if (AValue<0) then
      AValue:=0
    else if (AValue>200) then
      AValue:=200;
    libvlc_audio_set_volume(Finstance,AValue);
    end;
end;

procedure TCustomVLCMediaPlayer.SetPlayRate(Avalue : Integer);
begin
  if Assigned(FInstance) then
    begin
    if (Avalue< 1) then
       AValue:=1
    else if (AValue>1000) then
      AValue:=1000;
    libvlc_media_player_set_rate(FInstance,AValue/100);
    end;
end;

function TCustomVLCMediaPlayer.GetPlayRate: Integer;
begin
  if Assigned(FInstance) then
    Result:=Round(libvlc_media_player_get_rate(FInstance)*100)
  else
    Result:=-1;
end;

procedure TCustomVLCMediaPlayer.SetFullScreenMode(AValue: Boolean);
begin
  if Assigned(FInstance) then
    libvlc_set_fullscreen(Finstance,Ord(AValue));
end;

function TCustomVLCMediaPlayer.GetFullScreenMode: Boolean;
begin
  If Assigned(FInstance) then
    Result:=libvlc_get_fullscreen(Finstance)<>0
  else
    Result:=False;
end;

procedure TCustomVLCMediaPlayer.SetVideoFractional(AValue: Double);
begin
  libvlc_media_player_set_position(FInstance,AValue);
end;

procedure TCustomVLCMediaPlayer.SetVideoPos(AValue: Int64);
begin
  libvlc_media_player_set_time(FInstance,AVAlue);
end;

procedure TCustomVLCMediaPlayer.SetVideoScale(AValue: Double);
begin
  libvlc_video_set_scale(Finstance,AVAlue);
end;

function TCustomVLCMediaPlayer.GetInstance: Plibvlc_media_player_t;
begin
  Result:=FInstance;
  if (FInstance=Nil) then
    begin
    FInstance:=libvlc_media_player_new(VLC.Instance);
    libvlc_video_set_mouse_input(FInstance,1);
    libvlc_video_set_key_input(FInstance,1);
    if FUseEvents then
      HookupEvents;
    end;
  Result:=FInstance;
end;

procedure TCustomVLCMediaPlayer.SetParentWindow;
begin
  // Do nothing
end;

procedure TCustomVLCMediaPlayer.SetParentWindowSize(AWidth, AHeight: Cardinal);
begin
  // Do nothing
end;

Procedure TCustomVLCMediaPlayer.UnHookEvents;


  Procedure ClearEvent(M : plibvlc_event_manager_t;t : libvlc_event_e);

  begin
    libvlc_event_detach(M,ord(t),@PlayerEventHelper,Self);
  end;

Var
  M : plibvlc_event_manager_t;

begin
  M:=libvlc_media_player_event_manager(Instance);
  if (M<>Nil) then
    begin
    ClearEvent(M,libvlc_MediaPlayerMediaChanged);
    ClearEvent(M,libvlc_MediaPlayerNothingSpecial);
    ClearEvent(M,libvlc_MediaPlayerOpening);
    ClearEvent(M,libvlc_MediaPlayerBuffering);
    ClearEvent(M,libvlc_MediaPlayerPlaying);
    ClearEvent(M,libvlc_MediaPlayerPaused);
    ClearEvent(M,libvlc_MediaPlayerStopped);
    ClearEvent(M,libvlc_MediaPlayerForward);
    ClearEvent(M,libvlc_MediaPlayerBackward);
    ClearEvent(M,libvlc_MediaPlayerEndReached);
    ClearEvent(M,libvlc_MediaPlayerEncounteredError);
    ClearEvent(M,libvlc_MediaPlayerTimeChanged);
    ClearEvent(M,libvlc_MediaPlayerPositionChanged);
    ClearEvent(M,libvlc_MediaPlayerSeekableChanged);
    ClearEvent(M,libvlc_MediaPlayerPausableChanged);
    ClearEvent(M,libvlc_MediaPlayerTitleChanged);
    ClearEvent(M,libvlc_MediaPlayerSnapshotTaken);
    ClearEvent(M,libvlc_MediaPlayerLengthChanged);
    FreeAndNil(FECS);
    end;
end;

Procedure TCustomVLCMediaPlayer.HookupEvents;

  Procedure AttachEvent( M : plibvlc_event_manager_t;t : libvlc_event_e);

  begin
    libvlc_event_attach(M,ord(t),@PlayerEventHelper,Self);
  end;

Var
  M : plibvlc_event_manager_t;

begin
  M:=libvlc_media_player_event_manager(Instance);
  if (M<>Nil) then
    begin
    FECS:=TCriticalSection.Create;
    AttachEvent(M,libvlc_MediaPlayerMediaChanged);
    AttachEvent(M,libvlc_MediaPlayerNothingSpecial);
    AttachEvent(M,libvlc_MediaPlayerOpening);
    AttachEvent(M,libvlc_MediaPlayerBuffering);
    AttachEvent(M,libvlc_MediaPlayerPlaying);
    AttachEvent(M,libvlc_MediaPlayerPaused);
    AttachEvent(M,libvlc_MediaPlayerStopped);
    AttachEvent(M,libvlc_MediaPlayerForward);
    AttachEvent(M,libvlc_MediaPlayerBackward);
    AttachEvent(M,libvlc_MediaPlayerEndReached);
    AttachEvent(M,libvlc_MediaPlayerEncounteredError);
    AttachEvent(M,libvlc_MediaPlayerTimeChanged);
    AttachEvent(M,libvlc_MediaPlayerPositionChanged);
    AttachEvent(M,libvlc_MediaPlayerSeekableChanged);
    AttachEvent(M,libvlc_MediaPlayerPausableChanged);
    AttachEvent(M,libvlc_MediaPlayerTitleChanged);
    AttachEvent(M,libvlc_MediaPlayerSnapshotTaken);
    AttachEvent(M,libvlc_MediaPlayerLengthChanged);
    end;
end;

procedure TCustomVLCMediaPlayer.DoMediaChanged;

begin
  If Assigned(FOnMediaChanged) then
    FOnMediaChanged(Self);
end;

procedure TCustomVLCMediaPlayer.DoNothingSpecial;

begin
  If Assigned(FOnNothingSpecial) then
    FOnNothingSpecial(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnOpening;

begin
  If Assigned(FOnOpening) then
    FOnOpening(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnPlaying;

begin
  If Assigned(FOnPlaying) then
    FOnPlaying(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnPause;

begin
  If Assigned(FOnPause) then
    FOnPause(Self);
end;


procedure TCustomVLCMediaPlayer.DoOnStop;

begin
  If Assigned(FOnStop) then
    FOnStop(Self);
end;


procedure TCustomVLCMediaPlayer.DoOnForward;

begin
  If Assigned(FOnForward) then
    FOnForward(Self);
end;


procedure TCustomVLCMediaPlayer.DoOnBackward;

begin
  If Assigned(FOnBackward) then
    FOnBackward(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnEOF;

begin
  If Assigned(FOnEOF) then
    FOnEOF(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnBuffering;

begin
  If Assigned(FOnBuffering) then
    FOnBuffering(Self);
end;

procedure TCustomVLCMediaPlayer.DoOnError;

Var
  P : pcchar;
  E : String;
begin
  p:=libvlc_errmsg();
  if p<>Nil then
    E:=StrPas(PChar(P))
  else
    E:='';
  If Assigned(FOnError) then
    FOnError(Self,E);
end;

procedure TCustomVLCMediaPlayer.DoOnTimeChanged(Const ATime: libvlc_time_t);

begin
  If Assigned(FOnTimeChanged) then
    FOnTimeChanged(Self,VLCTimeToDateTime(ATime));
end;

procedure TCustomVLCMediaPlayer.DoOnPositionChanged(Const Aposition: Double);

begin
  If Assigned(FOnPositionChanged) then
    FOnPositionChanged(Self,APosition);
end;


procedure TCustomVLCMediaPlayer.DoOnSeekableChanged(Const ASeekable : Boolean);

begin
  If Assigned(FOnSeekableChanged) then
    FOnSeekableChanged(Self,ASeekable);
end;

procedure TCustomVLCMediaPlayer.DoOnPausableChanged(Const APausable : Boolean);

begin
  If Assigned(FOnPausableChanged) then
    FOnPausableChanged(Self,APausable);
end;

procedure TCustomVLCMediaPlayer.DoOnTitleChanged(Const ATitle: cint);

begin
  If Assigned(FOnTitleChanged) then
    FOnTitleChanged(Self,ATitle);
end;

procedure TCustomVLCMediaPlayer.DoOnSnapshot(Const AFileName : PCChar);

Var
  S :String;

begin
  If Assigned(FOnSnapshot) then
    begin
    if Assigned(AFileName) then
      S:=StrPas(PChar(AFileName))
    else
      S:='';
    FOnSnapShot(Self,S);
    end;
end;

procedure TCustomVLCMediaPlayer.DoOnLengthChanged(Const ATime: libvlc_time_t);

begin
  If Assigned(FOnLengtHChanged) then
    FOnLengtHChanged(Self,VLCTimeToDateTime(ATime));
end;



procedure TCustomVLCMediaPlayer.HandleVLCEvent(e: Plibvlc_event_t);

begin
  FECS.Enter;
  try
    case libvlc_event_e(e^._type) of
      libvlc_MediaPlayerMediaChanged     : DoMediaChanged;
      libvlc_MediaPlayerNothingSpecial   : DoNothingSpecial;
      libvlc_MediaPlayerOpening          : DoOnOpening;
      libvlc_MediaPlayerBuffering        : DoOnBuffering;
      libvlc_MediaPlayerPlaying          : DoOnPlaying;
      libvlc_MediaPlayerPaused           : DoOnPause;
      libvlc_MediaPlayerStopped          : DoOnStop;
      libvlc_MediaPlayerForward          : DoOnForward;
      libvlc_MediaPlayerBackward         : DoOnBackward;
      libvlc_MediaPlayerEndReached       : DoOnEOF;
      libvlc_MediaPlayerEncounteredError : DoOnError;
      libvlc_MediaPlayerTimeChanged      : begin
                                           DoOnTimeChanged(e^.media_player_time_changed.new_time);
                                           end;
      libvlc_MediaPlayerPositionChanged  : begin
                                           DoOnPositionChanged(e^.media_player_position_changed.new_position);
      end;
      libvlc_MediaPlayerSeekableChanged  : begin
                                           DoOnSeekableChanged(e^.media_player_seekable_changed.new_seekable<>0);
      end;
      libvlc_MediaPlayerPausableChanged  : begin
                                           DoOnPausableChanged(e^.media_player_pausable_changed.new_pausable<>0) ;
      end;
      libvlc_MediaPlayerTitleChanged     : begin
                                           DoOnTitleChanged(e^.media_player_title_changed.new_title);
      end;
      libvlc_MediaPlayerSnapshotTaken    : begin
                                           DoOnSnapShot(e^.media_player_snapshot_taken.psz_filename);
      end;
      libvlc_MediaPlayerLengthChanged    : begin
                                           DoOnLengthChanged(e^.media_player_length_changed.new_length);
      end;
    else
      // Not sure what to do here. 
      // Writeln('Unknown event type ',e^._type);
    end;
  finally
    FECS.Leave;
  end;
end;

destructor TCustomVLCMediaPlayer.Destroy;
begin
  If Assigned(FInstance) then
    begin
    libvlc_media_player_release(FInstance);
    FInstance:=Nil;
    end;
  FreeAndNil(FECS);
  inherited Destroy;
end;

procedure TCustomVLCMediaPlayer.SetMedia(M: TVLCMediaItem);

begin
  libvlc_media_player_set_media(Instance,M.Instance);
end;

procedure TCustomVLCMediaPlayer.Play;

Var
  W,H : Cardinal;

begin
  SetParentWindow;
  libvlc_media_player_play(Instance);
  If FitWindow then
    begin
    VideoScale:=1.0;
    if GetVideoSize(W,H) then
      SetParentWindowSize(W,H);
    end;
end;

procedure TCustomVLCMediaPlayer.Play(M: TVLCMediaItem);

begin
  if Playing then
    begin
    Stop;
    While Playing do
      Sleep(100);
    end;
  SetMedia(M);
  Play;
end;

procedure TCustomVLCMediaPlayer.PlayFile(const AFileName: String);

Var
  M : TVLCMediaItem;
begin
  M:=TVLCMediaItem.Create(Nil);
  try
    M.Path:=AFileName;
    Play(M);
  finally
    M.Free;
  end;
end;

procedure TCustomVLCMediaPlayer.Stop;
begin
  if Assigned(FInstance) then
    libvlc_media_player_stop(FInstance);
end;

procedure TCustomVLCMediaPlayer.Pause;
begin
  if Assigned(FInstance) then
    libvlc_media_player_pause(FInstance);
end;

procedure TCustomVLCMediaPlayer.Resume;
begin
  if (GetState()=libvlc_Paused)  then
   if Assigned(FInstance) then
     libvlc_media_player_play(FInstance);
end;

procedure TCustomVLCMediaPlayer.NextFrame;
begin
  if Assigned(FInstance) then
   libvlc_media_player_next_frame(Finstance);
end;

function TCustomVLCMediaPlayer.Snapshot(const AFileName: String): Boolean;

var
  w,h : Cardinal;
begin
  Result:=Assigned(FInstance);
  if Result then
    begin
    w:=0;
    h:=0;
    Result:=libvlc_video_get_size(FInstance,0,@W,@H)=0;
    if Result then
      Result:=SnapShot(AFileName,W,H);
    end;
end;

function TCustomVLCMediaPlayer.Snapshot(const AFileName: String; AWidth,
  AHeight: Cardinal): Boolean;
begin
  Result:=Assigned(FInstance);
  If Result then
    Result:=libvlc_video_take_snapshot(FInstance,0,PCChar(PChar(AFileName)),AWidth,AHeight)=0;
end;

function TCustomVLCMediaPlayer.GetVideoSize(var AWidth, AHeight: Cardinal
  ): Boolean;
begin
  Result:=libvlc_video_get_size(FInstance,0,@AWidth,@AHeight)=0;
end;

{ TVLCMediaItems }

constructor TVLCMediaItems.Create(ALibrary: TVLCLibrary;AItemClass: TVLCMediaItemClass = Nil);
begin
  Inherited Create(AItemClass);
  FVLC:=ALibrary;
end;

constructor TVLCMediaItems.Create(AInstance: Plibvlc_media_list_t;
  AItemClass: TVLCMediaItemClass);


Var
  I : Integer;
  P : plibvlc_media_t;

begin
  Inherited Create(AItemClass);
  FInstance:=AInstance;
  For I:=0 to libvlc_media_list_count(FInstance)-1 do
    begin
    P:=libvlc_media_list_item_at_index(FInstance,I);
    (Add as TVLCMediaItem).SetInstance(P);
    end;
end;

procedure TVLCMediaItems.Lock;
begin
  libvlc_media_list_lock(FInstance);
end;

procedure TVLCMediaItems.Unlock;
begin
  libvlc_media_list_lock(FInstance);
end;

function TVLCMediaItems.GetInstance: Plibvlc_media_list_t;
Var
  I :integer;
begin
  if FInstance=Nil then
    begin
    FInstance:=libvlc_media_list_new(VLC.Instance);
    For I:=0 to Count-1 do
      GetI(I).RegisterInstance;
    end;
  Result:=Finstance;
end;

function TVLCMediaItems.GetIsReadOnly: Boolean;
begin
  Result:=libvlc_media_list_is_readonly(FInstance)<>0;
end;

function TVLCMediaItems.GetI(AIndex : Integer): TVLCMediaItem;
begin
  Result:=Items[AIndex] as TVLCMediaItem;
end;

procedure TVLCMediaItems.SetI(AIndex : Integer; AValue: TVLCMediaItem);
begin
  Items[AIndex]:=AValue;
end;


function TVLCMediaItems.GetVLC: TVLCLibrary;
begin
  Result:=VLCLibrary;
end;

{ TVLCMediaItem }

function TVLCMediaItem.GetInstance: plibvlc_media_t;
begin
  Result:=Finstance;
  If (Result=Nil) then
    Raise EVLC.Create('No instance available at this time. Set MRL, Path or FileDescriptor first');
end;

function TVLCMediaItem.GetM(AIndex: Integer): Boolean;
begin
  Result:=FOpts[AIndex];
end;

function TVLCMediaItem.GetMD(AMeta : libvlc_meta_t): String;

Var
  P : PCChar;

begin
  P:=libvlc_media_get_meta(Instance,AMeta);
  if (P<>Nil) then
    Result:=StrPas(PChar(p))
  else
    Result:='';
end;

function TVLCMediaItem.GetMRL: String;
Var
  P : PCChar;

begin
  P:=libvlc_media_get_mrl(Instance);
  if (P<>Nil) then
    Result:=StrPas(PChar(p))
  else
    Result:='';
end;

function TVLCMediaItem.GetParsed: Boolean;
begin
  Result:=libvlc_media_is_parsed(Instance)<>0;
end;

function TVLCMediaItem.GetUD: Pointer;
begin
  Result:=libvlc_media_get_user_data(Instance);
end;

procedure TVLCMediaItem.SetDIM(AValue: TDeinterlaceMode);

Const
  DMS : Array[TDeinterlaceMode] of string
      = ('blend', 'discard', 'bob', 'linear', 'mean', 'x', 'yadif', 'yadif2x');
begin
  if (FDIM=AValue) then Exit;
  FDIM:=AValue;
  libvlc_media_add_option(Instance, PCChar(PChar('deinterlace-mode='+DMS[AValue])));
end;

procedure TVLCMediaItem.SetFD(AValue: Integer);
begin
  FFD:=AValue;
  Finstance:=libvlc_media_new_fd(GetVLC.Instance,AValue);
  If (FInstance=Nil) then
    Raise EVLC.CreateFmt('Failed to create media item from file descriptor "%d"',[AValue]);
  RegisterInstance;
end;

procedure TVLCMediaItem.SetFSS(AValue: TSNapshotFormat);

Const
  ssfs : Array[TSnapShotFormat] of string = ('png','jpg');

begin
  if FSS=AValue then Exit;
  FSS:=AValue;
  libvlc_media_add_option(Instance, PCChar(PChar('no-snapshot-preview')));
  libvlc_media_add_option(instance, PCChar(PChar('snapshot-format=' + SSFS[aValue])));
end;

procedure TVLCMediaItem.SetM(AIndex: Integer; AValue: Boolean);

begin
  FOpts[AIndex]:=AValue;
  libvlc_media_add_option(FInstance,PcChar(PChar(GetBoolOpt(AIndex,AValue))));
end;

function TVLCMediaItem.GetBoolOpt(AIndex: Integer; AValue: Boolean): String;
begin
  Case AINdex of
    0 : Result:='video-title-show';
    1 : Result:='video-on-top';
    2 : Result:='overlay';
    3 : Result:='fullscreen';
    4 : Result:='deinterlace='+IntToStr(Ord(AValue));
  end;
  if (AIndex < 4) and Not AValue then
    Result:='no-'+Result;
end;

procedure TVLCMediaItem.SetMD(AMeta : libvlc_meta_t; AValue: String);
begin
  libvlc_media_set_meta(Instance,AMeta,Pcchar(PChar(AValue)));
end;

procedure TVLCMediaItem.SetMRL(AValue: String);
begin
  Finstance:=libvlc_media_new_location(GetVLC.Instance,PCChar(AValue));
  If (FInstance=Nil) then
    Raise EVLC.CreateFmt('Failed to create media item from MRL : "%s"',[AValue]);
  RegisterInstance;
end;

procedure TVLCMediaItem.SetPath(AValue: String);
begin
  if FPath=AValue then Exit;
  FPath:=AValue;
  FInstance:=libvlc_media_new_path(GetVLC.Instance,PCChar(AValue));
  if (FInstance=Nil) then
    Raise EVLC.CreateFmt('Failed to create media item from path : "%s"',[AValue]);
  RegisterInstance;
end;

procedure TVLCMediaItem.SetUD(AValue: Pointer);
begin
  libvlc_media_set_user_data(Instance,AValue);
end;

function TVLCMediaItem.GetState: libvlc_state_t;
begin
  Result:=libvlc_media_get_state(instance);
end;

function TVLCMediaItem.GetDuration: TDateTime;

Var
  d :  libvlc_time_t;

begin
  d:=libvlc_media_get_duration(Instance);
  Result:=D
end;

procedure TVLCMediaItem.RegisterInstance;

Var
  L : Plibvlc_media_list_t;

begin
  If Assigned(Collection) and (Collection is TVLCMediaItems) then
    begin
    L:=TVLCMediaItems(Collection).FInstance;
    if (L<>Nil) then
      begin
      libvlc_media_list_lock(L);
      libvlc_media_list_add_media(L, FInstance);
      libvlc_media_list_unlock(L);
      end;
    end;
end;

procedure TVLCMediaItem.UnRegisterInstance;
Var
  L : Plibvlc_media_list_t;
  i : integer;

begin
  If Assigned(Collection) and (Collection is TVLCMediaItems) then
    begin
    L:=TVLCMediaItems(Collection).FInstance;
    if L<>Nil then
      begin
      libvlc_media_list_lock(L);
      I:=libvlc_media_list_index_of_item(L,Finstance);
      if (i>=0) then
        libvlc_media_list_remove_index(L,i);
      libvlc_media_list_unlock(L);
      end;
    end;
end;

function TVLCMediaItem.GetVLC: TVLCLibrary;
begin
  If Assigned(Collection) and (Collection is TVLCMediaItems) then
    Result:=TVLCMediaItems(Collection).GetVLC
  else
    Result:=VLCLibrary;
  if not Result.Initialized then
    Result.Initialize;
end;

function TVLCMediaItem.GetEventManager: plibvlc_event_manager_t;
begin
  Result:=libvlc_media_event_manager(Instance);
end;

procedure TVLCMediaItem.SetInstance(Avalue: plibvlc_media_t);
begin
  FInstance:=AValue;
end;

destructor TVLCMediaItem.Destroy;
begin
  inherited Destroy;
  if Assigned(FInstance) then
    begin
    UnregisterInstance;
    libvlc_media_release(FInstance);
    FInstance:=Nil;
    end;
end;

procedure TVLCMediaItem.AddOption(const AValue: String);
begin
  libvlc_media_add_option(Instance,PCChar(PChar(AValue)));
end;

procedure TVLCMediaItem.Parse;
begin
  libvlc_media_parse(Instance);
end;

procedure TVLCMediaItem.ParseAsync;
begin
  libvlc_media_parse_async(Instance);
end;

procedure TVLCMediaItem.SaveMetaData;
begin
  libvlc_media_save_meta(Instance);
end;

function TVLCMediaItem.GetStats(var AStats: libvlc_media_stats_t): Boolean;
begin
  Result:=libvlc_media_get_stats(Instance,@AStats)<>0;
end;

function TVLCMediaItem.Duplicate: TVLCMediaItem;
begin
  If Assigned(Collection) and (Collection is TVLCMediaItems) then
    Result:=TVLCMediaItems(Collection).Add as TVLCMediaItem
  else
    Result:=TVLCMediaItem.Create(Nil);
  Result.SetInstance(libvlc_media_duplicate(Instance));
end;


function TVLCLibrary.GetLastError: String;

Var
  P : PCChar;

begin
  P:=libvlc_errmsg();
  if Assigned(P) then
    Result := StrPas(PChar(P))
  else
    Result:='';
end;

function TVLCLibrary.GetI: Boolean;
begin
  Result:=FInstance<>Nil;
end;

function TVLCLibrary.GetVersion: String;
Var
  P : PCChar;

begin
  P:=libvlc_get_version();
  if Assigned(P) then
    Result := StrPas(PChar(P))
  else
    Result:='';
end;

function TVLCLibrary.GetCompiler: String;
Var
  P : PCChar;

begin
  P:=libvlc_get_compiler();
  if Assigned(P) then
    Result := StrPas(PChar(P))
  else
    Result:='';
end;

function TVLCLibrary.GetChangeSet: String;

Var
  P : PCChar;

begin
  P:=libvlc_get_changeset();
  if Assigned(P) then
    Result := StrPas(PChar(P))
  else
    Result:='';
end;

procedure TVLCLibrary.SetLibraryPath(const AValue: String);
begin
  If AValue=FLibraryPath then exit;
  If Assigned(FInstance) then
    Raise EVLC.Create('VLC already initialized, cannot set librarypath');
  FLibraryPath:=AVAlue;
end;

function TVLCLibrary.GetInstance: plibvlc_instance_t;

var
  args: Array of AnsiString;
  cargs : array of PAnsiChar;
  argc,
  I : integer;

begin
  If (FInstance=Nil) then
    begin
    LibraryArgs.add('--no-video-title-show');
    SetLength(cArgs,LibraryArgs.Count+2);
    SetLength(Args,LibraryArgs.Count+1);
    cargs[0] := PChar(FLibraryPath);
    For I:=0 to LibraryArgs.Count-1 do
      begin
      Args[i]:=LibraryArgs[i];
      CArgs[i+1]:=PChar(Args[i]);
      end;
    argc:=Length(CArgs);
    cargs[argc-1] := NIL;
    FInstance := libvlc_new(argc-1, PPcchar(cargs));
    if (FInstance=Nil) then
      Raise EVLC.Create('Could not create instance of libvlc');
    end;
  Result:=FInstance;
end;

constructor TVLCLibrary.Create(AOwner: TComponent);
begin
  Inherited;
  FInstance:=Nil;
  FLibraryPath:=LibName;
  FLibraryArgs:=TStringList.Create;
end;

destructor TVLCLibrary.Destroy;
begin
  FreeAndNil(FLibraryArgs);
  Release;
  inherited Destroy;
end;

procedure TVLCLibrary.Initialize;
begin
  LoadLibVLC(LibraryPath,False);
  GetInstance;
end;

procedure TVLCLibrary.Release;
begin
  If (FInstance<>Nil) then
    begin
    libvlc_release(FInstance);
    FreeLibVLC;
    end;
  FInstance:=Nil;
end;

Initialization

Finalization
  DoneVLC;
end.

