需要帮助在构建图形的上下文中找到与 VCL TpaintBox.Canvas.Handle 等效的 FireMonkey

Need help to find FireMonkey equivalent of the VCL TpaintBox.Canvas.Handle in the context of building graph

前言: 我正在使用 Black Magic Design (BMD) Decklink 输入卡来获取高清视频信号。他们在 SDK 中提供 C++ 示例。我已经成功地将 c++ 示例翻译成 Delphi (VCL)。我还在 TDecklink 中隔离了 API 调用 我希望它对 Delphi 社区可用。它在 VCL 中运行良好(如果需要,我可以为 TDecklnk 提供一个演示应用程序来使用它)。

现在我需要以 FMX 形式获取信号(但不能交叉编译到 Windows 以外的其他平台)。我试图修改 TDecklink 以在 FMX 中使用但没有成功。

核心问题:
在我的 VCL 版本中,我将 TPaintBox 引用传递到我的 TDecklink。 TPaintBox 被 GraphBuilder 用作显示实时视频的区域。

这是我在 VCL 版本中用于将 TPaintBox 分配给 GraphBuilder 的一些代码行:

      pWnd := WindowFromDC(FpboxPreview.Canvas.Handle);   //WindowFromDC  retreive HWND from HDC
      hr:= pIVMRWindowlessCtrl.SetVideoClippingWindow(pWnd);   // set the bounds of the video to the preview window
      if hr = S_OK then
      begin
        previewRect.Left   := FpboxPreview.Left;
        previewRect.Right  := FpboxPreview.Width;
        previewRect.Top    := FpboxPreview.Top;
        previewRect.Bottom := FpboxPreview.Height;
        hr:= pIVMRWindowlessCtrl.SetVideoPosition(nil, @previewRect);   // show the whole of the source frame in the whole of the client area of the control
        hr:= pIVMRWindowlessCtrl.SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); // maintain the aspect ratio of the video
        hr:= pIVMRWindowlessCtrl.SetBorderColor(GetSysColor(COLOR_BTNFACE));    // set the colour of the letter or pillar boxed area 

其中 PWnd 是一个 HWND

在 FMX 中,用于提供 GraphBuilder 期望接收的内容的最佳组件和参数是什么?

在 VCL 中,TPaintBox 是一个 TGraphicControl 后代,它绘制到其 Parent 控件的 HWNDHDC 上。当 Parent 控件收到 WM_PAINT 消息时,它会根据需要将自己绘制到提供的 HDC 上,然后暂时将相同的 HDC 分配给每个 child TGraphicControl 绘制它们时,将 HDC 剪裁到每个 child 的坐标和相应的矩形。如果您尝试从其 Parent 控件的 WM_PAINT 处理程序外部绘制到 TGraphicControl.Canvas(您永远不应该这样做),TCanvas 将暂时获取 Parent控件的 HDC 使用 Win32 API GetDC() 函数。

因此,这条语句:

pWnd := WindowFromDC(FpboxPreview.Canvas.Handle);

实际上与此相同:

pWnd := FpboxPreview.Parent.Handle;

因此,您实际上是将视频放在 TPaintBox.Parent 控件的 window 上,而不是 TPaintBox 本身。如果您希望视频与其自己的控件关联,请考虑使用 TPanel,因为它是 TWinControl 的后代,具有自己的 HWND.

另一方面,

FireMonkey 没有TGraphicControlTWinControl 的概念。每个控件都是 TControl 的后代,具有覆盖的 Paint() 方法来处理 TCanvas 上的任何自定义绘图,该 TCanvas 由 parent TForm 或调用者提供TControl.PaintTo() 方法。 FireMonkey 甚至不为每个控件创建 HWND。只有 parent TForm 有自己的 HWND(因此它可以与 OS 交互)。 Child 控件直接绘制到 window 上,相应地调整绘制坐标和裁剪矩形(在后台,FireMonkey 使用 DirectX (Windows) 或 OpenGL(其他平台)对于它的所有绘图)。

因此,如果您确实需要 HWND 来显示您的视频 class,您必须:

  1. 使用 TFormHWND,您可以通过将其 Handle 属性 传递给 FMX.Platform.Win.WindowHandleToPlatform() function (or the FMX.Platform.Win.FmxHandleToHWND() 旧版 FireMonkey 的功能):

    uses
      ..., FMX.Platform.Win;
    
    pWnd := WindowHandleToPlatform(Form1.Handle);
    

    或将 TForm 本身传递给 FMX.Platform.Win.FormToHWND() 函数:

    uses
      ..., FMX.Platform.Win;
    
    pWnd := FormToHWND(Form1);
    
  2. 直接使用 Win32 API 根据需要创建自己的 HWND,然后将其嵌入到 TFormHWND 中。

否则,您将不得不在 FireMonkey 中 re-think 您的视频 UI。例如,假设视频 class 可以为您提供视频帧的图像,您可以从 TPaintBox.OnPaint 事件中将它们绘制到 TPaintBox.Canvas 上(TPaintBox应该首先在 VCL 和 FireMonkey 中使用)。或者可能派生出您自己的自定义 TControl,以其自己覆盖的 Paint() 方法从视频 class 中提取图像。我不知道你的 GraphBuilder class 有什么功能,但 BMD 提供了一个 SDK 用于控制视频 recording/playback 硬件和访问视频数据(参见 this PDF)。