Skip to content

Commit 3ba84e6

Browse files
committed
Refactor DRM grabber
1 parent ab1c933 commit 3ba84e6

File tree

3 files changed

+892
-555
lines changed

3 files changed

+892
-555
lines changed
Lines changed: 168 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
22

33
#include <map>
4-
#include <memory>
4+
#include <memory>
5+
#include <vector>
56

67
// DRM
78
#include <drm_fourcc.h>
@@ -37,75 +38,211 @@ struct Encoder
3738
std::map<std::string, DrmProperty, std::less<>> props;
3839
};
3940

41+
struct DrmResources {
42+
using drmModeConnectorPtr_unique = std::unique_ptr<drmModeConnector, decltype(&drmModeFreeConnector)>;
43+
using drmModeCrtcPtr_unique = std::unique_ptr<drmModeCrtc, decltype(&drmModeFreeCrtc)>;
44+
45+
std::vector<drmModeConnectorPtr_unique> connectors;
46+
std::vector<drmModeCrtcPtr_unique> crtcs;
47+
};
48+
4049
///
4150
/// The DRMFrameGrabber is used for creating snapshots of the display (screenshots)
4251
///
4352
class DRMFrameGrabber : public Grabber
53+
/**
54+
* @brief The DRMFrameGrabber class is a screen grabber that uses the Linux Direct Rendering Manager (DRM)
55+
* API to capture the screen content. This method is generally faster and more efficient than X11-based
56+
* methods, as it operates at a lower level. It is suitable for systems without a running X server,
57+
* such as dedicated media centers.
58+
*/
4459
{
4560
public:
46-
///
47-
/// Construct a DRMFrameGrabber that will capture snapshots with specified dimensions.
48-
///
49-
/// @param[in] device The framebuffer device name/path
50-
///
61+
/**
62+
* @brief Constructs a DRMFrameGrabber.
63+
*
64+
* @param deviceIdx The index of the DRM device to use (e.g., 0 for /dev/dri/card0).
65+
* @param cropLeft Number of pixels to crop from the left of the screen.
66+
* @param cropRight Number of pixels to crop from the right of the screen.
67+
* @param cropTop Number of pixels to crop from the top of the screen.
68+
* @param cropBottom Number of pixels to crop from the bottom of the screen.
69+
*/
5170
explicit DRMFrameGrabber(int deviceIdx = 0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
5271

72+
/**
73+
* @brief Destructor for the DRMFrameGrabber.
74+
* Ensures that all DRM resources are properly released by calling freeResources().
75+
*/
5376
~DRMFrameGrabber() override;
5477

78+
/**
79+
* @brief Releases all allocated DRM resources.
80+
* This includes closing the device file descriptor and freeing memory associated with
81+
* connectors, encoders, CRTCs, planes, and framebuffers.
82+
*/
5583
void freeResources();
5684

57-
///
58-
/// Captures a single snapshot of the display and writes the data to the given image. The
59-
/// provided image should have the same dimensions as the configured values (_width and
60-
/// _height)
61-
///
62-
/// @param[out] image The snapped screenshot (should be initialized with correct width and
63-
/// height)
64-
///
85+
/**
86+
* @brief Captures a single frame from the configured DRM device.
87+
* The captured frame is processed (cropped and scaled) and stored in the provided image object.
88+
*
89+
* @param[out] image The Image object to store the captured frame. It must be initialized
90+
* with the correct dimensions before calling this function.
91+
* @return 0 on success, a negative value on failure.
92+
*/
6593
int grabFrame(Image<ColorRgb> & image) override;
6694

67-
///
68-
/// @brief Setup a new capture screen, will free the previous one
69-
/// @return True on success, false if no screen is found
70-
///
95+
/**
96+
* @brief Initializes the DRM device for screen capturing.
97+
* This involves opening the device, identifying active connectors, CRTCs, and planes,
98+
* and setting up the necessary resources for grabbing frames.
99+
*
100+
* @return True if the screen was set up successfully, false otherwise.
101+
*/
71102
bool setupScreen() override;
72103

104+
/**
105+
* @brief Gets the resolution of the currently configured screen.
106+
*
107+
* @return A QSize object containing the width and height of the screen.
108+
*/
73109
QSize getScreenSize() const override;
110+
111+
/**
112+
* @brief Gets the resolution of a specific DRM device.
113+
*
114+
* @param device The name of the device (e.g., "card0").
115+
* @return A QSize object containing the width and height of the specified screen.
116+
*/
74117
QSize getScreenSize(const QString& device) const;
75118

76-
///
77-
///@brief Set new width and height for the DRM-grabber, overwrite Grabber.h implementation
119+
/**
120+
* @brief Sets the desired capture width and height.
121+
* This will affect the dimensions of the image returned by grabFrame().
122+
*
123+
* @param width The desired capture width.
124+
* @param height The desired capture height.
125+
* @return True on success, false on failure.
126+
*/
78127
bool setWidthHeight(int width, int height) override;
79128

129+
/**
130+
* @brief Returns the full device path for the current DRM grabber instance.
131+
* For example, "/dev/dri/card0".
132+
*
133+
* @return A QString containing the device name.
134+
*/
80135
QString getDeviceName() const {return QString("%1/%2%3").arg(DRM_DIR_NAME, DRM_PRIMARY_MINOR_NAME).arg(_input);}
81136

137+
/**
138+
* @brief Retrieves a list of available DRM input devices.
139+
*
140+
* @return A QJsonArray where each element is a QJsonObject describing a found device.
141+
*/
82142
QJsonArray getInputDeviceDetails() const override;
83143

84-
///
85-
/// @brief Discover DRM screens available (for configuration).
86-
///
87-
/// @param[in] params Parameters used to overwrite discovery default behaviour
88-
///
89-
/// @return A JSON structure holding a list of devices found
90-
///
144+
/**
145+
* @brief Discovers available DRM devices and their properties.
146+
* This is used for configuration purposes, allowing a user to see available screens.
147+
*
148+
* @param params JSON object with parameters to customize the discovery process.
149+
* @return A QJsonObject containing a list of discovered devices and their details.
150+
*/
91151
QJsonObject discover(const QJsonObject& params);
92152

93153
private:
94154

155+
/**
156+
* @brief Opens the DRM device file descriptor.
157+
* @return True on success, false on failure.
158+
*/
95159
bool openDevice();
160+
161+
/**
162+
* @brief Closes the DRM device file descriptor.
163+
* @return True on success, false on failure.
164+
*/
96165
bool closeDevice();
166+
167+
/**
168+
* @brief Gathers information about the active screen configuration.
169+
* This includes enumerating connectors, encoders, finding the active CRTC and primary plane.
170+
* @return True on success, false on failure.
171+
*/
97172
bool getScreenInfo();
98173

174+
/**
175+
* @brief Helper function to discover DRM resources for a given device.
176+
* @param[in] device The device path (e.g., "/dev/dri/card0").
177+
* @param[out] resources A struct to be filled with the discovered resource information.
178+
* @return True on success, false on failure.
179+
*/
180+
bool discoverDrmResources(const QString& device, DrmResources& resources) const;
181+
182+
/**
183+
* @brief Sets the client capabilities for the DRM device connection.
184+
* Specifically, it requests universal plane support.
185+
*/
186+
void setDrmClientCaps();
187+
188+
/**
189+
* @brief Enumerates all available connectors and encoders for the device.
190+
* @param resources The DRM resources structure obtained from the device.
191+
*/
192+
void enumerateConnectorsAndEncoders(const drmModeRes* resources);
193+
194+
/**
195+
* @brief Finds the active CRTC (CRT Controller) that is connected to a display.
196+
* @param resources The DRM resources structure obtained from the device.
197+
*/
198+
void findActiveCrtc(const drmModeRes* resources);
199+
200+
/**
201+
* @brief Checks if a given plane is the primary plane for the active CRTC.
202+
* @param planeId The ID of the plane to check.
203+
* @param properties The properties of the plane object.
204+
* @return True if it is the primary plane, false otherwise.
205+
*/
206+
bool isPrimaryPlaneForCrtc(uint32_t planeId, const drmModeObjectProperties* properties);
207+
208+
/**
209+
* @brief Finds the primary display plane associated with the active CRTC.
210+
* The primary plane is the one that holds the main desktop image.
211+
* @param planeResources The list of available planes.
212+
*/
213+
void findPrimaryPlane(const drmModePlaneRes* planeResources);
214+
215+
/**
216+
* @brief Retrieves properties for various DRM objects like connectors and planes.
217+
* This is currently a placeholder and not fully implemented.
218+
*/
219+
void getDrmObjectProperties() const;
220+
221+
/**
222+
* @brief Retrieves the framebuffer(s) associated with the primary plane.
223+
* This is necessary to get a handle to the screen's pixel data.
224+
*/
225+
void getFramebuffers();
226+
227+
/// The file descriptor for the opened DRM device.
99228
int _deviceFd;
100-
/// Map of available connectors
229+
230+
/// Map of available connectors (e.g., HDMI, DP), keyed by connector ID.
101231
std::map<uint32_t, std::unique_ptr<Connector>> _connectors;
102232

103-
/// Map of available encoders
233+
/// Map of available encoders, keyed by encoder ID.
104234
std::map<uint32_t, std::unique_ptr<Encoder>> _encoders;
105-
drmModeCrtcPtr _crtc;
106-
std::map<uint32_t, drmModePlanePtr> _planes;
235+
236+
/// Pointer to the active CRTC (CRT Controller).
237+
drmModeCrtcPtr _crtc;
238+
239+
/// Map of available display planes, keyed by plane ID.
240+
std::map<uint32_t, drmModePlanePtr> _planes;
241+
242+
/// Map of framebuffers attached to the CRTC, keyed by framebuffer ID.
107243
std::map<uint32_t, drmModeFB2Ptr> _framebuffers;
108244

245+
/// The pixel format of the captured framebuffer.
109246
PixelFormat _pixelFormat;
110247
};
111248

include/utils/PixelFormat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ enum class PixelFormat {
1515
RGB32,
1616
BGR32,
1717
NV12,
18+
NV21,
19+
P030,
1820
I420,
1921
MJPEG,
2022
NO_CHANGE

0 commit comments

Comments
 (0)