1

早上好家伙!

我目前正在试验 XE3,我有兴趣使用FM2. 我面临一个关于视频规模的问题,或者更确切地说,似乎完全缺乏对它的支持。

我在表格中添加了 aTMediaPlayer和 aTMediaPlayerControl并将它们连接起来。然后我添加了一个具有简单播放/停止功能的按钮,以及另一个用于加载视频文件的按钮。但是,播放的每个视频都以实际分辨率播放(尽管 align 设置为alClient)。我已经尽可能地查看了文档和源代码,但我似乎找不到任何缩放或重新调整实际视频区域大小的方法。唯一的例外是如果我将实际窗口的大小调整为小于视频区域,此时它将在保持纵横比的同时缩小。

作为附加说明,视频区域出现在所有标准控件之上,无论它是否“发送回”。

至少,我很感激任何关于使用新的FM²/Firemonkey2 XE3 媒体组件调整或缩放视频区域的输入。目前是否有可能,还是我们将等待补丁来改进实施?

4

3 回答 3

6

目前 FM2 的内置实现不支持拉伸视图。

解决这个问题实际上是解决这个错误......对不起,这将是一个很长的帖子:)

将视频大小调整为包含控件(通常是 a TMediaPlayerControl)的魔法是在TMedia.UpdateMediaFromControl方法中完成的,更准确地说是在特定于平台的TMedia-descendant 中UpdateMediaFromControlTWindowsMedia.UpdateMediaFromControl在 win 上)。

该方法用于TRectF.Fit将视频大小调整为控件的客户区。该方法只支持缩小,不支持放大。所以你可能想改变这个......

我的解决方案可能并不完美,但它适用于我......

  1. 通过从 FM2 复制粘贴您的平台特定实现来创建您自己的TMedia后代 ( TMyMedia)。(例如。FMX.Media.Win.TWindowsMedia)。遗憾的是,创建后代类将不起作用,因为 Embarcadero 开发人员将所有必要的字段设为私有,因此后代类将无法访问它们。确保复制粘贴所有方法并保持原样。
  2. 仅更新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;
    
  3. 诀窍完成了,让我们让 FM2 使用它。FM2 使用一个TMediaCodecManager类来配对媒体类型(win 上的文件扩展名)和TCustomMediaCodec-descendant(s) 来播放它。Windows 实现TWindowsMediaCodec用于所有支持的媒体文件格式。TCustomMediaCodec只有一种方法:CreateFromFile应该创建一个TMedia-descendant 类来播放媒体文件。您将必须创建自己的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;
    
  4. 让我们告诉TMediaCodecManager使用我们的“编解码器” ...FMX.Media.Win将所有支持的媒体文件扩展名添加到该initialization部分的列表中,并且无法删除或更改它们,因此我们将解决这个问题。注册我们自己的扩展,例如。.###与我们的TMyMediaCodec.

    TMediaCodecManager.RegisterMediaCodecClass('.###', 'My Media Codec', TMediaType.Video, TMyMediaCodec);
    
  5. 要使用它,您必须.###在分配时将扩展名附加到所有媒体文件名TMediaPlayer.FileName,当然,在尝试播放文件之前必须删除此扩展名(见TMyMediaCodec.CreateFromFile上文)。

    MediaPlayer1.FileName := OpenDialog1.FileName + '.###';
    
  6. 当调用TMediaCodecManager.GetFilterString支持的媒体文件类型列表时,我们必须.###在使用列表之前手动删除扩展名,例如。在TOpenDialog.Filter.

我知道这个解决方案可能不是最优雅的,但它对我有用,直到 Embarcadero 愿意更新 FM2。

于 2013-01-14T21:11:22.297 回答
4

如果您无法访问源代码,您可以编写一个类助手:

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;
于 2013-11-19T10:04:08.730 回答
0

For a real stretch, I suggest the following changes to the MyRectFit function:

  function MyRectFit(var R: TRectF; const BoundsRect: TRectF): Single;
  var
    RatioX, RatioY: Single;
  begin
    Result := 1;
    if BoundsRect.Width * BoundsRect.Height = 0 then
      Exit;

    RatioX := R.Width / BoundsRect.Width;
    RatioY := R.Height / BoundsRect.Height;
    R := RectF(0, 0, R.Width / RatioX, R.Height / RatioY);

    Result := RatioX;
    RectCenter(R, BoundsRect);
  end;
于 2018-02-24T15:03:44.727 回答