Advanced Usage and Remarks

Multiple monitors / GPUs

std::shared_ptr<DXCam::DXCamera> cam1 = DXCam::create(0, 0);
std::shared_ptr<DXCam::DXCamera> cam2 = DXCam::create(0, 1);
std::shared_ptr<DXCam::DXCamera> cam3 = DXCam::create(1, 1);
cv::Mat img1 = cam1->grab();
cv::Mat img2 = cam2->grab();
cv::Mat img3 = cam3->grab();

The above code creates three DXCam::DXCamera instances for: [monitor0, GPU0], [monitor1, GPU0], [monitor1, GPU1], and subsequently takes three full-screen screenshots. (Like Python DXcam, cross-GPU untested, but I also hope it works.)

To get a complete list of devices and outputs, call DXCam::get_devices_info() and DXCam::get_outputs_info():

std::vector<DXCam::DeviceInfo> devices_info = DXCam::get_devices_info();
std::vector<std::vector<DXCam::OutputInfo>> outputs_info = DXCam::get_outputs_info();

Here is the declaration of DXCam::DeviceInfo and DXCam::OutputInfo:

struct DXCam::DeviceInfo {
    std::wstring description;
    SIZE_T vram_size;
    UINT vendor_id;
};

struct DXCam::OutputInfo {
    std::wstring device_name;
    LONG width;
    LONG height;
    int rotation_angle;
};

Video buffer

The captured frames will be insert into a fixed-size ring buffer, and when the buffer is full the newest frame will replace the oldest frame. You can specify the maximum buffer length (default to 64) by setting the argument max_buffer_len upon creation of the DXCam::DXCamera instance.

DXCam::DXCamera camera = DXCam::create(0, -1, 512);

Consuming frames from buffer

To consume frames during capturing there is DXCam::DXCamera::get_latest_frame() available which assume the user to process frames in a LIFO pattern. This is a read-only action and won’t pop the processed frame from the buffer.

Going further than the Python DXcam, you may call DXCam::DXCamera::get_frame_buffer() to obtain the whole frame buffer:

const cv::Mat *const *frame_buffer;
const std::atomic_int *head, *tail;
const size_t *len;
const std::atomic_bool *full;
std::mutex *const *frame_buffer_mutex;
std::mutex *frame_buffer_all_mutex;

camera.get_frame_buffer(&frame_buffer, &frame_buffer_mutex, &len, &head,
                        &tail, &full, &frame_buffer_all_mutex);

{
    // you should lock frame_buffer_all_mutex when reading the frame buffer
    std::scoped_lock lock(*frame_buffer_all_mutex);

    // read the frame buffer in a correct order
    for (size_t i = *head; i != *tail; i = (i + 1) % *len) {
        cv::Mat frame = (*frame_buffer)[i];

        // Do something with the frame
    }
}

The frame buffer is readonly.

Important

You should lock frame_buffer_all_mutex while reading the frame buffer.

Target FPS

To set the target FPS, set the target_fps argument upon calling DXCam::DXCamera::start().

camera.start(60);

Video mode

The default behavior of DXCam::DXCamera::get_latest_frame() only put newly rendered frames in the buffer, which suits the usage scenario of an object detection or machine learning pipeline. However, when recording a video that is not ideal since we aim to get the frames at a constant framerate.

To capture frames at a constant framerate, you may set the video_mode argument to true when calling DXCam::DXCamera::start(), so that the frame buffer will be fed at the target fps. If there is no new frame available, the last rendered frame will be duplicated and put into the buffer.

Safely releasing of resource

Upon calling DXCam::DXCamera::stop(), DXCamera will stop the active capture and free the frame buffer.

Upon deleting all std::shared_ptr<DXCam::DXCamera> objects referring to a DXCam::DXCamera object, it will stop any active capturing, free the buffer, and release the duplicator and staging resource.

Actually, you do not need to manually handle the resource releasing since std::shared_ptr will automatically manage the lifetime of the object it refers to. However, if you want to manually release the resource or recreate a DXCam::DXCamera instance, you may manually delete it by calling std::shared_ptr::reset() on the std::shared_ptr<DXCam::DXCamera> object.

std::shared_ptr<DXCam::DXCamera> camera1 = DXCam::create(0);
std::shared_ptr<DXCam::DXCamera> camera2 = DXCam::create(0);  // Not allowed, camera1 will be returned
assert(camera1 == camera2);
camera1.reset();
camera2 = DXCam::create(0);  // Allowed