lazarus-ccr/components/mplayer/mplayerctrl.pas

876 lines
27 KiB
ObjectPascal

{ LCL control for playing videos using mplayer under gtk2
Copyright (C) 2009 Mattias Gaertner mattias@freepascal.org
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
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. See the GNU Library General Public License
for more details.
You should have received a copy of the GNU Library General Public License
along with this library; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Changes:
2014-03-24 Changes for Microsoft Windows Compatibility and added Events
for Mouse Actions/ Michael Koecher aka six1
2014-06-21 Added OnFeedback/OnError events
Added OnPlay, OnStop, OnPlaying events
Expanded Timer code to track state of Player
Added pausing_keep_force to all commands
- simply requesting state information was enough to resume paused video
- adding pausing_keep was insufficent
Added Duration, Position
Replaced StrToCmdParam with AnsiQuotedStr in Play
- StrToCmdParam didn't work under Windows - wrapped filename in ', Windows needed "
Persisted FCanvas outside of IDE to prevent painting issues when no file playing
/ Mike Thompson
2014-06-24 Added FindMPlayerPath (Refactored code from Play)
2014-06-28 Extended FindMPlayer to also look for mplayer in a subfolder of the exe
Fixed painting issues when playing audio files (introduces a flicker on
resize when playing video :-( )...
Fixed repeated requests for volume in files that don't support volme
Changed TProcessUTF8 population code in .Play from .CommandLine to
use .Executable & .Parameters
- incidently removed the need to use AnsiQuotedStr around Filename under Windows
Added Rate (Fast Forward only, mplayer doesn't support rewind)
Only request position updates every ON_PLAYING_INTERVAL
Set Volume on Play
Added GrabImage and OnGrabImage (delay before mplayer grabs image)
- doesn't work well with some renderers (-glnosw for instance,
also inconsistently on -vo X11)
- Capturing failed attempts in code will be hard, for now I'll
just ensure this is documented on the wiki (recommend -vo direct3d under win)
/ Mike Thompson
2014-07-01 Discovered -identify to load stats (including Start Time)
Moved set volume on play to the parameters
Refactored TimerEvent to ensure OnPlay & OnPlaying are broadcast in correct sequence
Added VideoInfo and AudioInfo (load values from -identify)
Fixed Position for videos with embedded Start_Time
Deprecated PlayerProcess (no need for it to be exposed anymore)
Realised no need for StepForward/StepBack - can be implemented externally via Position
Exposed OnMouseWheel and implemented wheelmouse scrolling through video in FullFeatured
demo
/ Mike Thompson
TODO
EXTENSIVE TESTING UNDER LINUX
- Tested under Linus Mint 16 (MATE) with mplayer installed (not mplayer2)
Consider descending control from TGraphicControl (instead of creating FCanvas)
NOTES
2014-06-29 TProcessUTF8 is a thin wrapper over TProcess. TProcess on Windows
is not unicode aware, so there is currently an issue playing unicode
filenames under windows.
No easy apparent solution other than upgrading TProcess (win\process.inc).
}
unit MPlayerCtrl;
{$mode objfpc}{$H+}
{$ifdef Linux}
{$ifndef LCLgtk2}
{$error this unit only supports LCL under gtk2}
{$endif}
{$endif}
interface
uses
Classes, SysUtils, Controls, WSLCLClasses, LCLProc, LCLType, InterfaceBase,
LResources, LMessages, Graphics, ExtCtrls, FileUtil, Process, UTF8Process,
LazFileUtils
{$ifdef Linux}
, gtk2int, gtk2, glib2, gdk2x, Gtk2WSControls, GTK2Proc, Gtk2Def
{$endif}
;
type
TVideoInfo = record
Codec: string;
Format: string;
Width, Height: Integer;
FPS: Single;
Bitrate: Integer;
end;
TAudioInfo = record
Codec: string;
Format: string;
Bitrate: Single;
Channels: Integer;
SampleRate: Integer; // Hz
end;
{ TCustomMPlayerControl }
TOnFeedback = procedure(ASender: TObject; AStrings: TStringList) of object;
TOnError = procedure(ASender: TObject; AStrings: TStringList) of object;
TOnPlaying = procedure(ASender: TObject; APosition: single) of object;
TOnGrabImage = Procedure(ASender: TObject; AFilename: String) of object;
TCustomMPlayerControl = class(TWinControl)
private
FFilename: string;
FImagePath: string;
FLastImageFilename: string;
FOnGrabImage: TOnGrabImage;
FRate: single;
FStartParam:string;
FLoop: integer;
FMPlayerPath: string;
FPaused: boolean;
FPlayerProcess: TProcessUTF8;
FTimer: TTimer;
FVolume: integer;
FCanvas: TCanvas;
FPosition: Single;
FLastPosition: string;
FRequestingPosition: boolean;
FLastTimer: TDateTime;
FRequestVolume: boolean;
FStartTime: single;
FDuration: single;
FOnError: TOnError;
FOnFeedback: TOnFeedback;
FOnPlay: TNotifyEvent;
FOnPlaying: TOnPlaying;
FOnStop: TNotifyEvent;
FOutList: TStringList;
FVideoInfo: TVideoInfo;
FAudioInfo: TAudioInfo;
function GetPosition: single;
function GetRate: single;
procedure SetImagePath(AValue: string);
procedure SetPosition(AValue: single);
procedure SetFilename(const AValue: string);
procedure SetLoop(const AValue: integer);
procedure SetMPlayerPath(const AValue: string);
procedure SetPaused(const AValue: boolean);
procedure SetRate(AValue: single);
procedure SetVolume(const AValue: integer);
procedure SetStartParam(const AValue: string);
procedure TimerEvent(Sender: TObject);
protected
procedure WMPaint(var Message: TLMPaint); message LM_PAINT;
procedure WMSize(var Message: TLMSize); message LM_SIZE;
procedure InitialiseInfo;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure SendMPlayerCommand(Cmd: string); // see: mplayer -input cmdlist and http://www.mplayerhq.hu/DOCS/tech/slave.txt
function Running: boolean;
procedure Play;
procedure Stop;
function Playing: boolean;
procedure Invalidate; override;
procedure EraseBackground(DC: HDC); override;
public
function FindMPlayerPath : Boolean;
procedure GrabImage;
property LastImageFilename: String read FLastImageFilename;
property Filename: string read FFilename write SetFilename;
property StartParam: string read FStartParam write SetStartParam;
property MPlayerPath: string read FMPlayerPath write SetMPlayerPath;
property PlayerProcess: TProcessUTF8 read fPlayerProcess; deprecated;
property Paused: boolean read FPaused write SetPaused;
property Loop: integer read FLoop write SetLoop; // -1 no, 0 forever, 1 once, 2 twice, ...
property Volume: integer read FVolume write SetVolume;
property ImagePath: string read FImagePath write SetImagePath;
property Rate: single read GetRate write SetRate; // mplayer only supports 0.1 to 100
property Duration: single read FDuration; // seconds
property Position: single read GetPosition write SetPosition; // seconds
property VideoInfo: TVideoInfo read FVideoInfo; // this isn't fully populated until OnPlay recieved
property AudioInfo: TAudioInfo read FAudioInfo; // this isn't fully populated until OnPlay received
property OnFeedback: TOnFeedback read FOnFeedback write FOnFeedback;
property OnError: TOnError read FOnError write FOnError;
property OnPlaying: TOnPlaying read FOnPlaying write FOnPlaying;
property OnPlay: TNotifyEvent read FOnPlay write FOnPlay;
property OnStop: TNotifyEvent read FOnStop write FOnStop;
Property OnGrabImage: TOnGrabImage read FOnGrabImage write FOnGrabImage;
end;
TMPlayerControl = class(TCustomMPlayerControl)
published
property Align;
property Anchors;
property BorderSpacing;
property Enabled;
property Filename;
property Loop;
property OnChangeBounds;
property OnConstrainedResize;
property OnResize;
property OnClick;
property OnMouseUp;
property OnMouseDown;
property OnMouseWheel;
property Visible;
property Volume; // 0 to 100
property OnFeedback; // Provides standard console output from mplayer
property OnError; // Provides stderr console output from mplayer
property OnPlaying; // When not paused, an event every 250ms to 500ms with Position
property OnPlay; // Sent after mplayer initialises the current video file
property OnStop; // Sent sometime (up to approx 250ms) after mplayer finishes current video
property OnGrabImage; // Fired when mplayer reports the filename of the image grab
end;
{ TWSMPlayerControl }
{$ifdef Linux}
TWSMPlayerControl = class(TGtk2WSWinControl)
published
class function CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): HWND; override;
class procedure DestroyHandle(const AWinControl: TWinControl); override;
end;
{$endif}
Const
ON_PLAYING_INTERVAL = 500 / (24*60*60*1000);
procedure Register;
implementation
Uses
Forms;
procedure Register;
begin
RegisterComponents('Multimedia',[TMPlayerControl]);
end;
// returns the value from "ANS_PropertyName=Value" strings
function ExtractAfter(AInput, AIdentifier: string): string; inline;
begin
AInput := Lowercase(AInput);
AIdentifier := Lowercase(AIdentifier);
Result := Copy(AInput, Length(AIdentifier) + 1, Length(AInput) - Length(AIdentifier));
end;
{ TCustomMPlayerControl }
procedure TCustomMPlayerControl.TimerEvent(Sender: TObject);
var
ErrList: TStringList;
i: integer;
sTemp: string;
iPosEquals, iPosAfterUS: SizeInt;
sValue: string;
sProperty: string;
iError: Integer;
bPostOnPlay, bPostOnStop, bPostOnPlaying: boolean;
begin
bPostOnPlay:=False;
bPostOnStop:=False;
bPostOnPlaying:=False;
if FPlayerProcess<>nil then
begin
If Running And ((Now-FLastTimer)>ON_PLAYING_INTERVAL) Then
begin
// Inject a request for current position
if Assigned(FOnPlaying) and not FPaused then
begin
SendMPlayerCommand('get_time_pos');
FRequestingPosition := True;
end;
// Inject a request for Volume level
if FRequestVolume then
SendMPlayerCommand('get_property volume');
FLastTimer := Now;
bPostOnPlaying := True;
end;
if FPlayerProcess.Output.NumBytesAvailable > 0 then
begin
FOutList.LoadFromStream(FPlayerProcess.Output);
// Look for responses to injected commands...
// or for standard issued information
for i := FOutList.Count - 1 downto 0 do
begin
sTemp := Lowercase(FOutList[i]);
iPosEquals := Pos('=', sTemp);
// Identify requests look like ID_Property=Value
// Property requests look like ANS_Property=Value
if (iPosEquals>1) and ((Pos('ans_', sTemp)=1) or (Pos('id_', sTemp)=1)) then
begin
iPosAfterUS := Pos('_', sTemp)+1;
sValue := Copy(sTemp, iPosEquals + 1, Length(sTemp) - iPosEquals);
sProperty := Copy(sTemp, iPosAfterUS, iPosEquals - iPosAfterUS);
if Assigned(FOnPlaying) and (FRequestingPosition) and (sProperty = 'time_position') then
begin
// Are we paused by any chance?
if sValue = FLastPosition then
SendMPlayerCommand('get_property pause');
FLastPosition := sValue;
FPosition := StrToFloatDef(sValue, 0) - FStartTime;
// Don't remove any further ANS_Time_Positions, they're not ours...
FRequestingPosition := False;
// clear this response from the queue
FOutList.Delete(i);
end
else
case sProperty Of
'volume' :
begin
FVolume := Trunc(0.5 + StrToFloatDef(sValue, 100));
FRequestVolume := False;
// clear this response from the queue
FOutList.Delete(i);
end;
'length' : FDuration := StrToFloatDef(sValue, -1);
'pause' : FPaused := (sValue = 'yes');
'video_codec' : FVideoInfo.Codec:=sValue;
'video_format' : FVideoInfo.Format:=sValue;
'video_bitrate': FVideoInfo.Bitrate:=StrToIntDef(sValue, 0);
'video_width' : FVideoInfo.Width:=StrToIntDef(sValue, 0);
'video_height' : FVideoInfo.Height:=StrToIntDef(sValue, 0);
'video_fps' : FVideoInfo.FPS:=StrToFloatDef(sValue, 0);
'start_time' : FStartTime:=StrToFloatDef(sValue, 0);
//'seekable' : FSeekable:=(sValue='1');
'audio_codec' : FAudioInfo.Codec:=sValue;
'audio_format' : FAudioInfo.Format:=sValue;
'audio_bitrate': FAudioInfo.Bitrate:=StrToIntDef(sValue, 0);
'audio_rate' : FAudioInfo.SampleRate:=StrToIntDef(sValue, 0);
'audio_nch' : FAudioInfo.Channels:=StrToIntDef(sValue, 0);
'exit' : bPostOnStop:=True;
end;
end // ID_ or ANS_
else if Assigned(FOnPlay) and (sTemp = 'starting playback...') then
bPostOnPlay:=True
else if (Pos('*** screenshot', sTemp)=1) Then
begin
// result looks like *** screenshot 'shot0002.png' ***
FLastImageFilename:=IncludeTrailingBackslash(GetCurrentDirUTF8) + Copy(sTemp, 17, Pos('.', sTemp)-17+4);
if assigned(FOnGrabImage) And FileExistsUTF8(FLastImageFilename) then
FOnGrabImage(Self, FLastImageFilename);
// clear this response from the queue
FOutList.Delete(i);
end
else if sTemp='sending vfctrl_screenshot!' then
FOutList.Delete(i);
end;
if Assigned(FOnFeedback) and (FOutlist.Count > 0) then
FOnFeedback(Self, FOutlist);
end;
if FPlayerProcess.StdErr.NumBytesAvailable > 0 then
begin
ErrList := TStringList.Create;
try
ErrList.LoadFromStream(FPlayerProcess.Stderr);
// Catch error retrieving volume
If FRequestVolume Then
begin
iError := ErrList.IndexOf('Failed to get value of property ''volume''.');
If iError<>-1 Then
begin
Errlist.Delete(iError);
// Prevent further requests for volume
FVolume := 0;
FRequestVolume := False;
end;
end;
if Assigned(FOnError) then
FOnError(Self, ErrList);
finally
ErrList.Free;
end;
end;
end;
// don't post the OnPlay until all the data above is processed
if Assigned(FOnPlay) and bPostOnPlay then
FOnPlay(Self);
If Assigned(FOnPlaying) And bPostOnPlaying then
FOnPlaying(Self, FPosition);
If (not Running) Or bPostOnStop Then
Stop;
end;
procedure TCustomMPlayerControl.WMPaint(var Message: TLMPaint);
begin
Include(FControlState, csCustomPaint);
inherited WMPaint(Message);
if (csDesigning in ComponentState) and (FCanvas<>nil) then begin
with FCanvas do begin
if Message.DC <> 0 then
Handle := Message.DC;
Brush.Color:=clLtGray;
Pen.Color:=clRed;
Rectangle(0,0,Self.Width-1,Self.Height-1);
MoveTo(0,0);
LineTo(Self.Width,Self.Height);
MoveTo(0,Self.Height);
LineTo(Self.Width,0);
if Message.DC <> 0 then
Handle := 0;
end;
end;
Exclude(FControlState, csCustomPaint);
end;
procedure TCustomMPlayerControl.WMSize(var Message: TLMSize);
begin
if (Message.SizeType and Size_SourceIsInterface)>0 then
DoOnResize;
end;
procedure TCustomMPlayerControl.SetStartParam(const AValue: string);
begin
if FStartParam=AValue then exit;
FStartParam:=AValue;
end;
procedure TCustomMPlayerControl.SetFilename(const AValue: string);
// Copied from win\process.inc
// mplayer uses identical params under linux, so this is safe
Function MaybeQuoteIfNotQuoted(Const S : String) : String;
begin
If (Pos(' ',S)<>0) and (pos('"',S)=0) then
Result:='"'+S+'"'
else
Result:=S;
end;
begin
if FFilename=AValue then exit;
FFilename:=AValue;
if Running then
SendMPlayerCommand('loadfile '+MaybeQuoteIfNotQuoted(Filename));
end;
procedure TCustomMPlayerControl.SetLoop(const AValue: integer);
begin
if FLoop=AValue then exit;
FLoop:=AValue;
if Running then
SendMPlayerCommand('loop '+IntToStr(FLoop));
end;
procedure TCustomMPlayerControl.SetMPlayerPath(const AValue: string);
begin
if FMPlayerPath=AValue then exit;
FMPlayerPath:=AValue;
end;
procedure TCustomMPlayerControl.SetPaused(const AValue: boolean);
begin
if FPaused=AValue then exit;
if Running then begin
FPaused:=AValue;
SendMPlayerCommand('pause');
end;
end;
procedure TCustomMPlayerControl.SetRate(AValue: single);
begin
if FRate=AValue then Exit;
if (FRate<0.1) or (FRate>100) then Exit;
if Running then begin
FRate:=AValue;
SendMPlayerCommand(Format('set_property speed %.3f', [FRate]));
end;
end;
procedure TCustomMPlayerControl.SetVolume(const AValue: integer);
begin
if FVolume=AValue then exit;
FVolume:=AValue;
if Running then
begin
SendMPlayerCommand('volume ' + IntToStr(FVolume) + ' 1');
FRequestVolume := True;
end;
end;
constructor TCustomMPlayerControl.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
ControlStyle:=ControlStyle-[csSetCaption];
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
SetInitialBounds(0, 0, 160, 90);
FOutlist := TStringList.Create;
FMPlayerPath := 'mplayer' + GetExeExt;
FTimer := TTimer.Create(Self);
FTimer.Enabled := False;
FTimer.Interval := 250;
FTimer.OnTimer := @TimerEvent;
end;
destructor TCustomMPlayerControl.Destroy;
begin
Stop;
FreeAndNil(FCanvas);
FreeAndNil(FTimer);
FreeAndNil(FOutList);
inherited Destroy;
end;
procedure TCustomMPlayerControl.SendMPlayerCommand(Cmd: string);
begin
if Cmd='' then exit;
if not Running then exit;
if Pos('paus', Lowercase(Cmd)) <> 1 then
Cmd := 'pausing_keep_force ' + Cmd;
if Cmd[length(Cmd)] <> LineEnding then
Cmd := Cmd + LineEnding;
FPlayerProcess.Input.Write(Cmd[1], length(Cmd));
end;
function TCustomMPlayerControl.Running: boolean;
begin
Result:=(fPlayerProcess<>nil) and fPlayerProcess.Running;
end;
function TCustomMPlayerControl.FindMPlayerPath: Boolean;
var
ExePath: string;
MPlayerExe: String;
begin
result := FileExistsUTF8(FMPlayerPath);
If not result then
begin
MPlayerExe:='mplayer'+GetExeExt;
if FMPlayerPath='' then
FMPlayerPath:=MPlayerExe;
ExePath:=FMPlayerPath;
// Is mplayer installed in the environment path?
if not FilenameIsAbsolute(ExePath) then
ExePath:=FindDefaultExecutablePath(ExePath);
// is mplayer in a folder under the application folder?
if Not FileExistsUTF8(ExePath) then
ExePath := IncludeTrailingBackSlash(ExtractFileDir(Application.ExeName))+
IncludeTrailingBackslash('mplayer') + MPlayerExe;
// did we find it?
if FileExistsUTF8(ExePath) then
begin
FMPlayerPath:=ExePath;
result := true;
end;
end;
end;
procedure TCustomMPlayerControl.GrabImage;
begin
if Running then
SendMPlayerCommand('screenshot 0')
end;
procedure TCustomMPlayerControl.Play;
var
CurWindowID: PtrUInt;
slStartParams : TStringList;
begin
if (csDesigning in ComponentState) then exit;
if Running and Paused then begin
Paused:=false;
exit;
end;
if Playing then begin
if FRate<>1 Then
Rate := 1;
exit;
end;
{$IFDEF Linux}
if (not HandleAllocated) then exit;
DebugLn(['TCustomMPlayerControl.Play ']);
{$endif}
if fPlayerProcess<>nil then
FreeAndNil(fPlayerProcess);
// raise Exception.Create('TCustomMPlayerControl.Play fPlayerProcess still exists');
if not FindMPlayerPath then
raise Exception.Create(MPlayerPath+' not found');
{$IFDEF Linux}
CurWindowID := GDK_WINDOW_XWINDOW({%H-}PGtkWidget(PtrUInt(Handle))^.window);
{$else}
CurWindowID := Handle;
{$ENDIF}
FPlayerProcess := TProcessUTF8.Create(Self);
FPlayerProcess.Options := FPlayerProcess.Options + [poUsePipes, poNoConsole];
// -really-quiet : DONT USE: causes the video player to not connect to -wid. Odd...
// -noconfig all : stop mplayer from reading commands from a text file
// -zoom -fs : Unsure: Only perceptible difference is background drawn black not green
// -vo direct3d : uses Direct3D renderer (recommended under windows)
// -vo gl_nosw : uses OpenGL no software renderer
FPlayerProcess.Executable:=FMPlayerPath;
FPlayerProcess.Parameters.Add('-slave'); // allow us to control mplayer
FPlayerProcess.Parameters.Add('-quiet'); // supress most messages
FPlayerProcess.Parameters.Add('-identify'); // Request stats on playing file
FPlayerProcess.Parameters.Add('-volume'); // Set initial volume
FPlayerProcess.Parameters.Add(IntToStr(FVolume));
FPlayerProcess.Parameters.Add('-vf');
FPlayerProcess.Parameters.Add('screenshot'); // (with -vf) Allow frame grab
FPlayerProcess.Parameters.Add('-wid'); // sets Window ID (display video in our control)
FPlayerProcess.Parameters.Add(IntToStr(CurWindowID));
// Add the user defined start params
if (Trim(FStartParam)<>'') then
begin
slStartParams := TStringList.Create;
try
CommandToList(StartParam, slStartParams);
FPlayerProcess.Parameters.AddStrings(slStartParams);
finally
slStartParams.Free;
end;
end;
FPlayerProcess.Parameters.Add(FFilename);
FPlayerProcess.Parameters.Delimiter:=' ';
DebugLn(['TCustomMPlayerControl.Play ', FPlayerProcess.Parameters.DelimitedText]);
// Normally I'd be careful to only use FOutList in the
// Timer event, but here I'm confident the timer isn't running...
if assigned(FOnFeedback) then
begin
FOutlist.Clear;
FOutlist.Add(FPlayerProcess.Executable + ' ' + FPlayerProcess.Parameters.DelimitedText);
FOutlist.Add('');
FonFeedback(Self, FOutlist);
end;
// Populate defaults
InitialiseInfo;
FPlayerProcess.Execute;
// Start the timer that handles feedback from mplayer
FTimer.Enabled := True;
end;
procedure TCustomMPlayerControl.Stop;
begin
if FPlayerProcess = nil then
exit;
DebugLn(Format('ExitStatus=%d', [fPlayerProcess.ExitStatus]));
FPaused := False;
FDuration := -1;
FTimer.Enabled := False;
SendMPlayerCommand('quit');
FreeAndNil(FPlayerProcess);
if Assigned(FOnStop) then
FOnStop(Self);
// repaint the control
Refresh;
end;
function TCustomMPlayerControl.Playing: boolean;
begin
Result := Running and (not Paused);
end;
procedure TCustomMPlayerControl.Invalidate;
begin
if csCustomPaint in FControlState then exit;
inherited Invalidate;
end;
procedure TCustomMPlayerControl.EraseBackground(DC: HDC);
begin
if (FCanvas <> nil) then
with FCanvas do
begin
if DC <> 0 then
Handle := DC;
Brush.Color := clLtGray;
Rectangle(0, 0, Self.Width, Self.Height);
if DC <> 0 then
Handle := 0;
end;
end;
procedure TCustomMPlayerControl.InitialiseInfo;
begin
FLastPosition := '';
FPosition := 0;
FRequestVolume := False;
FStartTime := 0;
FRate := 1;
FDuration := -1;
with FVideoInfo Do
begin
Format := '';
Width := 0;
Height := 0;
FPS := 0;
Bitrate := 0;
end;
With FAudioInfo Do
begin
Format := '';
Bitrate := 0;
end;
end;
function TCustomMPlayerControl.GetPosition: single;
begin
DebugLn(Format('Get Position %.3f', [FPosition]));
Result := FPosition;
end;
function TCustomMPlayerControl.GetRate: single;
begin
Result := FRate;
//If not Running Then
// Result := FRate
//Else
// Result := StrToFloatDef(DoCommand('get_property speed', 'ans_speed='), 1)
end;
procedure TCustomMPlayerControl.SetImagePath(AValue: string);
begin
if DirectoryExistsUTF8(AValue) then
begin
FImagePath:=AValue;
SetCurrentDirUTF8(AValue);
end;
end;
procedure TCustomMPlayerControl.SetPosition(AValue: single);
begin
if Running then
begin
if AValue>0 Then
FPosition := AValue
Else
FPosition := 0;
DebugLn(Format('Set Position to %.3f', [FPosition]));
SendMPlayerCommand(Format('pausing_keep seek %.3f 2', [FPosition]));
end;
end;
{$ifdef Linux}
function MPLayerWidgetDestroyCB(Widget: PGtkWidget; {%H-}data: gPointer): GBoolean; cdecl;
begin
FreeWidgetInfo(Widget); // created in TWSMPlayerControl.CreateHandle
Result:=false;
end;
{ TWSMPlayerControl }
class function TWSMPlayerControl.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): HWND;
var
NewWidget: PGtkWidget;
WidgetInfo: PWidgetInfo;
Allocation: TGTKAllocation;
begin
if csDesigning in AWinControl.ComponentState then
Result:=inherited CreateHandle(AWinControl,AParams)
else begin
NewWidget:=gtk_event_box_new;
WidgetInfo := GetWidgetInfo(NewWidget,true); // destroyed in MPLayerWidgetDestroyCB
WidgetInfo^.LCLObject := AWinControl;
WidgetInfo^.Style := AParams.Style;
WidgetInfo^.ExStyle := AParams.ExStyle;
WidgetInfo^.WndProc := {%H-}PtrUInt(AParams.WindowClass.lpfnWndProc);
// set allocation
Allocation.X := AParams.X;
Allocation.Y := AParams.Y;
Allocation.Width := AParams.Width;
Allocation.Height := AParams.Height;
gtk_widget_size_allocate(NewWidget, @Allocation);
if csDesigning in AWinControl.ComponentState then begin
// at designtime setup normal handlers
TGtk2WidgetSet(WidgetSet).FinishCreateHandle(AWinControl,NewWidget,AParams);
end else begin
// at runtime
g_signal_connect(GPointer(NewWidget), 'destroy',
TGTKSignalFunc(@MPLayerWidgetDestroyCB), WidgetInfo);
end;
Result:=HWND({%H-}PtrUInt(Pointer(NewWidget)));
DebugLn(['TWSMPlayerControl.CreateHandle ',dbgs(NewWidget)]);
end;
end;
class procedure TWSMPlayerControl.DestroyHandle(const AWinControl: TWinControl
);
begin
inherited DestroyHandle(AWinControl);
end;
{$endif}
initialization
{$ifdef Linux}
RegisterWSComponent(TCustomMPlayerControl,TWSMPlayerControl);
{$endif}
{$I mplayerctrl.lrs}
end.