{
  Autor: Michael Springwald

  Erstellt: Samstag der 01.März.2008
  Updates:
  -----------------------------------------------------------------------
01- Mittwoch, 26.März.2008         - Freitag, 28.März.2008              -
  -----------------------------------------------------------------------
02- Samstag, 29.März.2008          - Mittwoch, 11.Februar.2009          -
  -----------------------------------------------------------------------
03- Sonntag, 21.März.2010          -                                    -  
  -----------------------------------------------------------------------

Vielen Dank an "Peter During":
Bei GetLen und GetCurrTime kann man nun wahlweise das Format hh:mm:ss oder mm:ss haben.

Hinweis: Ich selbst habe die Weiterentwicklung dieser Unit vorläufig Eingestellt. Jeder "darf"
Änderungen vornehmen. Schön wäre, wenn die Änderungen im Forum bekannt gebgen würden,
so könnten diese in die Aktuelle Version einfließen und alle haben was davon.
}

unit plXine;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, xine,xlib;

const
  plSOpen  = 0;
  plSPlay  = 1;
  plSPause = 2;
  plSStop  = 3;

 TI_TITLE             = 0;
 TI_COMMENT           = 1;
 TI_ARTIST            = 2;
 TI_GENRE             = 3;
 TI_ALBUM             = 4;
 TI_YEAR              = 5;
 TI_VIDEOCODEC        = 6;
 TI_AUDIOCODEC        = 7;
 TI_SYSTEMLAYER       = 8;
 TI_INPUT_PLUGIN      = 9;

 TIF_TITLE            = '{$TITLE}';
 TIF_COMMENT          = '{$COMMENT}';
 TIF_ARTIST           = '{$ARTIST}';
 TIF_GENRE            = '{$GENRE}';
 TIF_ALBUM            = '{$ALBUM}';
 TIF_YEAR             = '{$YEAR}';
 TIF_VIDEOCODEC       = '{$VIDEOCODEC}';
 TIF_AUDIOCODEC       = '{$AUDIOCODEC}';
 TIF_SYSTEMLAYER      = '{$SYSTEMLAYER}';
 TIF_INPUT_PLUGIN     = '{$INPUT_PLUGIN}';
 TIF_MINUTE           = '{$MINUTE}';
 TIF_HOUR             = '{$HOUR}';
 TIF_SECOND           = '{$SECOND}';

type
  TPLXine = class;
  TPLTestEvent = procedure of Object;

  TMyThread = class(TThread)
    private
      procedure ShowStatus;
    protected
      procedure Execute; override;
    public
      xine:TPLXine;
      TestEvent:TPLTestEvent;
      t:Integer;
      Constructor Create(CreateSuspended : boolean);
    end;

  TOnFINISHED = procedure of Object;

  TXineEvent = procedure(data:Pointer) of object;

  TxineUserData = record
    rect: x11_rectangle_t;
    old_width, old_height : Integer;
    resizeFactor : Double;
    displayRatio : Double;
    Display: PDisplay;
    shmEventId: Integer;

    { event callbacks }
    OnPlaybackFinished: TXineEvent;
    OnChannelChanged: TXineEvent;
    OnSetTitle: TXineEvent;
    OnProgress: TXineEvent;
    OnNumButtons: TXineEvent;
    OnMRLReference: TXineEvent;
  end;

  { TPLXine }

  TPLXine = class
    fOnFINISHED: TXineEvent;
  private
    function GetMusicLenght: Integer;
    function GetPosition: Integer;
    function GetVolume: Integer;

    procedure SetPosition(const AValue: Integer);
    procedure SetVolume(const AValue: Integer);

  protected

  public
    PlayTime, PlayPos, PlayLen:Integer;

    CurrFileName:String;
    myXine : Pxine_t;

    ao_driver:Pxine_ao_driver_t;
    myXStream : Pxine_stream_t;
    queue: Pxine_event_queue_t;
    PlayStatus:Integer;
    UserData : TxineUserData;

    myThread:TMyThread;
    OpenF, NotPlay:Boolean;

    constructor Create(const aAutoInit:Boolean = True);
    destructor Destroy; override;

    procedure init;
    procedure FileOpen(const aFileName:String);
    procedure play;
    procedure Stop;
    procedure Pause;

    procedure Status(var aPos, aTime, aLen:Integer);
    procedure SetInfo;

    function GetLen(const Stunde:boolean = false):String;
    function GetCurrTime(const aCurr2Time:Boolean = False; Stunde:boolean = false):String;

    function GetFileExt:String;
    procedure TestEv;

    function Get_Info(Info:integer):string;
    function Get_Formated_Info(form:string):string;

  published
    property OnFINISHED:TXineEvent read fOnFINISHED write fOnFINISHED;

    property Volume:Integer read GetVolume write SetVolume;
    property Position:Integer read GetPosition write SetPosition;

    property MusicLenght:Integer read GetMusicLenght;

  end; // TPLXine


procedure XineEventCB(user_data:Pointer; event: Pxine_event_t); cdecl;

implementation
{ TPLXine }

procedure XineEventCB(user_data:Pointer; event: Pxine_event_t); cdecl;
var
  data:^TxineUserData;
begin
  if (user_data <> NIL) then begin
    data:=user_data;
    case event^.typ of
      XINE_EVENT_UI_PLAYBACK_FINISHED:
      begin
        if Assigned(data^.OnPlaybackFinished) then
          data^.OnPlaybackFinished(event^.data);
      end;

      XINE_EVENT_UI_CHANNELS_CHANGED:
      begin
      end;

      XINE_EVENT_UI_SET_TITLE:
      begin
      end;

      XINE_EVENT_PROGRESS:
      begin
        writeln('TEST:Progress');
      end;

      XINE_EVENT_UI_NUM_BUTTONS:
      begin
      end;

      XINE_EVENT_MRL_REFERENCE:
      begin
      end
      else
      begin
      end;
   end;
  end
end;

function TPLXine.GetMusicLenght: Integer;
begin

end;

function TPLXine.GetPosition: Integer;
begin
  result:=PlayTime;
end; // TPLXine.GetPosition

function TPLXine.GetVolume: Integer;
begin
  result:=xine_get_param(myXStream, XINE_PARAM_AUDIO_VOLUME);
end; // TPLXine.GetVolume

procedure TPLXine.SetPosition(const AValue: Integer);
begin
  if( xine_get_stream_info( myXStream, XINE_STREAM_INFO_SEEKABLE ) <> 0) then
  begin
    xine_set_param(myXStream, XINE_PARAM_AUDIO_VOLUME, AValue);
   xine_play( myXStream, 0, AValue );
  end;
end; // TPLXine.SetPosition

procedure TPLXine.SetVolume(const AValue: Integer);
begin
  xine_set_param(myXStream, XINE_PARAM_AUDIO_VOLUME, AValue);
end; // TPLXine.SetVolume

constructor TPLXine.Create(const aAutoInit:Boolean = True);
begin
  inherited Create;
  OpenF:=False;
  myThread:=TMyThread.Create(True);
  myThread.TestEvent:=@TestEv;
  myThread.xine:=self;

  if aAutoInit then init;
end; // TPLXine.Create

destructor TPLXine.Destroy;
begin
  inherited Destroy;
end; // TPLXine.Destroy

procedure TPLXine.init;
begin
  myThread.t:=1;
  myThread.Resume;
end; // TPLXine.init

procedure TPLXine.FileOpen(const aFileName: String);
begin
  CurrFileName:=aFileName;
  if xine_open(myXStream,PChar(CurrFileName)) >= 1 then begin
    if not NotPlay then begin
      OpenF:=True;
    end;
  end;
end; // TPLXine.FileOpen

procedure TPLXine.play;
begin
  xine_usec_sleep(1000);
  if (xine_get_param(myXStream,XINE_PARAM_SPEED) <> XINE_SPEED_PAUSE) then
  begin
     xine_play(myXStream,0,0);
  end;
  xine_set_param(myXStream,XINE_PARAM_SPEED,XINE_SPEED_NORMAL);

//  myThread.t:=3;
//  myThread.Resume;
  //writeln('-- Play -- ');

//  myThread.Resume;
end; // TPLXine.play

procedure TPLXine.Stop;
begin
  xine_stop(myXStream);
  xine_close(myXStream);
  OpenF:=False;
end; // TPLXine.Stop

procedure TPLXine.Pause;
begin
  if PlayStatus = plSPause then begin
    PlayStatus:=plSPlay;
    play;
  end
  else begin
    PlayStatus:=plSPause;
    xine_set_param(myXStream,XINE_PARAM_SPEED,XINE_SPEED_PAUSE);
  end;

end; // TPLXine.Pause

procedure TPLXine.Status(var aPos, aTime, aLen: Integer);
var
  zpos, ztime, zlength: Integer;
begin
  xine_get_pos_length(myXStream,@zpos,@ztime,@zlength);
  apos:=zPos; aTime:=ztime; aLen:=zlength;
end;

procedure TPLXine.SetInfo;
begin
  Status(playpos,playtime,PlayLen);
end; // TPLXine.SetInfo

function TPLXine.GetLen(const Stunde:boolean = false): String;
var
  sLen:String;
  aStu, aMin, aSek:Integer;
begin

  aSek:=(PlayLen div 1000) mod 60;
  aMin:=(PlayLen div 60000) mod 60;
  if Stunde then
  begin
    aStu:=(PlayLen div 3600000) mod 60;
    sLen:=Format('%.2D:%.2D:%.2D',[aStu, aMin, aSek])
  end else
    sLen:=Format('%.2D:%.2D',[aMin, aSek]);
  result:=sLen;
end; // TPLXine.GetLen

function TPLXine.GetCurrTime(const aCurr2Time:Boolean = False; Stunde:boolean = false): String;
var
  s:String;
  aStu, aMin, aSek, aT:Integer;
begin
  if not aCurr2Time then
    aT:=PlayTime
  else
    at:=PlayLen-PlayTime;

  aSek:=(aT div 1000) mod 60;
  aMin:=(aT div 60000) mod 60;
  if Stunde then
  begin
    aStu:=(aT div 3600000) mod 60;
    s:=Format('%.2D:%.2D:%.2D',[aStu, aMin, aSek])
  end else
    s:=Format('%.2D:%.2D',[aMin, aSek]);

  result:=s;
end; // TPLXine.GetCurrTime

function TPLXine.GetFileExt: String;
begin
  result:=ExtractFileExt(CurrFileName);
end;

procedure TPLXine.TestEv;
begin

end;

function TPLXine.Get_Info(Info:integer): string;
begin
  result:=StrPas(xine_get_meta_info(myXStream,Info));
end;

function TPLXine.Get_Formated_Info(form: string): string;
var s:string;
  aStu, aMin, aSek:Integer;
begin
  SetInfo;
  aSek:=(PlayLen div 1000) mod 60;
  aMin:=(PlayLen div 60000) mod 60;
  aStu:=(PlayLen div 3600000) mod 60;
  s:=StringReplace(form,TIF_TITLE,        Get_Info(TI_TITLE),        [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_HOUR,         inttostr(astu),            [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_MINUTE,       inttostr(amin),            [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_SECOND,       inttostr(asek),            [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_COMMENT,      Get_Info(TI_COMMENT),      [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_ARTIST,       Get_Info(TI_ARTIST),       [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_GENRE,        Get_Info(TI_GENRE),        [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_ALBUM,        Get_Info(TI_ALBUM),        [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_YEAR,         Get_Info(TI_YEAR),         [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_VIDEOCODEC,   Get_Info(TI_VIDEOCODEC),   [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_AUDIOCODEC,   Get_Info(TI_AUDIOCODEC),   [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_SYSTEMLAYER,  Get_Info(TI_SYSTEMLAYER),  [rfReplaceAll]);
  s:=StringReplace(s   ,TIF_INPUT_PLUGIN, Get_Info(TI_INPUT_PLUGIN), [rfReplaceAll]);
  result:=s;
end;

{ TMyThread }

procedure TMyThread.ShowStatus;
var
  s:Integer;
begin
  if t = 1 then begin
    xine.myXine := xine_new();
    xine_config_load(xine.myXine,PChar('/.xine/config'));
    xine_init(xine.myXine);
    xine.ao_driver := xine_open_audio_driver(xine.myXine,'alsa',Nil);
    xine.myXStream := xine_stream_new(xine.myXine,xine.ao_driver,nil);
    xine.queue := xine_event_new_queue (xine.myXStream);
    xine.UserData.OnPlaybackFinished:=xine.OnFINISHED;
    xine_event_create_listener_thread (xine.queue, @XineEventCB, @xine.UserData);
    t:=0;
  end;

  if ( t= 3) and (not xine.NotPlay) and (xine.OpenF) then begin
    writeln('-- Play3 -- ', xine.OpenF);

    if (xine_get_param(xine.myXStream,XINE_PARAM_SPEED) <> XINE_SPEED_PAUSE) then
    begin

       try
         xine_play(xine.myXStream,0,0);
       except
//         xine_open(xine.myXStream,PChar(xine.CurrFileName));
//         xine_play(xine.myXStream,0,0);
       end;
    end;
  ///  xine_set_param(xine.myXStream,XINE_PARAM_SPEED,XINE_SPEED_NORMAL);
    t:=0;
   //Terminate;
  end;
end;

procedure TMyThread.Execute;
begin
  Synchronize(@Showstatus);

{  while not Terminated do begin
    if t > 0 then  begin
      Synchronize(@Showstatus);
    end;
  end;}
end;

constructor TMyThread.Create(CreateSuspended: boolean);
begin
  FreeOnTerminate := False;
  inherited Create(CreateSuspended);
  t:=0;
end;

end.

