【问题标题】:TMediaPlayerControl Video SizeTMediaPlayerControl 视频大小
【发布时间】:2012-10-05 02:07:47
【问题描述】:

大家早上好!

我目前正在试验 XE3,我有兴趣使用 FM2 构建视频(和一般媒体)播放器。我面临一个关于视频规模的问题,或者更确切地说,似乎完全缺乏对它的支持。

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

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

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

【问题讨论】:

    标签: delphi firemonkey delphi-xe3


    【解决方案1】:

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

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

    将视频大小调整到包含控件(通常是TMediaPlayerControl)的魔法是在TMedia.UpdateMediaFromControl 方法中完成的,更准确地说是在特定于平台的TMedia-descendant 的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;
      
    3. 诀窍完成了,让我们让 FM2 使用它。 FM2 使用TMediaCodecManager 类来配对媒体类型(win 上的文件扩展名)和TCustomMediaCodec-descendant(s) 来播放它。 Windows 实现对所有支持的媒体文件格式使用TWindowsMediaCodecTCustomMediaCodec 只有一种方法: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;
      
    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。

    【讨论】:

      【解决方案2】:

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

      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;
      

      【讨论】:

        【解决方案3】:

        对于真正的延伸,我建议对 MyRectFit 函数进行以下更改:

          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;
        

        【讨论】:

          猜你喜欢
          • 2022-01-09
          • 1970-01-01
          • 2019-12-28
          • 1970-01-01
          • 2014-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-13
          相关资源
          最近更新 更多