TMediaPlayerControl视频大小

Sco*_*ard 0 delphi firemonkey delphi-xe3

早上好家伙!

我目前正在尝试使用XE3,我对使用它构建视频(和普通媒体)播放器感兴趣FM2.我正面临一个关于视频比例的问题,或者更确切地说,看起来完全缺乏对它的支持.

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

另外请注意,视频区域显示在所有标准控件上方,无论它是否为"已发送回".

至少,我很欣赏使用新的FM²/ Firemonkey2 XE3媒体组件调整视频区域大小或缩放的任何输入.目前是否可能,或者我们是否会等待补丁来改进实施?

小智 5

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

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

将视频大小调整到包含控件(通常为a TMediaPlayerControl)的魔力是在TMedia.UpdateMediaFromControl方法中完成的,更确切地说是在特定于平台的 - TMedia主体UpdateMediaFromControl(TWindowsMedia.UpdateMediaFromControl在胜利时).

该方法用于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;
    
    Run Code Online (Sandbox Code Playgroud)
  3. 诀窍已经完成,让我们让FM2使用它.FM2使用一个TMediaCodecManager类来配对媒体类型(win上的文件扩展名)和TCustomMediaCodec-descendant(s)来播放它.Windows实现TWindowsMediaCodec用于所有支持的媒体文件格式.TCustomMediaCodec只有一个方法:CreateFromFile应该创建一个TMedia-descendant类来播放媒体文件.你将不得不创建自己的TCustomMediaCodec-descendant来使用你自己的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;
    
    Run Code Online (Sandbox Code Playgroud)
  4. 让我们说TMediaCodecManager使用我们的"编解码器" ... FMX.Media.Win将所有支持的媒体文件扩展名添加到该initialization部分的列表中,并且无法删除或更改它们,因此我们将解决此问题.注册我们自己的扩展,例如..###与我们的TMyMediaCodec.

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

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

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