1 /* GStreamer
2 * Copyright (C) 2019 OKADA Jun-ichi <okada@abt.jp>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-dxgiscreencapsrc
22 * @title: dxgiscreencapsrc
23 *
24 * This element uses DXGI Desktop Duplication API.
25 * The default is capturing the whole desktop, but #GstDXGIScreenCapSrc:x,
26 * #GstDXGIScreenCapSrc:y, #GstDXGIScreenCapSrc:width and
27 * #GstDXGIScreenCapSrc:height can be used to select a particular region.
28 * Use #GstDXGIScreenCapSrc:monitor for changing which monitor to capture
29 * from.
30 *
31 * ## Example pipelines
32 * |[
33 * gst-launch-1.0 dxgiscreencapsrc ! videoconvert ! dshowvideosink
34 * ]| Capture the desktop and display it.
35 * |[
36 * gst-launch-1.0 dxgiscreencapsrc x=100 y=100 width=320 height=240 !
37 * videoconvert ! dshowvideosink
38 * ]| Capture a portion of the desktop and display it.
39 *
40 */
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include <windows.h>
47 #include <versionhelpers.h>
48 #include <gst/video/video.h>
49 #include "gstdxgiscreencapsrc.h"
50 #include "dxgicapture.h"
51
52 GST_DEBUG_CATEGORY_EXTERN (gst_dxgi_screen_cap_src_debug);
53 #define GST_CAT_DEFAULT gst_dxgi_screen_cap_src_debug
54
55 struct _GstDXGIScreenCapSrc
56 {
57 /* Parent */
58 GstPushSrc src;
59
60 /* Properties */
61 gint capture_x;
62 gint capture_y;
63 gint capture_w;
64 gint capture_h;
65 guint monitor;
66 gchar *device_name;
67 gboolean show_cursor;
68
69 /* Source pad frame rate */
70 gint rate_numerator;
71 gint rate_denominator;
72
73 /* Runtime variables */
74 RECT screen_rect;
75 RECT src_rect;
76 guint64 frame_number;
77 GstClockID clock_id;
78 GstVideoInfo video_info;
79
80 /*DXGI capture */
81 DxgiCapture *dxgi_capture;
82 };
83
84 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
85 GST_PAD_SRC,
86 GST_PAD_ALWAYS,
87 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("BGRA")));
88
89 #define gst_dxgi_screen_cap_src_parent_class parent_class
90 G_DEFINE_TYPE (GstDXGIScreenCapSrc, gst_dxgi_screen_cap_src, GST_TYPE_PUSH_SRC);
91
92 #define DEFAULT_MONITOR (-1)
93 #define DEFAULT_DEVICE_NAME (NULL)
94 #define DEFAULT_SHOW_CURSOR (FALSE)
95 #define DEFAULT_X_POS (0)
96 #define DEFAULT_Y_POS (0)
97 #define DEFAULT_WIDTH (0)
98 #define DEFAULT_HEIGHT (0)
99
100 enum
101 {
102 PROP_0,
103 PROP_MONITOR,
104 PROP_DEVICE_NAME,
105 PROP_SHOW_CURSOR,
106 PROP_X_POS,
107 PROP_Y_POS,
108 PROP_WIDTH,
109 PROP_HEIGHT
110 };
111
112 static void gst_dxgi_screen_cap_src_dispose (GObject * object);
113 static void gst_dxgi_screen_cap_src_set_property (GObject * object,
114 guint prop_id, const GValue * value, GParamSpec * pspec);
115 static void gst_dxgi_screen_cap_src_get_property (GObject * object,
116 guint prop_id, GValue * value, GParamSpec * pspec);
117
118 static GstCaps *gst_dxgi_screen_cap_src_fixate (GstBaseSrc * bsrc,
119 GstCaps * caps);
120 static gboolean gst_dxgi_screen_cap_src_set_caps (GstBaseSrc * bsrc,
121 GstCaps * caps);
122 static GstCaps *gst_dxgi_screen_cap_src_get_caps (GstBaseSrc * bsrc,
123 GstCaps * filter);
124 static gboolean gst_dxgi_screen_cap_src_start (GstBaseSrc * bsrc);
125 static gboolean gst_dxgi_screen_cap_src_stop (GstBaseSrc * bsrc);
126
127 static gboolean gst_dxgi_screen_cap_src_unlock (GstBaseSrc * bsrc);
128
129 static GstFlowReturn gst_dxgi_screen_cap_src_create (GstBaseSrc * pushsrc,
130 guint64 offset, guint length, GstBuffer ** buffer);
131
132 static HMONITOR _get_hmonitor (GstDXGIScreenCapSrc * src);
133
134 /* Implementation. */
135 static void
gst_dxgi_screen_cap_src_class_init(GstDXGIScreenCapSrcClass * klass)136 gst_dxgi_screen_cap_src_class_init (GstDXGIScreenCapSrcClass * klass)
137 {
138 GObjectClass *go_class;
139 GstElementClass *e_class;
140 GstBaseSrcClass *bs_class;
141
142 go_class = G_OBJECT_CLASS (klass);
143 e_class = GST_ELEMENT_CLASS (klass);
144 bs_class = GST_BASE_SRC_CLASS (klass);
145
146 go_class->set_property = gst_dxgi_screen_cap_src_set_property;
147 go_class->get_property = gst_dxgi_screen_cap_src_get_property;
148
149 go_class->dispose = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_dispose);
150 bs_class->get_caps = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_get_caps);
151 bs_class->set_caps = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_set_caps);
152 bs_class->start = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_start);
153 bs_class->stop = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_stop);
154 bs_class->unlock = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_unlock);
155 bs_class->fixate = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_fixate);
156 bs_class->create = GST_DEBUG_FUNCPTR (gst_dxgi_screen_cap_src_create);
157
158 g_object_class_install_property (go_class, PROP_MONITOR,
159 g_param_spec_int ("monitor", "Monitor",
160 "Which monitor to use (-1 = primary monitor and default)",
161 DEFAULT_MONITOR, G_MAXINT, DEFAULT_MONITOR, G_PARAM_READWRITE));
162 g_object_class_install_property (go_class, PROP_DEVICE_NAME,
163 g_param_spec_string ("device-name", "Monitor device name",
164 "Which monitor to use by device name (e.g. \"\\\\\\\\.\\\\DISPLAY1\")",
165 DEFAULT_DEVICE_NAME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
166 g_object_class_install_property (go_class, PROP_SHOW_CURSOR,
167 g_param_spec_boolean ("cursor",
168 "Show mouse cursor",
169 "Whether to show mouse cursor (default off)",
170 DEFAULT_SHOW_CURSOR, G_PARAM_READWRITE));
171 g_object_class_install_property (go_class, PROP_X_POS,
172 g_param_spec_int ("x", "X",
173 "Horizontal coordinate of top left corner for the screen capture "
174 "area", 0, G_MAXINT, DEFAULT_X_POS, G_PARAM_READWRITE));
175 g_object_class_install_property (go_class, PROP_Y_POS,
176 g_param_spec_int ("y", "Y",
177 "Vertical coordinate of top left corner for the screen capture "
178 "area", 0, G_MAXINT, DEFAULT_Y_POS, G_PARAM_READWRITE));
179 g_object_class_install_property (go_class, PROP_WIDTH,
180 g_param_spec_int ("width", "Width",
181 "Width of screen capture area (0 = maximum)",
182 0, G_MAXINT, DEFAULT_WIDTH, G_PARAM_READWRITE));
183 g_object_class_install_property (go_class, PROP_HEIGHT,
184 g_param_spec_int ("height", "Height",
185 "Height of screen capture area (0 = maximum)",
186 0, G_MAXINT, DEFAULT_HEIGHT, G_PARAM_READWRITE));
187
188 gst_element_class_add_static_pad_template (e_class, &src_template);
189
190 gst_element_class_set_static_metadata (e_class,
191 "DirectX DXGI screen capture source",
192 "Source/Video", "Captures screen", "OKADA Jun-ichi <okada@abt.jp>");
193 }
194
195 static void
gst_dxgi_screen_cap_src_init(GstDXGIScreenCapSrc * src)196 gst_dxgi_screen_cap_src_init (GstDXGIScreenCapSrc * src)
197 {
198 /* Set src element inital values... */
199 src->capture_x = DEFAULT_X_POS;
200 src->capture_y = DEFAULT_Y_POS;
201 src->capture_w = DEFAULT_WIDTH;
202 src->capture_h = DEFAULT_HEIGHT;
203
204 src->monitor = DEFAULT_MONITOR;
205 src->device_name = DEFAULT_DEVICE_NAME;
206 src->show_cursor = DEFAULT_SHOW_CURSOR;
207
208 src->dxgi_capture = NULL;
209
210 gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
211 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
212 }
213
214 static void
gst_dxgi_screen_cap_src_dispose(GObject * object)215 gst_dxgi_screen_cap_src_dispose (GObject * object)
216 {
217 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (object);
218
219 g_free (src->device_name);
220 src->device_name = NULL;
221
222 dxgicap_destory (src->dxgi_capture);
223 src->dxgi_capture = NULL;
224
225 G_OBJECT_CLASS (parent_class)->dispose (object);
226 }
227
228 static void
gst_dxgi_screen_cap_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)229 gst_dxgi_screen_cap_src_set_property (GObject * object,
230 guint prop_id, const GValue * value, GParamSpec * pspec)
231 {
232 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (object);
233
234 switch (prop_id) {
235 case PROP_MONITOR:
236 src->monitor = g_value_get_int (value);
237 break;
238 case PROP_DEVICE_NAME:
239 g_free (src->device_name);
240 src->device_name = g_value_dup_string (value);
241 break;
242 case PROP_SHOW_CURSOR:
243 src->show_cursor = g_value_get_boolean (value);
244 break;
245 case PROP_X_POS:
246 src->capture_x = g_value_get_int (value);
247 break;
248 case PROP_Y_POS:
249 src->capture_y = g_value_get_int (value);
250 break;
251 case PROP_WIDTH:
252 src->capture_w = g_value_get_int (value);
253 break;
254 case PROP_HEIGHT:
255 src->capture_h = g_value_get_int (value);
256 break;
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259 break;
260 };
261 }
262
263 static void
gst_dxgi_screen_cap_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)264 gst_dxgi_screen_cap_src_get_property (GObject * object, guint prop_id,
265 GValue * value, GParamSpec * pspec)
266 {
267 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (object);
268
269 switch (prop_id) {
270 case PROP_MONITOR:
271 g_value_set_int (value, src->monitor);
272 break;
273 case PROP_DEVICE_NAME:
274 g_value_set_string (value, src->device_name);
275 break;
276 case PROP_SHOW_CURSOR:
277 g_value_set_boolean (value, src->show_cursor);
278 break;
279 case PROP_X_POS:
280 g_value_set_int (value, src->capture_x);
281 break;
282 case PROP_Y_POS:
283 g_value_set_int (value, src->capture_y);
284 break;
285 case PROP_WIDTH:
286 g_value_set_int (value, src->capture_w);
287 break;
288 case PROP_HEIGHT:
289 g_value_set_int (value, src->capture_h);
290 break;
291 default:
292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293 break;
294 };
295 }
296
297 static GstCaps *
gst_dxgi_screen_cap_src_fixate(GstBaseSrc * bsrc,GstCaps * caps)298 gst_dxgi_screen_cap_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
299 {
300 GstStructure *structure;
301
302 caps = gst_caps_make_writable (caps);
303
304 structure = gst_caps_get_structure (caps, 0);
305
306 gst_structure_fixate_field_nearest_int (structure, "width", 640);
307 gst_structure_fixate_field_nearest_int (structure, "height", 480);
308 gst_structure_fixate_field_nearest_fraction (structure, "framerate", 30, 1);
309
310 caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
311
312 return caps;
313 }
314
315 static gboolean
gst_dxgi_screen_cap_src_set_caps(GstBaseSrc * bsrc,GstCaps * caps)316 gst_dxgi_screen_cap_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps)
317 {
318 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (bsrc);
319 GstStructure *structure;
320
321 structure = gst_caps_get_structure (caps, 0);
322
323 src->src_rect = src->screen_rect;
324 if (src->capture_w && src->capture_h) {
325 src->src_rect.left += src->capture_x;
326 src->src_rect.top += src->capture_y;
327 src->src_rect.right = src->src_rect.left + src->capture_w;
328 src->src_rect.bottom = src->src_rect.top + src->capture_h;
329 }
330
331 gst_structure_get_fraction (structure, "framerate",
332 &src->rate_numerator, &src->rate_denominator);
333
334 GST_DEBUG_OBJECT (src, "set_caps size %dx%d, %d/%d fps",
335 (gint) RECT_WIDTH (src->src_rect),
336 (gint) RECT_HEIGHT (src->src_rect),
337 src->rate_numerator, src->rate_denominator);
338
339 gst_video_info_from_caps (&src->video_info, caps);
340 gst_base_src_set_blocksize (bsrc, GST_VIDEO_INFO_SIZE (&src->video_info));
341 return TRUE;
342 }
343
344 static GstCaps *
gst_dxgi_screen_cap_src_get_caps(GstBaseSrc * bsrc,GstCaps * filter)345 gst_dxgi_screen_cap_src_get_caps (GstBaseSrc * bsrc, GstCaps * filter)
346 {
347 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (bsrc);
348 RECT rect_dst;
349 GstCaps *caps = NULL;
350
351 HMONITOR hmonitor = _get_hmonitor (src);
352 if (!get_monitor_physical_size (hmonitor, &rect_dst)) {
353 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
354 ("Specified monitor with index %d not found", src->monitor), (NULL));
355 return NULL;
356 }
357
358 src->screen_rect = rect_dst;
359 if (src->capture_w && src->capture_h &&
360 src->capture_x + src->capture_w <= RECT_WIDTH (rect_dst) &&
361 src->capture_y + src->capture_h <= RECT_HEIGHT (rect_dst)) {
362 rect_dst.left = src->capture_x;
363 rect_dst.top = src->capture_y;
364 rect_dst.right = src->capture_x + src->capture_w;
365 rect_dst.bottom = src->capture_y + src->capture_h;
366 } else {
367 /* Default values */
368 src->capture_x = src->capture_y = 0;
369 src->capture_w = src->capture_h = 0;
370 }
371
372 /* The desktop image is always in the DXGI_FORMAT_B8G8R8A8_UNORM format. */
373 GST_DEBUG_OBJECT (src, "get_cap rect: %ld, %ld, %ld, %ld", rect_dst.left,
374 rect_dst.top, rect_dst.right, rect_dst.bottom);
375
376 caps =
377 gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "BGRA",
378 "width", G_TYPE_INT, RECT_WIDTH (rect_dst),
379 "height", G_TYPE_INT, RECT_HEIGHT (rect_dst),
380 "framerate", GST_TYPE_FRACTION_RANGE, 1, 1, G_MAXINT,
381 1, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
382
383 if (filter) {
384 GstCaps *tmp =
385 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
386 gst_caps_unref (caps);
387 caps = tmp;
388 }
389 return caps;
390 }
391
392 static gboolean
gst_dxgi_screen_cap_src_start(GstBaseSrc * bsrc)393 gst_dxgi_screen_cap_src_start (GstBaseSrc * bsrc)
394 {
395 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (bsrc);
396 HMONITOR hmonitor = _get_hmonitor (src);
397 if (NULL == hmonitor) {
398 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
399 ("Specified monitor with index %d not found", src->monitor), (NULL));
400 return FALSE;
401 }
402 src->dxgi_capture = dxgicap_new (hmonitor, src);
403
404 if (NULL == src->dxgi_capture) {
405 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
406 ("Specified monitor with index %d not found", src->monitor), (NULL));
407 return FALSE;
408 }
409 dxgicap_start (src->dxgi_capture);
410
411 src->frame_number = -1;
412 return TRUE;
413 }
414
415 static gboolean
gst_dxgi_screen_cap_src_stop(GstBaseSrc * bsrc)416 gst_dxgi_screen_cap_src_stop (GstBaseSrc * bsrc)
417 {
418 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (bsrc);
419 dxgicap_stop (src->dxgi_capture);
420 dxgicap_destory (src->dxgi_capture);
421 src->dxgi_capture = NULL;
422
423 return TRUE;
424 }
425
426 static gboolean
gst_dxgi_screen_cap_src_unlock(GstBaseSrc * bsrc)427 gst_dxgi_screen_cap_src_unlock (GstBaseSrc * bsrc)
428 {
429 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (bsrc);
430
431 GST_OBJECT_LOCK (src);
432 if (src->clock_id) {
433 GST_DEBUG_OBJECT (src, "Waking up waiting clock");
434 gst_clock_id_unschedule (src->clock_id);
435 }
436 GST_OBJECT_UNLOCK (src);
437
438 return TRUE;
439 }
440
441 static GstFlowReturn
gst_dxgi_screen_cap_src_create(GstBaseSrc * base_src,guint64 offset,guint length,GstBuffer ** buf)442 gst_dxgi_screen_cap_src_create (GstBaseSrc * base_src, guint64 offset,
443 guint length, GstBuffer ** buf)
444 {
445 GstDXGIScreenCapSrc *src = GST_DXGI_SCREEN_CAP_SRC (base_src);
446 GstClock *clock;
447 GstClockTime buf_time, buf_dur;
448 guint64 frame_number;
449 GstFlowReturn ret;
450 GstBuffer *buffer = NULL;
451
452 if (G_UNLIKELY (!src->dxgi_capture)) {
453 GST_DEBUG_OBJECT (src, "format wasn't negotiated before create function");
454 return GST_FLOW_NOT_NEGOTIATED;
455 }
456
457 clock = gst_element_get_clock (GST_ELEMENT (src));
458 if (clock != NULL) {
459 GstClockTime time, base_time;
460
461 /* Calculate sync time. */
462
463 time = gst_clock_get_time (clock);
464 base_time = gst_element_get_base_time (GST_ELEMENT (src));
465 buf_time = time - base_time;
466
467 if (src->rate_numerator) {
468 frame_number = gst_util_uint64_scale (buf_time,
469 src->rate_numerator, GST_SECOND * src->rate_denominator);
470 } else {
471 frame_number = -1;
472 }
473 } else {
474 buf_time = GST_CLOCK_TIME_NONE;
475 frame_number = -1;
476 }
477
478 if (frame_number != -1 && frame_number == src->frame_number) {
479 GstClockID id;
480 GstClockReturn ret;
481
482 /* Need to wait for the next frame */
483 frame_number += 1;
484
485 /* Figure out what the next frame time is */
486 buf_time = gst_util_uint64_scale (frame_number,
487 src->rate_denominator * GST_SECOND, src->rate_numerator);
488
489 id = gst_clock_new_single_shot_id (clock,
490 buf_time + gst_element_get_base_time (GST_ELEMENT (src)));
491 GST_OBJECT_LOCK (src);
492 src->clock_id = id;
493 GST_OBJECT_UNLOCK (src);
494
495 GST_DEBUG_OBJECT (src, "Waiting for next frame time %" G_GUINT64_FORMAT,
496 buf_time);
497 ret = gst_clock_id_wait (id, NULL);
498
499 GST_OBJECT_LOCK (src);
500 gst_clock_id_unref (id);
501 src->clock_id = NULL;
502 GST_OBJECT_UNLOCK (src);
503
504 if (ret == GST_CLOCK_UNSCHEDULED) {
505 /* Got woken up by the unlock function */
506 if (clock) {
507 gst_object_unref (clock);
508 }
509 return GST_FLOW_FLUSHING;
510 }
511
512 /* Duration is a complete 1/fps frame duration */
513 buf_dur =
514 gst_util_uint64_scale_int (GST_SECOND, src->rate_denominator,
515 src->rate_numerator);
516 } else if (frame_number != -1) {
517 GstClockTime next_buf_time;
518
519 GST_DEBUG_OBJECT (src, "No need to wait for next frame time %"
520 G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT
521 " prev = %" G_GINT64_FORMAT, buf_time, frame_number, src->frame_number);
522 next_buf_time =
523 gst_util_uint64_scale (frame_number + 1,
524 src->rate_denominator * GST_SECOND, src->rate_numerator);
525 /* Frame duration is from now until the next expected capture time */
526 buf_dur = next_buf_time - buf_time;
527 } else {
528 buf_dur = GST_CLOCK_TIME_NONE;
529 }
530 src->frame_number = frame_number;
531
532 if (clock) {
533 gst_object_unref (clock);
534 }
535
536 /* Get the latest desktop frame. */
537 do {
538 ret = dxgicap_acquire_next_frame (src->dxgi_capture, src->show_cursor, 0);
539 if (ret == GST_DXGICAP_FLOW_RESOLUTION_CHANGE) {
540 GST_DEBUG_OBJECT (src, "Resolution change detected.");
541
542 if (!gst_base_src_negotiate (GST_BASE_SRC (src))) {
543 return GST_FLOW_NOT_NEGOTIATED;
544 }
545 }
546 } while (ret == GST_DXGICAP_FLOW_RESOLUTION_CHANGE);
547
548 if (ret != GST_FLOW_OK) {
549 return ret;
550 }
551
552 ret =
553 GST_BASE_SRC_CLASS (g_type_class_peek_parent (parent_class))->alloc
554 (base_src, offset, length, &buffer);
555 if (ret != GST_FLOW_OK) {
556 return ret;
557 }
558
559 /* Copy the latest desktop frame to the video frame. */
560 if (dxgicap_copy_buffer (src->dxgi_capture, src->show_cursor,
561 &src->src_rect, &src->video_info, buffer)) {
562 GST_BUFFER_TIMESTAMP (buffer) = buf_time;
563 GST_BUFFER_DURATION (buffer) = buf_dur;
564 *buf = buffer;
565
566 return GST_FLOW_OK;
567 }
568
569 gst_clear_buffer (&buffer);
570
571 return GST_FLOW_ERROR;
572 }
573
574 static HMONITOR
_get_hmonitor(GstDXGIScreenCapSrc * src)575 _get_hmonitor (GstDXGIScreenCapSrc * src)
576 {
577 HMONITOR hmonitor = NULL;
578 GST_DEBUG_OBJECT (src, "device_name:%s", GST_STR_NULL (src->device_name));
579 if (NULL != src->device_name) {
580 hmonitor = get_hmonitor_by_device_name (src->device_name);
581 }
582 if (NULL == hmonitor && DEFAULT_MONITOR != src->monitor) {
583 hmonitor = get_hmonitor_by_index (src->monitor);
584 }
585 if (NULL == hmonitor) {
586 hmonitor = get_hmonitor_primary ();
587 }
588 return hmonitor;
589 }
590
591 void
gst_dxgi_screen_cap_src_register(GstPlugin * plugin,GstRank rank)592 gst_dxgi_screen_cap_src_register (GstPlugin * plugin, GstRank rank)
593 {
594 if (!IsWindows8OrGreater ()) {
595 GST_WARNING ("OS version is too old");
596 return;
597 }
598
599 if (!gst_dxgicap_shader_init ()) {
600 GST_WARNING ("Couldn't load HLS compiler");
601 return;
602 }
603
604 /**
605 * element-dxgiscreencapsrc:
606 *
607 * Since: 1.18
608 */
609 gst_element_register (plugin, "dxgiscreencapsrc",
610 rank, GST_TYPE_DXGI_SCREEN_CAP_SRC);
611 }
612