早上好![/ p>
我目前正在尝试使用XE3,我有兴趣使用FM2
构建视频(和一般媒体)播放器。我正面临一个关于视频比例的问题,或者更确切地说,看起来完全没有支持它。
我在表单中添加了TMediaPlayer
和TMediaPlayerControl
并将其连接起来。然后我添加了一个具有简单播放/停止功能的按钮,另一个用于加载视频文件。但是,每个播放的视频都以其实际分辨率进行(尽管对齐设置为alClient
)。我尽可能地通过文档和源代码看,我似乎无法找到任何缩放或重新调整实际视频区域的方法。 ONLY 例外情况是,如果我将实际窗口的大小调整为小于视频区域,此时它将按比例缩小,同时保持宽高比。
作为补充说明,视频区域显示在所有标准控件上方,无论它是否为“已发送回”。
至少,我很欣赏使用新的FM²
/ Firemonkey2 XE3媒体组件调整视频区域大小或缩放的任何输入。目前是否可能,或者我们是否会等待补丁来改进实施?
答案 0 :(得分:5)
目前FM2的内置实现不支持拉伸视图。
解决这个问题实际上是要解决这个 bug ...对不起,这将是一个很长的帖子:)
将视频大小调整为包含控件(通常为TMediaPlayerControl
)的魔力是在TMedia.UpdateMediaFromControl
方法中完成的,更确切地说是在特定于平台的TMedia
- 后代的UpdateMediaFromControl
中(赢得TWindowsMedia.UpdateMediaFromControl
)。
该方法使用TRectF.Fit
将视频大小调整为控件的客户区。此方法仅支持按比例缩小但不支持按比例放大。所以你可能想改变这个......
我的解决方案可能不完美,但它对我有用......
TMedia
后代(TMyMedia
)。 (例如FMX.Media.Win.TWindowsMedia
)。遗憾的是,创建一个后代类是行不通的,因为Embarcadero开发人员将所有必要的字段设为私有,因此后代类将无法访问它们。确保复制粘贴所有方法并保持原样。仅更新UpdateMediaFromControl
:
procedure TMyMedia.UpdateMediaFromControl;
var
P: TPointF;
R: TRect;
Bounds: TRectF;
Form: TCommonCustomForm;
// this is just an updated version of TRecF.Fit to support scaling up
function MyRectFit(var R: TRectF; const BoundsRect: TRectF): Single;
var
ratio: Single;
begin
Result := 1;
if BoundsRect.Width * BoundsRect.Height = 0 then
Exit;
if (R.Width / BoundsRect.Width) > (R.Height / BoundsRect.Height) then
ratio := R.Width / BoundsRect.Width
else
ratio := R.Height / BoundsRect.Height;
// UPDATED
R := RectF(0, 0, R.Width / ratio, R.Height / ratio);
Result := ratio;
RectCenter(R, BoundsRect);
end;
begin
if FWnd <> 0 then
begin
if (Control <> nil) and not(csDesigning in Control.ComponentState) and
(Control.ParentedVisible) and (Control.Root <> nil) and
(Control.Root.GetObject is TCommonCustomForm) then
begin
Form := TCommonCustomForm(Control.Root.GetObject);
P := GetVideoSize;
Bounds := TRectF.Create(0, 0, P.X, P.Y);
// UPDATED:
// Bounds.Fit(RectF(0, 0, Control.AbsoluteWidth, Control.AbsoluteHeight));
MyRectFit(Bounds, RectF(0, 0, Control.AbsoluteWidth, Control.AbsoluteHeight));
Bounds.Offset(Control.AbsoluteRect.Left, Control.AbsoluteRect.Top);
SetParent(FWnd, FmxHandleToHWND(Form.Handle));
SetWindowPos(FWnd, 0, Bounds.Round.Left, Bounds.Round.Top, Bounds.Round.Width,
Bounds.Round.Height, 0);
R.Create(0, 0, Bounds.Round.Width, Bounds.Round.Height);
if FVMRWindowlessControl <> nil then
FVMRWindowlessControl.SetVideoPosition(nil, @R);
ShowWindow(FWnd, SW_SHOW)
end
else
ShowWindow(FWnd, SW_HIDE)
end;
end;
诀窍已经完成,让FM2使用它。 FM2使用TMediaCodecManager
类来配对媒体类型(win上的文件扩展名)和TCustomMediaCodec
- 后代来播放它。 Windows实现对所有支持的媒体文件格式使用TWindowsMediaCodec
。 TCustomMediaCodec
只有一个方法:CreateFromFile
,它应该创建一个TMedia
- 后代类来播放媒体文件。您必须创建自己的TCustomMediaCodec
- 后代才能使用您自己的TMyMedia
...
type
TMyMediaCodec = class(TCustomMediaCodec)
public
function CreateFromFile(const AFileName: string): TMedia; override;
end;
function TMyMediaCodec.CreateFromFile(const AFileName: string): TMedia;
begin
// LeftStr is for the extension trick - see later
Result := TMyMedia.Create(LeftStr(AFileName, Length(AFileName) - 4));
end;
让我们告诉TMediaCodecManager
使用我们的“codec” ... FMX.Media.Win
将所有支持的媒体文件扩展名添加到{{1}的列表中部分,并没有办法删除或更改它们,所以我们将解决这个问题。注册我们自己的扩展,例如。 initialization
与我们的.###
。
TMyMediaCodec
要使用它,您必须在分配给TMediaCodecManager.RegisterMediaCodecClass('.###', 'My Media Codec', TMediaType.Video, TMyMediaCodec);
时将.###
扩展名附加到所有媒体文件名,当然在尝试播放之前必须删除此扩展程序文件(参见上面的TMediaPlayer.FileName
)。
TMyMediaCodec.CreateFromFile
在调用MediaPlayer1.FileName := OpenDialog1.FileName + '.###';
以获取支持的媒体文件类型列表时,我们必须在使用列表之前手动删除TMediaCodecManager.GetFilterString
扩展名,例如。在.###
。
我知道这个解决方案可能不是最优雅但它适用于我,直到Embarcadero愿意更新FM2。
答案 1 :(得分:3)
如果您无权访问源代码,则可以编写类助手:
unit mediaPlayerStretchFix;
interface
uses windows,FMX.Platform.Win,FMX.Media.Win,FMX.Forms, system.types, fmx.controls,
system.Classes,directshow9;
type
TMediaPlayerTurbo = class helper for TWindowsMedia
private
function getFWnd: HWND;
function getFControl: TControl;
function getVMRWC: IVMRWindowlessControl9;
property leFWnd:HWND read getFWnd;
property leControl:TControl read getFControl;
property leFVMRWindowlessControl:IVMRWindowlessControl9 read getVMRWC;
public
procedure Stretch;
end;
implementation
procedure TMediaPlayerTurbo.Stretch;
var
P: TPointF;
R: TRect;
Bounds: TRectF;
Form: TCommonCustomForm;
// this is just an updated version of TRecF.Fit to support scaling up
function MyRectFit(var R: TRectF; const BoundsRect: TRectF): Single;
var
ratio: Single;
begin
Result := 1;
if BoundsRect.Width * BoundsRect.Height = 0 then
Exit;
if (R.Width / BoundsRect.Width) > (R.Height / BoundsRect.Height) then
ratio := R.Width / BoundsRect.Width
else
ratio := R.Height / BoundsRect.Height;
// UPDATED
R := RectF(0, 0, R.Width / ratio, R.Height / ratio);
Result := ratio;
RectCenter(R, BoundsRect);
end;
begin
if leFWnd <> 0 then
begin
if (leControl <> nil) and not(csDesigning in Control.ComponentState) and
(Control.ParentedVisible) and (Control.Root <> nil) and
(Control.Root.GetObject is TCommonCustomForm) then
begin
Form := TCommonCustomForm(Control.Root.GetObject);
P := self.GetVideoSize;
Bounds := TRectF.Create(0, 0, P.X, P.Y);
// UPDATED:
// Bounds.Fit(RectF(0, 0, Control.AbsoluteWidth, Control.AbsoluteHeight));
MyRectFit(Bounds, RectF(0, 0, Control.AbsoluteWidth, Control.AbsoluteHeight));
Bounds.Offset(Control.AbsoluteRect.Left, Control.AbsoluteRect.Top);
SetParent(leFWnd, FmxHandleToHWND(Form.Handle));
SetWindowPos(leFWnd, 0, Bounds.Round.Left, Bounds.Round.Top, Bounds.Round.Width,
Bounds.Round.Height, 0);
R.Create(0, 0, Bounds.Round.Width, Bounds.Round.Height);
if leFVMRWindowlessControl <> nil then
leFVMRWindowlessControl.SetVideoPosition(nil, @R);
ShowWindow(leFWnd, SW_SHOW)
end
else
ShowWindow(leFWnd, SW_HIDE)
end;
end;
function TMediaPlayerTurbo.getFControl: TControl;
begin
result:=TControl(fCOntrol);
end;
function TMediaPlayerTurbo.getFWnd: HWND;
begin
result:=self.fWnd;
end;
function TMediaPlayerTurbo.getVMRWC: IVMRWindowlessControl9;
begin
result:=self.FVMRWindowlessControl;
end;
end.
试验:
var
mp:TWindowsMedia
begin
mp:=TWindowsMedia.create(filename);
mp.Control:=videoframe;
mp.Play;
mp.Stretch;
end;