使用 Delphi 自动化 VideoLan 的 VLC
Automating VideoLan's VLC using Delphi
我已经从 VideoLan 的 VLC 播放器 v.2.2.1 生成了一个类型库导入单元
并以简单的 Delphi(D7 和 XE8)形式嵌入生成的插件组件。代码摘录如下。
该组件的基本功能很好 - 我可以播放(本地).MP4 文件,
停止它,上下加速等等没有任何问题。然而,有一个基本的
功能不起作用,即音量控制。
该插件显示一个v. simple(与VLC 运行中的一个应用程序相比)
底部的工具栏有两个轨迹条,一个用于显示+改变播放
视频中的位置,另一个用于控制音量。后者是
初始显示音量为 100 (%)。
如果我尝试通过单击轨迹栏来更改它,我会收到“未处理的太多
异常”错误 (EInvalidOp)。如果我安装一个 Application.OnException 处理程序并且
捕获异常,插件变得无响应,我必须重置应用程序
在 IDE。如果我在代码中读取音量设置然后设置
它是我刚刚读到的值。
插件调用的内部事件,Get8087CW returns相同的值,
4798,因为我在应用程序启动时保存。
我的问题是:如何在尝试更改时避免这些异常
通过 GUI 轨迹栏或代码进行音量?我错过了一步吗,也许,还是有
在将 8087 值或异常处理设置为
防止应用程序锁定? (顺便说一句,可以在代码中打开插件工具栏的显示,所以如果其他方法都失败了,我可以用我自己的工具栏替换它,但如果可能的话,我宁愿让 VLC 工具栏正常工作)。
代码:
TForm1 = class(TForm)
VLCPlugin1: TVLCPlugin;
[...]
public
{ Public declarations }
IPlugIn : IVlcControl;
IPlugIn2 : IVlcControl2;
Input : IVlcInput;
PlayList : IVlcPlayList;
IAudio : IVlcAudio;
Speed : Integer;
Volume : Integer;
Saved8087CW : Integer;
procedure PlayFile;
property FileName : WideString read FFileName write SetFileName;
end;
// This routine, NoOp, is one I've used since D1 to facilitate single-stepping
// through code and checking values on the way. It accesses the NoOpCount
// global variable because I assumed/hoped the compiler's optimiser wouldn't optimise it away.
var
NoOpCount : Integer;
procedure NoOp;
begin
Inc(NoOpCount);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnException := HandleException;
Saved8087CW := Get8087CW;
end;
procedure TForm1.PlayFile;
begin
Assert((Trim(FileName) <> '') and (FileExists(FileName)));
if VLCPlugIn1.Playing then
VLCPlugIn1.stop;
IPlugIn := VlcPlugIn1.ControlInterface;
//VLC's VLCPlugIn2 contains some extra methods compared to VLCPlugIn, so
IPlugIn.QueryInterface(VlcPlugIn2, IPlugIn2);
if IPlugIn2 = Nil then
NoOp
else
NoOp;
IAudio := IPlugIn2.Audio; // this is the interface to the object which gets/sets the volume
if IAudio = Nil then
NoOp
else
NoOp;
Input := IPlugIn2.Input;
if Input = Nil then
NoOp
else
NoOp;
VLCPlugin1.addTarget('file:///' + FileName, null, VLCPlayListInsert, 0);
{ The following assignment to IAudio.Volume causes an EInvalidOp exception
Volume := IAudio.Volume;
IAudio.Volume := Volume;
}
VlcPlugIn1.AutoLoop := True;
IPlugIn2.playlist.play;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if IPlugIn.Playing then
IPlugIn.Stop;
end;
procedure TForm1.VLCPlugin1MediaPlayerPlaying(Sender: TObject);
begin
if Saved8087CW = Get8087CW then
NoOp
else
NoOp;
end;
procedure TForm1.VLCPlugin1play(Sender: TObject);
begin
if IAudio <> Nil then begin
Volume := IAudio.Volume;
// IAudio.Volume := Volume; <- provokes EInvalidOp
end;
end;
procedure TForm1.HandleException(Sender: TObject; E: Exception);
begin
if Saved8087CW = Get8087CW then
NoOp
else
NoOp;
end;
尝试在启动时禁用 FPU 异常:
Set8087CW(3F);
或(对于现代 Delphi)
Math.SetExceptionMask(exAllArithmeticExceptions);
我已经从 VideoLan 的 VLC 播放器 v.2.2.1 生成了一个类型库导入单元 并以简单的 Delphi(D7 和 XE8)形式嵌入生成的插件组件。代码摘录如下。
该组件的基本功能很好 - 我可以播放(本地).MP4 文件, 停止它,上下加速等等没有任何问题。然而,有一个基本的 功能不起作用,即音量控制。
该插件显示一个v. simple(与VLC 运行中的一个应用程序相比) 底部的工具栏有两个轨迹条,一个用于显示+改变播放 视频中的位置,另一个用于控制音量。后者是 初始显示音量为 100 (%)。
如果我尝试通过单击轨迹栏来更改它,我会收到“未处理的太多 异常”错误 (EInvalidOp)。如果我安装一个 Application.OnException 处理程序并且 捕获异常,插件变得无响应,我必须重置应用程序 在 IDE。如果我在代码中读取音量设置然后设置 它是我刚刚读到的值。
插件调用的内部事件,Get8087CW returns相同的值, 4798,因为我在应用程序启动时保存。
我的问题是:如何在尝试更改时避免这些异常 通过 GUI 轨迹栏或代码进行音量?我错过了一步吗,也许,还是有 在将 8087 值或异常处理设置为 防止应用程序锁定? (顺便说一句,可以在代码中打开插件工具栏的显示,所以如果其他方法都失败了,我可以用我自己的工具栏替换它,但如果可能的话,我宁愿让 VLC 工具栏正常工作)。
代码:
TForm1 = class(TForm)
VLCPlugin1: TVLCPlugin;
[...]
public
{ Public declarations }
IPlugIn : IVlcControl;
IPlugIn2 : IVlcControl2;
Input : IVlcInput;
PlayList : IVlcPlayList;
IAudio : IVlcAudio;
Speed : Integer;
Volume : Integer;
Saved8087CW : Integer;
procedure PlayFile;
property FileName : WideString read FFileName write SetFileName;
end;
// This routine, NoOp, is one I've used since D1 to facilitate single-stepping
// through code and checking values on the way. It accesses the NoOpCount
// global variable because I assumed/hoped the compiler's optimiser wouldn't optimise it away.
var
NoOpCount : Integer;
procedure NoOp;
begin
Inc(NoOpCount);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnException := HandleException;
Saved8087CW := Get8087CW;
end;
procedure TForm1.PlayFile;
begin
Assert((Trim(FileName) <> '') and (FileExists(FileName)));
if VLCPlugIn1.Playing then
VLCPlugIn1.stop;
IPlugIn := VlcPlugIn1.ControlInterface;
//VLC's VLCPlugIn2 contains some extra methods compared to VLCPlugIn, so
IPlugIn.QueryInterface(VlcPlugIn2, IPlugIn2);
if IPlugIn2 = Nil then
NoOp
else
NoOp;
IAudio := IPlugIn2.Audio; // this is the interface to the object which gets/sets the volume
if IAudio = Nil then
NoOp
else
NoOp;
Input := IPlugIn2.Input;
if Input = Nil then
NoOp
else
NoOp;
VLCPlugin1.addTarget('file:///' + FileName, null, VLCPlayListInsert, 0);
{ The following assignment to IAudio.Volume causes an EInvalidOp exception
Volume := IAudio.Volume;
IAudio.Volume := Volume;
}
VlcPlugIn1.AutoLoop := True;
IPlugIn2.playlist.play;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if IPlugIn.Playing then
IPlugIn.Stop;
end;
procedure TForm1.VLCPlugin1MediaPlayerPlaying(Sender: TObject);
begin
if Saved8087CW = Get8087CW then
NoOp
else
NoOp;
end;
procedure TForm1.VLCPlugin1play(Sender: TObject);
begin
if IAudio <> Nil then begin
Volume := IAudio.Volume;
// IAudio.Volume := Volume; <- provokes EInvalidOp
end;
end;
procedure TForm1.HandleException(Sender: TObject; E: Exception);
begin
if Saved8087CW = Get8087CW then
NoOp
else
NoOp;
end;
尝试在启动时禁用 FPU 异常:
Set8087CW(3F);
或(对于现代 Delphi)
Math.SetExceptionMask(exAllArithmeticExceptions);