source: CoolAudio/Systems/mplayer/AudioSystemMPlayer.pas

Last change on this file was 569, checked in by chronos, 3 months ago
  • Modified: Removed U prefix from CoolAudio unit names.
File size: 8.3 KB
Line 
1// MPlayer slave command list: http://www.mplayerhq.hu/DOCS/tech/slave.txt
2
3unit AudioSystemMPlayer;
4
5{$I CoolAudioConfig.inc}
6
7interface
8
9uses
10 Classes, SysUtils, AudioSystem, Process, Math, Dialogs, DateUtils;
11
12const
13{$ifdef Unix}
14 MPlayerExecutableName = 'mplayer';
15{$endif}
16{$ifdef Windows}
17 MPlayerExecutableName = 'mplayer.exe';
18{$endif}
19
20type
21 { TAudioSystemMPlayer }
22
23 TAudioSystemMPlayer = class(TAudioSystem)
24 protected
25 FPath: string;
26 procedure SetOutputMode(AValue: TOutputDriver); override;
27 public
28 function FindPath: string;
29 constructor Create(AOwner: TComponent); override;
30 destructor Destroy; override;
31 function GetMediaPlayerDriverClass: TMediaPlayerDriverClass; override;
32 property Path: string read FPath write FPath;
33 end;
34
35 { TPlayerMPlayer }
36
37 TPlayerMPlayer = class(TMediaPlayerDriver)
38 protected
39 FProcess: TProcess;
40 FVolume: Real;
41 function GetProcessOutput: string;
42 procedure SendCommand(Command: string);
43 function GetLength: TDateTime; override;
44 function GetPosition: TDateTime; override;
45 function GetVolume: Real; override;
46 function GetMuted: Boolean; override;
47 procedure SetPosition(AValue: TDateTime); override;
48 procedure SetVolume(AValue: Real); override;
49 procedure SetMuted(AValue: Boolean); override;
50 procedure SetFileName(AValue: string); override;
51 public
52 procedure Play; override;
53 procedure Pause; override;
54 procedure Stop; override;
55 constructor Create; override;
56 destructor Destroy; override;
57 end;
58
59resourcestring
60 SMPlayerNotFound = 'MPlayer executable not found. Make sure it is properly installed in binary path';
61 SSendCommandException = 'Exception occured during sending command to MPlayer';
62 SErrorReadingOutput = 'Exception while reading MPlayer output';
63 SCantStopProcess = 'Can''t stop Mplayer process';
64
65
66implementation
67
68function StrToFloatPoint(Value: string): Extended;
69var
70 FPointSeparator: TFormatSettings;
71begin
72 // Format seetings to convert a string to a float
73 FPointSeparator := DefaultFormatSettings;
74 FPointSeparator.DecimalSeparator := '.';
75 FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
76 Result := StrToFloat(Value, FPointSeparator);
77end;
78
79function FloatPointToStr(Value: Extended): string;
80var
81 FPointSeparator: TFormatSettings;
82begin
83 // Format seetings to convert a string to a float
84 FPointSeparator := DefaultFormatSettings;
85 FPointSeparator.DecimalSeparator := '.';
86 FPointSeparator.ThousandSeparator := '#';// disable the thousand separator
87 Result := FloatToStr(Value, FPointSeparator);
88end;
89
90{ TAudioSystemMPlayer }
91
92procedure TAudioSystemMPlayer.SetOutputMode(AValue: TOutputDriver);
93begin
94 inherited SetOutputMode(AValue);
95end;
96
97function TAudioSystemMPlayer.FindPath: string;
98var
99 tmps: string;
100 tmppath: string;
101 I: Integer;
102begin
103 Result := '';
104 {$ifdef Darwin}
105 {$else}
106 // Searches for MPlayer in the PATH
107 tmps := GetEnvironmentVariable('PATH');
108 repeat
109 I := Pos(PathSeparator, tmps);
110 if I = 0 then I := Length(tmps);
111 tmppath := IncludeTrailingPathDelimiter(Copy(tmps, 0, I - 1)) + MPlayerExecutableName;
112 if FileExists(tmppath) then Result := tmppath
113 else Delete(tmps, 1, I);
114 until (Length(tmps) <= 1) or (Result <> '');
115 {$endif}
116 if Result = '' then raise Exception.Create(SMPlayerNotFound);
117end;
118
119constructor TAudioSystemMPlayer.Create(AOwner: TComponent);
120begin
121 inherited;
122 FPath := FindPath;
123end;
124
125destructor TAudioSystemMPlayer.Destroy;
126begin
127 inherited;
128end;
129
130function TAudioSystemMPlayer.GetMediaPlayerDriverClass: TMediaPlayerDriverClass;
131begin
132 Result := TPlayerMPlayer;
133end;
134
135{ TPlayerMPlayer }
136
137procedure TPlayerMPlayer.SendCommand(Command: string);
138begin
139 Command := Command + #10; // MPLayer always needs #10 as Lineending, no matter if win32 or linux
140 try
141 if FProcess.Running then FProcess.Input.Write(Command[1], System.Length(Command));
142 except
143 raise Exception.Create(SSendCommandException);
144 end;
145end;
146
147function TPlayerMPlayer.GetLength: TDateTime;
148var
149 tmps: string;
150 I: Integer;
151 Time: Real;
152begin
153 if FPlaying and fProcess.Running then begin
154 repeat
155 SendCommand('get_time_length');
156 Sleep(5);
157 tmps := GetProcessOutput;
158 until Pos('LENGTH', tmps) > 0;
159 I := LastDelimiter('=', tmps);
160 if I > 0 then begin
161 Time := StrToFloatPoint(Copy(tmps, I + 1, System.Length(tmps)));
162 Result := Time * OneSecond;
163 end;
164 end;
165end;
166
167function TPlayerMPlayer.GetPosition: TDateTime;
168var
169 tmps: string;
170 I: Integer;
171 Time: Real;
172begin
173 if FProcess.Running then begin
174 I := 0;
175 repeat
176 SendCommand('get_property time_pos');
177 Sleep(8);
178 tmps := GetProcessOutput;
179 Inc(I);
180 until (Pos('time_pos', tmps) > 0) or (I >= 3);
181 I := LastDelimiter('=', tmps);
182 if I > 0 then begin
183 Time := StrToFloatPoint(Copy(tmps, I + 1, System.Length(tmps)));
184 Result := Time * OneSecond;
185 end else Result := -1;
186 end else Result := -1;
187end;
188
189function TPlayerMPlayer.GetVolume: Real;
190begin
191 Result := 0;
192end;
193
194function TPlayerMPlayer.GetMuted: Boolean;
195var
196 tmps, s: string;
197 I: Integer;
198begin
199 if FPlaying and FProcess.Running then begin
200 repeat
201 SendCommand('get_property mute');
202 Sleep(5);
203 tmps := GetProcessOutput;
204 until Pos('mute', tmps) > 0;
205 i := LastDelimiter('=', tmps);
206 if i > 0 then begin
207 s := Copy(tmps, i + 1, System.Length(tmps) - i);
208 Result := s = 'yes';
209 end;
210 end;
211end;
212
213procedure TPlayerMPlayer.SetPosition(AValue: TDateTime);
214begin
215 if FPlaying and FProcess.Running then begin
216 SendCommand('set_property time_pos ' + FloatPointToStr(AValue / OneSecond));
217 end;
218end;
219
220procedure TPlayerMPlayer.SetVolume(AValue: Real);
221begin
222 if FVolume = AValue then Exit;
223 FVolume := AValue;
224 if FPlaying and FProcess.Running then begin
225 if AValue < 0 then AValue := 0;
226 if AValue > 1 then AValue := 1;
227 SendCommand('set_property volume ' + IntToStr(Round(AValue * 100)) + '/1');
228 end;
229end;
230
231procedure TPlayerMPlayer.SetMuted(AValue: Boolean);
232begin
233 if FPlaying and FProcess.Running then
234 SendCommand('mute');
235end;
236
237procedure TPlayerMPlayer.SetFileName(AValue: string);
238begin
239 inherited SetFileName(AValue);
240end;
241
242function IntTodB(I, Ref: Longint): Integer;
243var
244 dB: Real;
245begin
246 if I = 0 then db := 0.001 else dB := I;
247 dB := 20 * log10(dB / ref);
248 Result := Round(dB);
249end;
250
251procedure TPlayerMPlayer.Play;
252var
253 MPOptions: String;
254begin
255 if FPlaying then Stop;
256 //FProcess := TProcess.Create(nil);
257 MPOptions := '-slave -quiet -softvol';
258 if AudioSystem.OutputMode = omAlsa then MPOptions := MPOptions + ' -ao alsa';
259 if AudioSystem.OutputMode = omOSS then MPOptions := MPOptions + ' -ao oss';
260 if AudioSystem.OutputMode = omWin32 then MPOptions := MPOptions + ' -ao win32';
261 if AudioSystem.OutputMode = omDirectX then MPOptions := MPOptions + ' -ao dsound';
262
263 //MPOptions := '-af volume=' + IntToStr(IntTodB(Round(FVolume * 100), 100)) + ' ' + MPOptions;// -volume xx only supported with patched mplayer;
264
265 FProcess.CommandLine := TAudioSystemMPlayer(AudioSystem).FPath + ' ' + MPOptions + ' "' + UTF8Decode(FFileName) + '"';
266 FProcess.Options := FProcess.Options + [poUsePipes, poDefaultErrorMode, poStderrToOutPut, poNoConsole];
267 //InputBox('', '', FProcess.CommandLine);
268 FProcess.Execute;
269
270 if FProcess.Running then begin
271 FPlaying := True;
272 end;
273end;
274
275procedure TPlayerMPlayer.Pause;
276begin
277 if FPlaying then begin
278 SendCommand('pause');
279 Sleep(10);
280 //FPaused := not FPaused;
281 end;
282end;
283
284procedure TPlayerMPlayer.Stop;
285begin
286 if FPlaying then begin
287 SendCommand('quit');
288 Sleep(15);
289 if FProcess.Running then begin
290 Sleep(50);
291 if FProcess.Running then
292 if not FProcess.Terminate(0) then
293 raise Exception.Create(SCantStopProcess);
294 end;
295 end;
296 FPlaying := False;
297end;
298
299constructor TPlayerMPlayer.Create;
300begin
301 inherited;
302 FProcess := TProcess.Create(nil);
303end;
304
305destructor TPlayerMPlayer.Destroy;
306begin
307 Stop;
308 FreeAndNil(FProcess);
309 inherited;
310end;
311
312function TPlayerMPlayer.GetProcessOutput: string;
313var
314 AStringList: TStringList;
315begin
316 try
317 AStringList:=TStringList.Create;
318 try
319 if FProcess.Running then AStringList.LoadFromStream(FProcess.Output);
320 if AStringList.Count > 0 then
321 Result := AStringList.Strings[0]
322 else Result := '';
323 except
324 Result := '';
325 raise Exception.Create(SErrorReadingOutput);
326 end;
327 finally
328 AStringList.Free;
329 end;
330end;
331
332end.
333
Note: See TracBrowser for help on using the repository browser.