1 | // MPlayer slave command list: http://www.mplayerhq.hu/DOCS/tech/slave.txt
|
---|
2 |
|
---|
3 | unit AudioSystemMPlayer;
|
---|
4 |
|
---|
5 | {$I CoolAudioConfig.inc}
|
---|
6 |
|
---|
7 | interface
|
---|
8 |
|
---|
9 | uses
|
---|
10 | Classes, SysUtils, AudioSystem, Process, Math, Dialogs, DateUtils;
|
---|
11 |
|
---|
12 | const
|
---|
13 | {$ifdef Unix}
|
---|
14 | MPlayerExecutableName = 'mplayer';
|
---|
15 | {$endif}
|
---|
16 | {$ifdef Windows}
|
---|
17 | MPlayerExecutableName = 'mplayer.exe';
|
---|
18 | {$endif}
|
---|
19 |
|
---|
20 | type
|
---|
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 |
|
---|
59 | resourcestring
|
---|
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 |
|
---|
66 | implementation
|
---|
67 |
|
---|
68 | function StrToFloatPoint(Value: string): Extended;
|
---|
69 | var
|
---|
70 | FPointSeparator: TFormatSettings;
|
---|
71 | begin
|
---|
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);
|
---|
77 | end;
|
---|
78 |
|
---|
79 | function FloatPointToStr(Value: Extended): string;
|
---|
80 | var
|
---|
81 | FPointSeparator: TFormatSettings;
|
---|
82 | begin
|
---|
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);
|
---|
88 | end;
|
---|
89 |
|
---|
90 | { TAudioSystemMPlayer }
|
---|
91 |
|
---|
92 | procedure TAudioSystemMPlayer.SetOutputMode(AValue: TOutputDriver);
|
---|
93 | begin
|
---|
94 | inherited SetOutputMode(AValue);
|
---|
95 | end;
|
---|
96 |
|
---|
97 | function TAudioSystemMPlayer.FindPath: string;
|
---|
98 | var
|
---|
99 | tmps: string;
|
---|
100 | tmppath: string;
|
---|
101 | I: Integer;
|
---|
102 | begin
|
---|
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);
|
---|
117 | end;
|
---|
118 |
|
---|
119 | constructor TAudioSystemMPlayer.Create(AOwner: TComponent);
|
---|
120 | begin
|
---|
121 | inherited;
|
---|
122 | FPath := FindPath;
|
---|
123 | end;
|
---|
124 |
|
---|
125 | destructor TAudioSystemMPlayer.Destroy;
|
---|
126 | begin
|
---|
127 | inherited;
|
---|
128 | end;
|
---|
129 |
|
---|
130 | function TAudioSystemMPlayer.GetMediaPlayerDriverClass: TMediaPlayerDriverClass;
|
---|
131 | begin
|
---|
132 | Result := TPlayerMPlayer;
|
---|
133 | end;
|
---|
134 |
|
---|
135 | { TPlayerMPlayer }
|
---|
136 |
|
---|
137 | procedure TPlayerMPlayer.SendCommand(Command: string);
|
---|
138 | begin
|
---|
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;
|
---|
145 | end;
|
---|
146 |
|
---|
147 | function TPlayerMPlayer.GetLength: TDateTime;
|
---|
148 | var
|
---|
149 | tmps: string;
|
---|
150 | I: Integer;
|
---|
151 | Time: Real;
|
---|
152 | begin
|
---|
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;
|
---|
165 | end;
|
---|
166 |
|
---|
167 | function TPlayerMPlayer.GetPosition: TDateTime;
|
---|
168 | var
|
---|
169 | tmps: string;
|
---|
170 | I: Integer;
|
---|
171 | Time: Real;
|
---|
172 | begin
|
---|
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;
|
---|
187 | end;
|
---|
188 |
|
---|
189 | function TPlayerMPlayer.GetVolume: Real;
|
---|
190 | begin
|
---|
191 | Result := 0;
|
---|
192 | end;
|
---|
193 |
|
---|
194 | function TPlayerMPlayer.GetMuted: Boolean;
|
---|
195 | var
|
---|
196 | tmps, s: string;
|
---|
197 | I: Integer;
|
---|
198 | begin
|
---|
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;
|
---|
211 | end;
|
---|
212 |
|
---|
213 | procedure TPlayerMPlayer.SetPosition(AValue: TDateTime);
|
---|
214 | begin
|
---|
215 | if FPlaying and FProcess.Running then begin
|
---|
216 | SendCommand('set_property time_pos ' + FloatPointToStr(AValue / OneSecond));
|
---|
217 | end;
|
---|
218 | end;
|
---|
219 |
|
---|
220 | procedure TPlayerMPlayer.SetVolume(AValue: Real);
|
---|
221 | begin
|
---|
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;
|
---|
229 | end;
|
---|
230 |
|
---|
231 | procedure TPlayerMPlayer.SetMuted(AValue: Boolean);
|
---|
232 | begin
|
---|
233 | if FPlaying and FProcess.Running then
|
---|
234 | SendCommand('mute');
|
---|
235 | end;
|
---|
236 |
|
---|
237 | procedure TPlayerMPlayer.SetFileName(AValue: string);
|
---|
238 | begin
|
---|
239 | inherited SetFileName(AValue);
|
---|
240 | end;
|
---|
241 |
|
---|
242 | function IntTodB(I, Ref: Longint): Integer;
|
---|
243 | var
|
---|
244 | dB: Real;
|
---|
245 | begin
|
---|
246 | if I = 0 then db := 0.001 else dB := I;
|
---|
247 | dB := 20 * log10(dB / ref);
|
---|
248 | Result := Round(dB);
|
---|
249 | end;
|
---|
250 |
|
---|
251 | procedure TPlayerMPlayer.Play;
|
---|
252 | var
|
---|
253 | MPOptions: String;
|
---|
254 | begin
|
---|
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;
|
---|
273 | end;
|
---|
274 |
|
---|
275 | procedure TPlayerMPlayer.Pause;
|
---|
276 | begin
|
---|
277 | if FPlaying then begin
|
---|
278 | SendCommand('pause');
|
---|
279 | Sleep(10);
|
---|
280 | //FPaused := not FPaused;
|
---|
281 | end;
|
---|
282 | end;
|
---|
283 |
|
---|
284 | procedure TPlayerMPlayer.Stop;
|
---|
285 | begin
|
---|
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;
|
---|
297 | end;
|
---|
298 |
|
---|
299 | constructor TPlayerMPlayer.Create;
|
---|
300 | begin
|
---|
301 | inherited;
|
---|
302 | FProcess := TProcess.Create(nil);
|
---|
303 | end;
|
---|
304 |
|
---|
305 | destructor TPlayerMPlayer.Destroy;
|
---|
306 | begin
|
---|
307 | Stop;
|
---|
308 | FreeAndNil(FProcess);
|
---|
309 | inherited;
|
---|
310 | end;
|
---|
311 |
|
---|
312 | function TPlayerMPlayer.GetProcessOutput: string;
|
---|
313 | var
|
---|
314 | AStringList: TStringList;
|
---|
315 | begin
|
---|
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;
|
---|
330 | end;
|
---|
331 |
|
---|
332 | end.
|
---|
333 |
|
---|