<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      dotnet X11 獲取多屏 edid 信息

      我需要獲取準確的顯示器屏幕關聯的設備信息,在屏幕對應的 Edid 信息里面記錄了我需要的物理設備信息。我嘗試通過 /sys/class/drm/ 路徑讀取,但遇到了關聯問題,不知道哪個 Edid 文件應該對應哪個屏幕。我不想去猜測,于是詢問了 Handsome08 了解到了使用 XRRGetOutputProperty 獲取 Edid 數據的方法。具體的方法如下

      通過 XRRGetMonitors 方法獲取當前設備的每個顯示器屏幕信息,其方法定義代碼如下

              const string libX11Randr = "libXrandr.so.2";
      
              [DllImport(libX11Randr)]
              public static extern XRRMonitorInfo* XRRGetMonitors(IntPtr dpy, IntPtr window, bool get_active, out int nmonitors);
      

      返回的 XRRMonitorInfo 結構體定義如下

          public unsafe struct XRRMonitorInfo
          {
              public IntPtr Name;
              public int Primary;
              public int Automatic;
              public int NOutput;
              public int X;
              public int Y;
              public int Width;
              public int Height;
              public int MWidth;
              public int MHeight;
              public IntPtr* Outputs;
          }
      

      為了方便上層調用,我將其再次封裝,封裝了 MonitorInfo 結構體,代碼如下

      public unsafe struct MonitorInfo
      {
          public IntPtr Name;
          public bool IsPrimary;
          public int X;
          public int Y;
          public int Width;
          public int Height;
          public IntPtr[] Outputs;
          public IntPtr Display { get; init; }
      
          public string? GetNameText()
          {
              var namePtr = XGetAtomName(Display, Name);
              var name = Marshal.PtrToStringAnsi(namePtr);
              XFree(namePtr);
              return name;
          }
      
          public override string ToString()
          {
              var name = GetNameText();
      
              return $"{name}({Name}) IsPrimary={IsPrimary} XY={X},{Y} WH={Width},{Height}";
          }
      }
      

      于是獲取屏幕信息的代碼就可以這么寫

      // Copy from https://github.com/AvaloniaUI/Avalonia \src\Avalonia.X11\Screens\X11Screen.Providers.cs
      
      public class Randr15ScreensImpl
      {
          public Randr15ScreensImpl(nint display, nint rootWindow)
          {
              _display = display;
              var eventWindow = CreateEventWindow(display, rootWindow);
              _window = eventWindow;
      
              XRRSelectInput(display, _window, RandrEventMask.RRScreenChangeNotify);
          }
      
          public unsafe MonitorInfo[] GetMonitorInfos()
          {
              XRRMonitorInfo* monitors = XRRGetMonitors(_display, _window, true, out var count);
              var screens = new MonitorInfo[count];
              for (var c = 0; c < count; c++)
              {
                  var mon = monitors[c];
      
                  var outputs = new nint[mon.NOutput];
      
                  for (int i = 0; i < outputs.Length; i++)
                  {
                      outputs[i] = mon.Outputs[i];
                  }
      
                  screens[c] = new MonitorInfo()
                  {
                      Name = mon.Name,
                      IsPrimary = mon.Primary != 0,
                      X = mon.X,
                      Y = mon.Y,
                      Width = mon.Width,
                      Height = mon.Height,
                      Outputs = outputs,
                      Display = _display,
                  };
              }
      
              return screens;
          }
      
          private readonly IntPtr _display;
      
          private readonly IntPtr _window;
      }
      

      以上代碼是從 Avalonia 項目拷貝的。經過了 SeWZC 的考證,傳入 XRRGetMonitors 的窗口應該是 RootWindow 窗口,然而在本文這里和 Avalonia 這里都傳入的是一個 EventWindow 窗口,且傳入 EventWindow 窗口能拿到正確的值,十分有趣,更底層原因我就沒有繼續調查了

      以上代碼的 CreateEventWindow 方法的實現如下

              public static IntPtr CreateEventWindow(nint display, nint rootWindow)
              {
                  var win = XCreateSimpleWindow(display, rootWindow,
                      0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero);
                  return win;
              }
      
              [DllImport(libX11)]
              public static extern IntPtr XCreateSimpleWindow(IntPtr display, IntPtr parent, int x, int y, int width,
                  int height, int border_width, IntPtr border, IntPtr background);
      
              const string libX11 = "libX11.so.6";
      

      拿到 MonitorInfo 對象之后,可以看到里面有很多個屬性,其中的 Outputs 屬性就是本文的重點

      在這里我編寫一個循環將其逐個取出,其中可能有一個就是包含了 EDID 信息,代碼如下

      var display = XOpenDisplay(IntPtr.Zero);
      var screen = XDefaultScreen(display);
      var rootWindow = XDefaultRootWindow(display);
      
      var randr15ScreensImpl = new Randr15ScreensImpl(display, rootWindow);
      MonitorInfo[] monitorInfos = randr15ScreensImpl.GetMonitorInfos();
      
      for (var i = 0; i < monitorInfos.Length; i++)
      {
          MonitorInfo monitorInfo = monitorInfos[i];
          Console.WriteLine(monitorInfo);
      
          OutputEdidInfo(monitorInfo);
      }
      

      在 OutputEdidInfo 方法里面,咱將進行 EDID 解析邏輯

      通過 XRRListOutputProperties 方法讀取 Outputs 里面的每一項,如果某一項中讀取到的屬性包含了 EDID Atom 內容,則證明當前項就是 EDID 信息

      其代碼如下

      unsafe void OutputEdidInfo(MonitorInfo monitorInfo)
      {
          var edidAtom = XInternAtom(display, "EDID", only_if_exists: true);
          var anyPropertyTypeAtom = XInternAtom(display, "AnyPropertyType", only_if_exists: true);
          const nint XA_INTEGER = 19;
      
          for (var i = 0; i < monitorInfo.Outputs.Length; i++)
          {
              var rrOutput = monitorInfo.Outputs[i];
              if (rrOutput == IntPtr.Zero)
              {
                  continue;
              }
      
              var properties = XRRListOutputProperties(display, rrOutput, out var propertyCount);
      
              IntPtr prop = 0;
      
              try
              {
                  var hasEDID = false;
                  for (var pc = 0; pc < propertyCount; pc++)
                  {
                      if (properties[pc] == edidAtom)
                      {
                          hasEDID = true;
                          break;
                      }
                  }
      
                  if (!hasEDID)
                  {
                      Console.WriteLine($"Output {rrOutput} does not have EDID property.");
                      continue;
                  }
      
                  ... // 忽略其他代碼
              }
              finally
              {
                  XLib.XFree(prop);
                  XLib.XFree(new IntPtr(properties));
              }
          }
      }
      

      如果當前項的 hasEDID 為 true 則通過 XRRGetOutputProperty 讀取屬性的值,代碼如下

                  // Length of a EDID-Block-Length(128 bytes), XRRGetOutputProperty multiplies offset and length by 4
                  const int EDIDStructureLength = 32;
      
                  XRRGetOutputProperty(display, rrOutput, edidAtom, 0, EDIDStructureLength, false, false,
                      anyPropertyTypeAtom, out IntPtr actualType, out int actualFormat, out int nItems, out long bytesAfter,
                      out prop);
      
                  // https://gitlab.gnome.org/GNOME/mutter/-/blame/3.29.90/src/backends/x11/meta-output-xrandr.c
      
                  if (actualType != XA_INTEGER)
                  {
                      continue;
                  }
      
                  if (actualFormat != 8) // Expecting a byte array
                  {
                      continue;
                  }
      
                  Span<byte> edid = new Span<byte>((void*) prop, (int) bytesAfter);
      

      此時即可讀取到 edid 二進制信息。此時的 edid 二進制信息還需要進一步的解析才能獲取內容。如何解析 edid 就不在本文范圍內了,大家可以使用自己喜歡的方式進行解析。本文這里只是做了簡單的內容解析,解析出了屏幕的物理尺寸信息。解析代碼封裝在 EdidInfo 結構體里面,如果大家感興趣,可以到本文末尾找到本文所有代碼的下載方法,下載代碼了解 Edid 解析邏輯

      解析之后將輸出物理設備信息,代碼如下

                  Span<byte> edid = new Span<byte>((void*)prop, (int)bytesAfter);
      
                  ReadEdidInfoResult edidInfoResult = EdidInfo.ReadEdid(edid);
                  if (edidInfoResult.IsSuccess)
                  {
                      EdidInfo edidInfo = edidInfoResult.EdidInfo;
      
                      Console.WriteLine($"EDID Info: ManufacturerName={edidInfo.ManufacturerName} MonitorPhysical={edidInfo.BasicDisplayParameters.MonitorPhysicalWidth.Value}x{edidInfo.BasicDisplayParameters.MonitorPhysicalHeight.Value}cm");
                  }
                  else
                  {
                      Console.WriteLine($"解析 Edid 失敗 {edidInfoResult.ErrorMessage}");
                  }
      

      在我的雙屏設備上運行,可以看到大概如下輸出信息。我的 DisplayPort-1 是主屏,放在右邊,是一個 165x93cm 的 75 寸大屏幕。副屏是 DisplayPort-0 放在左邊,是一個 190x107cm 的更大的屏幕

      DisplayPort-1(343) IsPrimary=True XY=1920,309 WH=1920,1080
      EDID Info: ManufacturerName=IWB MonitorPhysical=165x93cm
      DisplayPort-0(344) IsPrimary=False XY=0,0 WH=1920,1080
      EDID Info: ManufacturerName=IWB MonitorPhysical=190x107cm
      

      通過以上輸出,對比我的物理設備,發現可以對應上,通過此方法比從 /sys/class/drm/ 路徑下讀取更好,至少不用去猜路徑名。很多設備上,都可以在 /sys/class/drm/ 文件夾內找到和 XRRGetMonitors 返回的顯示器名對應的設備,但這取決于驅動,不一定能對應上。能從 XRRGetOutputProperty 獲取到的 Edid 信息才能完全對應

      本文代碼放在 githubgitee 上,可以使用如下命令行拉取代碼。我整個代碼倉庫比較龐大,使用以下命令行可以進行部分拉取,拉取速度比較快

      先創建一個空文件夾,接著使用命令行 cd 命令進入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼

      git init
      git remote add origin https://gitee.com/lindexi/lindexi_gd.git
      git pull origin 46db729ca3aaa4d73169d07e903c96f0aa2f7fee
      

      以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令行繼續輸入以下代碼,將 gitee 源換成 github 源進行拉取代碼。如果依然拉取不到代碼,可以發郵件向我要代碼

      git remote remove origin
      git remote add origin https://github.com/lindexi/lindexi_gd.git
      git pull origin 46db729ca3aaa4d73169d07e903c96f0aa2f7fee
      

      獲取代碼之后,進入 X11/FelocerebeWirolerco 文件夾,即可獲取到源代碼

      更多 X11 技術博客,請參閱 博客導航

      posted @ 2025-08-12 07:03  lindexi  閱讀(69)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日本边吃奶边摸边做在线视频| 毛片网站在线观看| 亚洲禁精品一区二区三区| 亚洲欧美日韩高清一区二区三区| 99热久久这里只有精品| 国产午夜精品福利免费不| 99精品伊人久久久大香线蕉| 中文字幕国产日韩精品| 91色老久久精品偷偷性色| 国产精品久久蜜臀av| 国产亚洲AV电影院之毛片| 人妻夜夜爽天天爽一区| 狠狠噜天天噜日日噜无码| 四川丰满少妇无套内谢| 久热爱精品视频线路一| 成人网站免费观看| 999精品全免费观看视频| 欧美人禽zozo动人物杂交| 亚洲av日韩av永久无码电影| 欧美三级中文字幕在线观看| 久久精品国产亚洲精品色婷婷| 国产成人精品午夜在线观看| 中文字幕无码免费久久9一区9| 久久亚洲av成人无码软件| 一区二区在线观看成人午夜| 一区二区三区人妻无码| 成人无码一区二区三区网站| 高清国产美女一级a毛片在线| 丝袜老师办公室里做好紧好爽| 国产一区二区三区亚洲精品| 成年女人免费视频播放体验区 | 一区二区三区激情都市| 人人爽人人爽人人爽| 中字幕人妻一区二区三区| 欧美人成精品网站播放| 国产精品麻豆欧美日韩ww| 国产成人无码av大片大片在线观看| 又爽又黄又无遮挡的激情视频| 二连浩特市| 国产精品人妻熟女男人的天堂| 免费人成视频网站在线18|