Split screen capture module

Split screen capture modules into platform specific files (X11
and OS X).
This commit is contained in:
Martin Pulec
2013-11-04 15:09:02 +01:00
parent 5334e9be99
commit cd5e954bb6
6 changed files with 344 additions and 144 deletions

View File

@@ -1668,9 +1668,14 @@ esac
if test $screen_cap = yes
then
AC_DEFINE([HAVE_SCREEN_CAP], [1], [Build with screen_capture])
AC_DEFINE([HAVE_SCREEN_CAP], [1], [Build with screen capture])
AC_SUBST(SCREEN_CAP_LIB_TARGET, "lib/ultragrid/vidcap_screen.so.$video_capture_abi_version")
SCREEN_CAP_OBJ="src/video_capture/screen.o"
if test $system = MacOSX; then
SCREEN_CAP_OBJ="src/video_capture/screen_osx.o"
else if test $system = Linux; then
SCREEN_CAP_OBJ="src/video_capture/screen_x11.o"
fi
fi
LIB_TARGETS="$LIB_TARGETS $SCREEN_CAP_LIB_TARGET"
LIB_OBJS="$LIB_OBJS $SCREEN_CAP_OBJ"
fi

View File

@@ -75,7 +75,8 @@
#include "video_capture/linsys.h"
#include "video_capture/null.h"
#include "video_capture/quicktime.h"
#include "video_capture/screen.h"
#include "video_capture/screen_osx.h"
#include "video_capture/screen_x11.h"
#include "video_capture/swmix.h"
#include "video_capture/testcard.h"
#include "video_capture/testcard2.h"
@@ -217,10 +218,17 @@ struct vidcap_device_api vidcap_device_table[] = {
/* The screen capture card */
0,
"screen",
MK_NAME(vidcap_screen_probe),
MK_NAME(vidcap_screen_init),
MK_NAME(vidcap_screen_done),
MK_NAME(vidcap_screen_grab),
#ifdef HAVE_LINUX
MK_NAME(vidcap_screen_x11_probe),
MK_NAME(vidcap_screen_x11_init),
MK_NAME(vidcap_screen_x11_done),
MK_NAME(vidcap_screen_x11_grab),
#else
MK_NAME(vidcap_screen_osx_probe),
MK_NAME(vidcap_screen_osx_init),
MK_NAME(vidcap_screen_osx_done),
MK_NAME(vidcap_screen_osx_grab),
#endif // ! defined HAVE_LINUX
NULL
},
#endif /* HAVE_SCREEN */

View File

@@ -0,0 +1,234 @@
/**
* @file screen_osx.c
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2012-2013 CESNET, z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif /* HAVE_CONFIG_H */
#include "debug.h"
#include "host.h"
#include "video.h"
#include "video_capture.h"
#include "tv.h"
#include "video_capture/screen_osx.h"
#include "audio/audio.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <pthread.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <Carbon/Carbon.h>
/* prototypes of functions defined in this module */
static void show_help(void);
static void show_help()
{
printf("Screen capture\n");
printf("Usage\n");
printf("\t-t screen[:fps=<fps>]\n");
printf("\t\t<fps> - preferred grabbing fps (otherwise unlimited)\n");
}
struct vidcap_screen_osx_state {
struct video_frame *frame;
struct tile *tile;
int frames;
struct timeval t, t0;
CGDirectDisplayID display;
struct timeval prev_time;
double fps;
bool initialized;
};
static void initialize(struct vidcap_screen_osx_state *s) {
s->frame = vf_alloc(1);
s->tile = vf_get_tile(s->frame, 0);
s->display = CGMainDisplayID();
CGImageRef image = CGDisplayCreateImage(s->display);
s->tile->width = CGImageGetWidth(image);
s->tile->height = CGImageGetHeight(image);
CFRelease(image);
s->frame->color_spec = RGBA;
if(s->fps > 0.0) {
s->frame->fps = s->fps;
} else {
s->frame->fps = 30;
}
s->frame->interlacing = PROGRESSIVE;
s->tile->data_len = vc_get_linesize(s->tile->width, s->frame->color_spec) * s->tile->height;
s->tile->data = (char *) malloc(s->tile->data_len);
return;
goto error; // dummy use (otherwise compiler would complain about unreachable code (Mac)
error:
fprintf(stderr, "[Screen cap.] Initialization failed!\n");
exit_uv(128);
}
struct vidcap_type * vidcap_screen_osx_probe(void)
{
struct vidcap_type* vt;
vt = (struct vidcap_type *) malloc(sizeof(struct vidcap_type));
if (vt != NULL) {
vt->id = VIDCAP_SCREEN_ID;
vt->name = "screen";
vt->description = "Grabbing screen";
}
return vt;
}
void * vidcap_screen_osx_init(const struct vidcap_params *params)
{
struct vidcap_screen_osx_state *s;
printf("vidcap_screen_init\n");
s = (struct vidcap_screen_osx_state *) malloc(sizeof(struct vidcap_screen_osx_state));
if(s == NULL) {
printf("Unable to allocate screen capture state\n");
return NULL;
}
s->initialized = false;
gettimeofday(&s->t0, NULL);
s->fps = 0.0;
s->frame = NULL;
s->tile = NULL;
s->prev_time.tv_sec =
s->prev_time.tv_usec = 0;
s->frames = 0;
if(vidcap_params_get_fmt(params)) {
if (strcmp(vidcap_params_get_fmt(params), "help") == 0) {
show_help();
return &vidcap_init_noerr;
} else if (strncasecmp(vidcap_params_get_fmt(params), "fps=", strlen("fps=")) == 0) {
s->fps = atoi(vidcap_params_get_fmt(params) + strlen("fps="));
}
}
return s;
}
void vidcap_screen_osx_done(void *state)
{
struct vidcap_screen_osx_state *s = (struct vidcap_screen_osx_state *) state;
assert(s != NULL);
if(s->tile) {
free(s->tile->data);
}
vf_free(s->frame);
free(s);
}
struct video_frame * vidcap_screen_osx_grab(void *state, struct audio_frame **audio)
{
struct vidcap_screen_osx_state *s = (struct vidcap_screen_osx_state *) state;
if (!s->initialized) {
initialize(s);
s->initialized = true;
}
*audio = NULL;
CGImageRef image = CGDisplayCreateImage(s->display);
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image));
const unsigned char *pixels = CFDataGetBytePtr(data);
int linesize = s->tile->width * 4;
int y;
unsigned char *dst = (unsigned char *) s->tile->data;
const unsigned char *src = (const unsigned char *) pixels;
for(y = 0; y < (int) s->tile->height; ++y) {
vc_copylineRGBA (dst, src, linesize, 16, 8, 0);
src += linesize;
dst += linesize;
}
CFRelease(data);
CFRelease(image);
if(s->fps > 0.0) {
struct timeval cur_time;
gettimeofday(&cur_time, NULL);
while(tv_diff_usec(cur_time, s->prev_time) < 1000000.0 / s->frame->fps) {
gettimeofday(&cur_time, NULL);
}
s->prev_time = cur_time;
}
gettimeofday(&s->t, NULL);
double seconds = tv_diff(s->t, s->t0);
if (seconds >= 5) {
float fps = s->frames / seconds;
fprintf(stderr, "[screen capture] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps);
s->t0 = s->t;
s->frames = 0;
}
s->frames++;
return s->frame;
}

View File

@@ -1,32 +1,23 @@
/**
* @file screen_osx.h
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* FILE: screen.h
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
* Copyright (c) 2012-2013 CESNET, z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
@@ -42,12 +33,12 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define VIDCAP_SCREEN_ID 0x5645ba22
struct vidcap_type *vidcap_screen_probe(void);
void *vidcap_screen_init(const struct vidcap_params *params);
void vidcap_screen_done(void *state);
struct video_frame *vidcap_screen_grab(void *state, struct audio_frame **audio);
struct vidcap_type *vidcap_screen_osx_probe(void);
void *vidcap_screen_osx_init(const struct vidcap_params *params);
void vidcap_screen_osx_done(void *state);
struct video_frame *vidcap_screen_osx_grab(void *state, struct audio_frame **audio);

View File

@@ -1,32 +1,23 @@
/**
* @file screen_x11.c
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* FILE: screen.c
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
* Copyright (c) 2012-2013 CESNET, z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
@@ -42,11 +33,8 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "host.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
@@ -60,37 +48,25 @@
#include "tv.h"
#include "video_capture/screen.h"
#include "video_capture/screen_x11.h"
#include "audio/audio.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <pthread.h>
#ifdef HAVE_MACOSX
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <Carbon/Carbon.h>
#else
#include <X11/Xlib.h>
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif // HAVE_XFIXES
#include <X11/Xutil.h>
#include "x11_common.h"
#endif
#define QUEUE_SIZE_MAX 3
/* prototypes of functions defined in this module */
static void show_help(void);
#ifdef HAVE_LINUX
static void *grab_thread(void *args);
#endif // HAVE_LINUX
static volatile bool should_exit = false;
static void show_help()
{
@@ -100,25 +76,18 @@ static void show_help()
printf("\t\t<fps> - preferred grabbing fps (otherwise unlimited)\n");
}
static struct vidcap_screen_state *state;
#ifdef HAVE_LINUX
struct grabbed_data;
struct grabbed_data {
XImage *data;
struct grabbed_data *next;
};
#endif
struct vidcap_screen_state {
struct vidcap_screen_x11_state {
struct video_frame *frame;
struct tile *tile;
int frames;
struct timeval t, t0;
#ifdef HAVE_MACOSX
CGDirectDisplayID display;
#else
Display *dpy;
Window root;
@@ -134,24 +103,18 @@ struct vidcap_screen_state {
volatile bool should_exit_worker;
pthread_t worker_id;
#endif
struct timeval prev_time;
double fps;
bool initialized;
};
pthread_once_t initialized = PTHREAD_ONCE_INIT;
static void initialize() {
struct vidcap_screen_state *s = (struct vidcap_screen_state *) state;
static void initialize(struct vidcap_screen_x11_state *s) {
s->frame = vf_alloc(1);
s->tile = vf_get_tile(s->frame, 0);
#ifndef HAVE_MACOSX
XWindowAttributes wa;
x11_lock();
@@ -178,15 +141,6 @@ static void initialize() {
s->should_exit_worker = false;
#else
s->display = CGMainDisplayID();
CGImageRef image = CGDisplayCreateImage(s->display);
s->tile->width = CGImageGetWidth(image);
s->tile->height = CGImageGetHeight(image);
CFRelease(image);
#endif
s->frame->color_spec = RGB;
if(s->fps > 0.0) {
s->frame->fps = s->fps;
@@ -196,13 +150,9 @@ static void initialize() {
s->frame->interlacing = PROGRESSIVE;
s->tile->data_len = vc_get_linesize(s->tile->width, s->frame->color_spec) * s->tile->height;
#ifndef HAVE_MACOSX
s->tile->data = (char *) malloc(s->tile->data_len);
pthread_create(&s->worker_id, NULL, grab_thread, s);
#else
s->tile->data = (char *) malloc(s->tile->data_len);
#endif
return;
@@ -213,10 +163,9 @@ error:
}
#ifdef HAVE_LINUX
static void *grab_thread(void *args)
{
struct vidcap_screen_state *s = args;
struct vidcap_screen_x11_state *s = args;
while(!s->should_exit_worker) {
struct grabbed_data *new_item = malloc(sizeof(struct grabbed_data));
@@ -285,9 +234,8 @@ static void *grab_thread(void *args)
return NULL;
}
#endif // HAVE_LINUX
struct vidcap_type * vidcap_screen_probe(void)
struct vidcap_type * vidcap_screen_x11_probe(void)
{
struct vidcap_type* vt;
@@ -300,17 +248,18 @@ struct vidcap_type * vidcap_screen_probe(void)
return vt;
}
void * vidcap_screen_init(const struct vidcap_params *params)
void * vidcap_screen_x11_init(const struct vidcap_params *params)
{
struct vidcap_screen_state *s;
struct vidcap_screen_x11_state *s;
printf("vidcap_screen_init\n");
state = s = (struct vidcap_screen_state *) malloc(sizeof(struct vidcap_screen_state));
s = (struct vidcap_screen_x11_state *) malloc(sizeof(struct vidcap_screen_x11_state));
if(s == NULL) {
printf("Unable to allocate screen capture state\n");
return NULL;
}
s->initialized = false;
gettimeofday(&s->t0, NULL);
@@ -319,17 +268,14 @@ void * vidcap_screen_init(const struct vidcap_params *params)
s->frame = NULL;
s->tile = NULL;
#ifdef HAVE_LINUX
s->worker_id = 0;
#ifndef HAVE_XFIXES
fprintf(stderr, "[Screen capture] Compiled without XFixes library, cursor won't be shown!\n");
#endif // ! HAVE_XFIXES
#endif // HAVE_LINUX
s->prev_time.tv_sec =
s->prev_time.tv_usec = 0;
s->frames = 0;
if(vidcap_params_get_fmt(params)) {
@@ -344,13 +290,11 @@ void * vidcap_screen_init(const struct vidcap_params *params)
return s;
}
static void vidcap_screen_finish(void *state)
static void vidcap_screen_x11_finish(void *state)
{
struct vidcap_screen_state *s = (struct vidcap_screen_state *) state;
struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state;
assert(s != NULL);
should_exit = true;
#ifdef HAVE_LINUX
pthread_mutex_lock(&s->lock);
if(s->boss_waiting) {
pthread_cond_signal(&s->boss_cv);
@@ -366,18 +310,16 @@ static void vidcap_screen_finish(void *state)
if(s->worker_id) {
pthread_join(s->worker_id, NULL);
}
#endif // HAVE_LINUX
}
void vidcap_screen_done(void *state)
void vidcap_screen_x11_done(void *state)
{
struct vidcap_screen_state *s = (struct vidcap_screen_state *) state;
struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state;
assert(s != NULL);
vidcap_screen_finish(state);
vidcap_screen_x11_finish(state);
#ifdef HAVE_LINUX
pthread_mutex_lock(&s->lock);
{
while(s->queue_len > 0) {
@@ -392,27 +334,22 @@ void vidcap_screen_done(void *state)
if(s->tile)
free(s->tile->data);
#endif
if(s->tile) {
#ifdef HAVE_MACOS_X
free(s->tile->data);
#endif
}
vf_free(s->frame);
free(s);
}
struct video_frame * vidcap_screen_grab(void *state, struct audio_frame **audio)
struct video_frame * vidcap_screen_x11_grab(void *state, struct audio_frame **audio)
{
struct vidcap_screen_state *s = (struct vidcap_screen_state *) state;
struct vidcap_screen_x11_state *s = (struct vidcap_screen_x11_state *) state;
pthread_once(&initialized, initialize);
if (!s->initialized) {
initialize(s);
s->initialized = true;
}
*audio = NULL;
#ifndef HAVE_MACOSX
struct grabbed_data *item = NULL;
pthread_mutex_lock(&s->lock);
@@ -444,25 +381,6 @@ struct video_frame * vidcap_screen_grab(void *state, struct audio_frame **audio)
XDestroyImage(item->data);
free(item);
#else
CGImageRef image = CGDisplayCreateImage(s->display);
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(image));
const unsigned char *pixels = CFDataGetBytePtr(data);
int linesize = s->tile->width * 4;
int y;
unsigned char *dst = (unsigned char *) s->tile->data;
const unsigned char *src = (const unsigned char *) pixels;
for(y = 0; y < (int) s->tile->height; ++y) {
vc_copylineRGBA (dst, src, linesize, 16, 8, 0);
src += linesize;
dst += linesize;
}
CFRelease(data);
CFRelease(image);
#endif
if(s->fps > 0.0) {
struct timeval cur_time;

View File

@@ -0,0 +1,44 @@
/**
* @file screen_x11.h
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2012-2013 CESNET, z.s.p.o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define VIDCAP_SCREEN_ID 0x5645ba22
struct vidcap_type *vidcap_screen_x11_probe(void);
void *vidcap_screen_x11_init(const struct vidcap_params *params);
void vidcap_screen_x11_done(void *state);
struct video_frame *vidcap_screen_x11_grab(void *state, struct audio_frame **audio);