diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/import_x11.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/import_x11.c | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/import_x11.c b/debian/transcode/transcode-1.1.7/import/import_x11.c new file mode 100644 index 00000000..da9ca2af --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/import_x11.c @@ -0,0 +1,465 @@ +/* + * demultiplex_x11.c -- extract full-screen images from an X11 connection. + * (C) 2006-2010 Francesco Romani <fromani at gmail dot com> + * + * This file is part of transcode, a video stream processing tool. + * + * transcode is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * transcode is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "transcode.h" +#include "libtc/optstr.h" + +#include "libtc/tcmodule-plugin.h" +#include "libtc/tctimer.h" +#include "libtc/optstr.h" + +#include "x11source.h" + +/*%* + *%* DESCRIPTION + *%* This module captures video frames from X window system using libX11. + *%* + *%* BUILD-DEPENDS + *%* libcx11-6 >= 1.0.0 + *%* + *%* DEPENDS + *%* libcx11-6 >= 1.0.0 + *%* + *%* PROCESSING + *%* import/demuxer + *%* + *%* MEDIA + *%* video + *%* + *%* #INPUT + *%* + *%* OUTPUT + *%* YUV420P, YUV422P, RGB24* + *%* + *%* OPTION + *%* skew_limit (integer) + *%* maximum frame A/V skew (ms) before correction attempt + *%*/ + + +/* + * TODO (approx. priority order) + * - Improve framerate emulation. + * It isn't easy without encoder support, and we will not have + * any smarter encoder at least until 1.2.0. + * - Grab cursor. + * - Make faster where feasible. + */ + +#define DEBUG 1 + +#define LEGACY 1 + +#ifdef LEGACY +# define MOD_NAME "import_x11.so" +#else +# define MOD_NAME "demultiplex_x11.so" +#endif + +#define MOD_VERSION "v0.1.0 (2007-07-21)" +#define MOD_CAP "fetch full-screen frames from an X11 connection" + +#define MOD_FEATURES \ + TC_MODULE_FEATURE_DEMULTIPLEX|TC_MODULE_FEATURE_VIDEO +#define MOD_FLAGS \ + TC_MODULE_FLAG_RECONFIGURABLE + +/*************************************************************************/ + +static const char tc_x11_help[] = "" + "Overview:\n" + " This module acts as a bridge from transcode an a X11 server.\n" + " It grabs screenshots at fixed rate from X11 connection, allowing\n" + " to record screencast and so on.\n" + "Options:\n" + " skew_limit=N tune maximum frame skew (ms) before correction\n" + " help produce module overview and options explanations\n"; + +#define SKEW_LIM_DEFAULT 0 +#define SKEW_LIM_MIN 0 +#define SKEW_LIM_MAX 5 + +static const int frame_delay_divs[] = { +/* div skew_lim */ + 1, /* 0 (disabled) */ + 2, /* 1 (weakest) */ + 3, + 5, + 10, + 20 /* 5 (strongest) */ +}; + + +typedef struct tcx11privatedata_ TCX11PrivateData; +struct tcx11privatedata_ { + TCX11Source src; + TCTimer timer; + + uint64_t frame_delay; + /* how much (ms) we must sleep to properly emulate frame rate? */ + + uint32_t expired; /* counter for execessively delayed frames */ + + uint64_t reftime; /* reference time (ms) for skew computation */ + + int64_t skew; /* take in account excess of retard (ms) */ + int64_t skew_limit; /* how much (ms) skew we can tolerate? */ +}; + + +/*************************************************************************/ +/* helpers */ + +static void tdebug(const TCX11PrivateData *priv, const char *str) +{ +#ifdef DEBUG + uint64_t now = tc_gettime(); + tc_log_info(MOD_NAME, "%-18s %lu", str, (unsigned long)(now - priv->reftime)); +#endif + return; +} + +/*************************************************************************/ + +static int tc_x11_init(TCModuleInstance *self, uint32_t features) +{ + TCX11PrivateData *priv = NULL; + + TC_MODULE_SELF_CHECK(self, "init"); + TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); + + if (verbose) { + tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP); + } + priv = tc_malloc(sizeof(TCX11PrivateData)); + if (priv == NULL) { + return TC_ERROR; + } + + self->userdata = priv; + return TC_OK; +} + +static int tc_x11_fini(TCModuleInstance *self) +{ + TC_MODULE_SELF_CHECK(self, "fini"); + + tc_free(self->userdata); + self->userdata = NULL; + + return TC_OK; +} + +static int tc_x11_configure(TCModuleInstance *self, + const char *options, vob_t *vob) +{ + TCX11PrivateData *priv = NULL; + int ret = 0, skew_lim = SKEW_LIM_DEFAULT; + + TC_MODULE_SELF_CHECK(self, "configure"); + + priv = self->userdata; + + if (options != NULL) { + optstr_get(options, "skew_limit", "%i", &skew_lim); + if (skew_lim < SKEW_LIM_MIN || skew_lim > SKEW_LIM_MAX) { + tc_log_warn(MOD_NAME, "skew limit value out of range," + " reset to defaults [%i]", + SKEW_LIM_DEFAULT); + } + } + + priv->skew = 0; + priv->reftime = 0; + priv->expired = 0; + priv->frame_delay = (uint64_t)(1000000.0 / vob->fps); /* microseconds */ + priv->skew_limit = priv->frame_delay / frame_delay_divs[skew_lim]; + + if (verbose >= TC_DEBUG) { + tc_log_info(MOD_NAME, "frame delay: %lu ms", + (unsigned long)priv->frame_delay); + tc_log_info(MOD_NAME, "skew limit: %li ms", + (long)priv->skew_limit); + } + + + ret = tc_timer_init_soft(&priv->timer, 0); + if (ret != 0) { + tc_log_error(MOD_NAME, "configure: can't initialize timer"); + return TC_ERROR; + } + + /* nothing to do here, yet */ + ret = tc_x11source_is_display_name(vob->video_in_file); + if (ret == TC_FALSE) { + tc_log_error(MOD_NAME, "configure: given source doesn't look like" + " a DISPLAY specifier"); + return TC_ERROR; + } + + ret = tc_x11source_open(&priv->src, vob->video_in_file, + TC_X11_MODE_BEST, vob->im_v_codec); + if (ret != 0) { + tc_log_error(MOD_NAME, "configure: failed to open X11 connection" + " to '%s'", vob->video_in_file); + return TC_ERROR; + } + + return TC_OK; +} + +static int tc_x11_inspect(TCModuleInstance *self, + const char *param, const char **value) +{ + TC_MODULE_SELF_CHECK(self, "inspect"); + + if (optstr_lookup(param, "help")) { + *value = tc_x11_help; + } + + return TC_OK; +} + +static int tc_x11_stop(TCModuleInstance *self) +{ + TCX11PrivateData *priv = NULL; + int ret = 0; + + TC_MODULE_SELF_CHECK(self, "stop"); + + priv = self->userdata; + + ret = tc_x11source_close(&priv->src); + if (ret != 0) { + tc_log_error(MOD_NAME, "stop: failed to close X11 connection"); + return TC_ERROR; + } + + ret = tc_timer_fini(&priv->timer); + if (ret != 0) { + tc_log_error(MOD_NAME, "stop: failed to stop timer"); + return TC_ERROR; + } + + if (verbose >= TC_DEBUG) { + tc_log_info(MOD_NAME, "expired frames count: %lu", + (unsigned long)priv->expired); + } + return TC_OK; +} + +static int tc_x11_demultiplex(TCModuleInstance *self, + vframe_list_t *vframe, aframe_list_t *aframe) +{ + TCX11PrivateData *priv = NULL; + uint64_t now = 0; + int ret = 0; + + TC_MODULE_SELF_CHECK(self, "demultiplex"); + priv = self->userdata; + + priv->reftime = tc_gettime(); + + tdebug(priv, "begin demultiplex"); + + if (aframe != NULL) { + aframe->audio_len = 0; /* no audio from here */ + } + + if (vframe != NULL) { + tdebug(priv, " begin acquire"); + + ret = tc_x11source_acquire(&priv->src, vframe->video_buf, + vframe->video_size); + + tdebug(priv, " end acquire"); + + if (ret > 0) { + int64_t naptime = 0; + uint64_t now = 0; + + vframe->attributes |= TC_FRAME_IS_KEYFRAME; + vframe->video_len = ret; + + now = tc_gettime(); + naptime = (priv->frame_delay - (now - priv->reftime)); + + if (priv->skew >= priv->skew_limit) { + tc_log_info(MOD_NAME, " skew correction (naptime was %lu)", + (unsigned long)naptime); + int64_t t = naptime; + naptime -= priv->skew; + priv->skew = TC_MAX(0, priv->skew - t); + } + + if (naptime <= 0) { + /* don't sleep at all if delay is already excessive */ + tc_log_info(MOD_NAME, "%-18s", " NO SLEEP!"); + priv->expired++; + } else { + tc_log_info(MOD_NAME, "%-18s %lu", " sleep time", + (unsigned long)(naptime)); + tc_timer_sleep(&priv->timer, (uint64_t)naptime); + } + } + } + + now = tc_gettime(); + now -= priv->reftime; + priv->skew += now - priv->frame_delay; + + tdebug(priv, "end multiplex"); + + tc_log_info(MOD_NAME, "%-18s %li", "detected skew", (long)(priv->skew)); + return (ret > 0) ?ret :-1; +} + + +/*************************************************************************/ + +static const TCCodecID tc_x11_codecs_in[] = { TC_CODEC_ERROR }; + +/* a multiplexor is at the end of pipeline */ +static const TCCodecID tc_x11_codecs_out[] = { + TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_YUV422P, TC_CODEC_ERROR +}; + +static const TCFormatID tc_x11_formats_in[] = { TC_FORMAT_X11, TC_FORMAT_ERROR }; +static const TCFormatID tc_x11_formats_out[] = { TC_FORMAT_ERROR }; + +static const TCModuleInfo tc_x11_info = { + .features = MOD_FEATURES, + .flags = MOD_FLAGS, + .name = MOD_NAME, + .version = MOD_VERSION, + .description = MOD_CAP, + .codecs_in = tc_x11_codecs_in, + .codecs_out = tc_x11_codecs_out, + .formats_in = tc_x11_formats_in, + .formats_out = tc_x11_formats_out +}; + +static const TCModuleClass tc_x11_class = { + TC_MODULE_CLASS_HEAD(tc_x11), + + .init = tc_x11_init, + .fini = tc_x11_fini, + .configure = tc_x11_configure, + .stop = tc_x11_stop, + .inspect = tc_x11_inspect, + + .demultiplex = tc_x11_demultiplex, +}; + +TC_MODULE_ENTRY_POINT(tc_x11) + +/*************************************************************************/ +/*************************************************************************/ + +/* Old-fashioned module interface. */ + +static TCModuleInstance mod_video; + +static int verbose_flag; +static int capability_flag = TC_CAP_YUV|TC_CAP_RGB|TC_CAP_YUV422|TC_CAP_VID; + +#define MOD_PRE x11 +#define MOD_CODEC "(video) X11" + +#include "import_def.h" + +/*************************************************************************/ + +#define RETURN_IF_FAILED(ret) do { \ + if ((ret) != TC_OK) { \ + return ret; \ + } \ +} while (0) + +#define COMMON_CHECK(param) do { \ + if ((param)->flag != TC_VIDEO) { \ + return TC_ERROR; \ + } \ +} while (0) + + +MOD_open +{ + int ret; + + COMMON_CHECK(param); + + ret = tc_x11_init(&mod_video, TC_MODULE_FEATURE_DEMULTIPLEX); + RETURN_IF_FAILED(ret); + + ret = tc_x11_configure(&mod_video, "", vob); + RETURN_IF_FAILED(ret); + + return TC_OK; +} + +MOD_decode +{ + vframe_list_t vframe; + int ret = 0; + + COMMON_CHECK(param); + + vframe.attributes = 0; + vframe.video_buf = param->buffer; + vframe.video_size = param->size; + + ret = tc_x11_demultiplex(&mod_video, &vframe, NULL); + + if (ret <= 0) { + /* well, frames from X11 never "ends", really :) */ + return TC_ERROR; + } + + param->size = ret; + param->attributes = vframe.attributes; + return TC_OK; +} + +MOD_close +{ + int ret; + + COMMON_CHECK(param); + + ret = tc_x11_stop(&mod_video); + RETURN_IF_FAILED(ret); + + ret = tc_x11_fini(&mod_video); + RETURN_IF_FAILED(ret); + + return TC_OK; +} + +/*************************************************************************/ +/* + * Local variables: + * c-file-style: "stroustrup" + * c-file-offsets: ((case-label . *) (statement-case-intro . *)) + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: + */ |
