summaryrefslogtreecommitdiffstats
path: root/debian/transcode/transcode-1.1.7/import/import_x11.c
diff options
context:
space:
mode:
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.c465
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:
+ */