UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
screen_osx.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2012-2023 CESNET, z.s.p.o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif /* HAVE_CONFIG_H */
43
44#include "debug.h"
45#include "host.h"
46#include "lib_common.h"
48#include "video.h"
49#include "video_capture.h"
50
51#include "tv.h"
52
53#include "audio/types.h"
54
55#include <stdio.h>
56#include <stdlib.h>
57#include <strings.h>
58
59#include <pthread.h>
60
61#include <Carbon/Carbon.h>
62
63#define MAX_DISPLAY_COUNT 10
64#define MOD_NAME "[screen cap mac] "
65
66
67/* prototypes of functions defined in this module */
68static void show_help(void);
69static void vidcap_screen_osx_done(void *state);
70
71static void show_help()
72{
73 printf("Screen capture\n");
74 printf("Usage\n");
75 printf("\t-t screen[:fps=<fps>][:codec=<c>][:display=<d>]\n");
76 printf("\t\t<fps> - preferred grabbing fps (otherwise unlimited)\n");
77 printf("\t\t <c> - requested codec to capture (RGB /default/ or RGBA)\n");
78 printf("\t\t <d> - display ID or \"primary\" or \"secondary\"\n");
79 printf("\n\nAvailable displays:\n");
80
81 CGDirectDisplayID screens[MAX_DISPLAY_COUNT];
82 uint32_t count = 0;
83 CGGetOnlineDisplayList(sizeof screens / sizeof screens[0], screens, &count);
84
85 for (unsigned int i = 0; i < count; ++i) {
86 char flags[128];
87 strcpy(flags, CGDisplayIsMain(screens[i]) ? "primary" : "secondary");
88 if (CGDisplayIsBuiltin(screens[i])) {
89 strncat(flags, ", builtin", sizeof flags - strlen(flags) - 1);
90 }
91 printf("\tID %u) %s\n", screens[i], flags);
92 }
93}
94
98 int frames;
99 struct timeval t, t0;
100 CGDirectDisplayID display;
102
103 struct timeval prev_time;
104
106};
107
108static bool initialize(struct vidcap_screen_osx_state *s) {
109 CGImageRef image = CGDisplayCreateImage(s->display);
110 if (image == NULL) {
111 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable create image (wrong display ID?)\n");
112 return false;
113 }
114
115 s->desc.width = CGImageGetWidth(image);
116 s->desc.height = CGImageGetHeight(image);
117 CFRelease(image);
119
120 return true;
121}
122
123static void vidcap_screen_osx_probe(struct device_info **available_cards, int *count, void (**deleter)(void *))
124{
125 *deleter = free;
126 *count = 1;
127 *available_cards = calloc(*count, sizeof(struct device_info));
128
129 snprintf((*available_cards)[0].name, sizeof (*available_cards)[0].name, "Screen capture");
130
131 int framerates[] = {24, 30, 60};
132
133 snprintf((*available_cards)[0].modes[0].name, sizeof (*available_cards)[0].name,
134 "Unlimited fps");
135 snprintf((*available_cards)[0].modes[0].id, sizeof (*available_cards)[0].modes[0].id,
136 "{\"fps\":\"\"}");
137
138 for(unsigned i = 0; i < sizeof(framerates) / sizeof(framerates[0]); i++){
139 snprintf((*available_cards)[0].modes[i + 1].name, sizeof (*available_cards)[0].name,
140 "%d fps", framerates[i]);
141 snprintf((*available_cards)[0].modes[i + 1].id, sizeof (*available_cards)[0].modes[0].id,
142 "{\"fps\":\"%d\"}", framerates[i]);
143 }
144}
145
147{
148 struct vidcap_screen_osx_state *s;
149
150 printf("vidcap_screen_init\n");
151
154 }
155
156 s = (struct vidcap_screen_osx_state *) calloc(1, sizeof(struct vidcap_screen_osx_state));
157 if(s == NULL) {
158 printf("Unable to allocate screen capture state\n");
159 return VIDCAP_INIT_FAIL;
160 }
161
162 s->initialized = false;
163
164 gettimeofday(&s->t0, NULL);
165
166 s->desc.tile_count = 1;
167 s->desc.color_spec = RGB;
168 s->desc.fps = 30;
170
171 s->display = CGMainDisplayID();
172
174 if (strcmp(vidcap_params_get_fmt(params), "help") == 0) {
175 show_help();
176 return VIDCAP_INIT_NOERR;
177 }
178 char *fmt = alloca(strlen(vidcap_params_get_fmt(params) + 1));
180 char *save_ptr = NULL;
181 char *item = NULL;
182 while ((item = strtok_r(fmt, ":", &save_ptr)) != NULL) {
183 if (strncasecmp(item, "fps=", strlen("fps=")) == 0) {
184 s->desc.fps = atof(item + strlen("fps="));
185 } else if (strncasecmp(item, "codec=", strlen("codec=")) == 0) {
186 s->desc.color_spec = get_codec_from_name(item + strlen("codec="));
187 } else if (strncasecmp(item, "display=", strlen("display=")) == 0) {
188 char *display = item + strlen("display=");
189
190 if (strcasecmp(display, "secondary") == 0) {
191 CGDirectDisplayID screens[MAX_DISPLAY_COUNT];
192 uint32_t count = 0;
193 CGGetOnlineDisplayList(sizeof screens / sizeof screens[0], screens, &count);
194 uint32_t i = 0;
195 for (; i < count; ++i) {
196 if (!CGDisplayIsMain(screens[i])) {
197 s->display = screens[i];
198 break;
199 }
200 }
201 if (i == count) {
202 log_msg(LOG_LEVEL_ERROR, MOD_NAME "No secondary scren found!\n");
204 return VIDCAP_INIT_FAIL;
205 }
206 } if (strcasecmp(display, "primary") != 0) { // primary was already set
207 s->display = atol(display);
208 }
209 } else {
210 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unrecognized option \"%s\"\n", item);
212 return VIDCAP_INIT_FAIL;
213 }
214 fmt = NULL;
215 }
216 }
217
218 switch (s->desc.color_spec) {
219 case RGB:
221 break;
222 case RGBA:
224 break;
225 default:
226 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Only RGB and RGBA are currently supported!\n");
228 return VIDCAP_INIT_FAIL;
229 }
230
231 *state = s;
232 return VIDCAP_INIT_OK;
233}
234
236{
238
239 assert(s != NULL);
240
242
243 free(s);
244}
245
247{
249
250 if (!s->initialized) {
251 s->initialized = initialize(s);
252 if (!s->initialized) {
253 return NULL;
254 }
255 }
256
258 struct tile *tile = vf_get_tile(frame, 0);
259
260 *audio = NULL;
261
262 CGImageRef image = CGDisplayCreateImage(s->display);
263 CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image));
264 const unsigned char *pixels = CFDataGetBytePtr(data);
265
266 int src_linesize = tile->width * 4;
267 int dst_linesize = vc_get_linesize(tile->width, frame->color_spec);
268 unsigned char *dst = (unsigned char *) tile->data;
269 const unsigned char *src = (const unsigned char *) pixels;
270 for (unsigned int y = 0; y < tile->height; ++y) {
271 s->decode(dst, src, dst_linesize, 16, 8, 0);
272 src += src_linesize;
273 dst += dst_linesize;
274 }
275
276 CFRelease(data);
277 CFRelease(image);
278
279 struct timeval cur_time;
280 gettimeofday(&cur_time, NULL);
281 while(tv_diff_usec(cur_time, s->prev_time) < 1000000.0 / frame->fps) {
282 gettimeofday(&cur_time, NULL);
283 }
284 s->prev_time = cur_time;
285
286 gettimeofday(&s->t, NULL);
287 double seconds = tv_diff(s->t, s->t0);
288 if (seconds >= 5) {
289 float fps = s->frames / seconds;
290 log_msg(LOG_LEVEL_INFO, "[screen capture] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps);
291 s->t0 = s->t;
292 s->frames = 0;
293 }
294
295 s->frames++;
296
297 return frame;
298}
299
307
309
void ** state
struct video_frame * frame
const char * fmt
const char unsigned int flags
struct audio_frame ** audio
int void(** deleter)(void *))
int vc_get_linesize(unsigned int width, codec_t codec)
codec_t get_codec_from_name(const char *name)
This file contains definition of some common audio types.
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_NO_GENERIC_FPS_INDICATOR
#define VIDEO_CAPTURE_ABI_VERSION
#define VIDCAP_INIT_FAIL
error ocured
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
int count
Definition hd-rum.c:44
@ LIBRARY_CLASS_VIDEO_CAPTURE
Definition lib_common.h:78
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
decoder_func_t vc_copylineRGBA
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
decoder_func_t vc_copylineBGRAtoRGB
static unsigned char pixels[]
static void vidcap_screen_osx_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition screen_osx.c:123
static void vidcap_screen_osx_done(void *state)
Definition screen_osx.c:235
static bool initialize(struct vidcap_screen_osx_state *s)
Definition screen_osx.c:108
static int vidcap_screen_osx_init(struct vidcap_params *params, void **state)
Definition screen_osx.c:146
#define MOD_NAME
Definition screen_osx.c:64
static struct video_frame * vidcap_screen_osx_grab(void *state, struct audio_frame **audio)
Definition screen_osx.c:246
static const struct video_capture_info vidcap_screen_osx_info
Definition screen_osx.c:300
#define MAX_DISPLAY_COUNT
Definition screen_osx.c:63
static void show_help(void)
Definition screen_osx.c:71
const char * name
Definition settings.cpp:193
struct used to comunicate with audio capture/playback device
Definition types.h:99
This struct represents initialized video display state.
Definition hd-rum.c:27
Struct tile is an area of video_frame.
Definition types.h:279
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int height
Definition types.h:281
CGDirectDisplayID display
Definition screen_osx.c:100
struct timeval prev_time
Definition screen_osx.c:103
decoder_t decode
decoder, must accept BGRA (different shift)
Definition screen_osx.c:101
struct timeval t t0
Definition screen_osx.c:99
struct video_desc desc
Definition screen_osx.c:96
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
double fps
Definition types.h:308
codec_t color_spec
Definition types.h:306
uint32_t tv_diff_usec(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:109
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
This is an umbrella header for video functions.
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY
struct tile * vf_get_tile(struct video_frame *buf, int pos)
Returns pointer to n-th tile from video frame Equivalent to &video_frame::tiles[pos].
void video_frame_pool_destroy(void *state)
void * video_frame_pool_init(struct video_desc desc, int len)
struct video_frame * video_frame_pool_get_disposable_frame(void *state)