summaryrefslogtreecommitdiffstats
path: root/debian/transcode/transcode-1.1.7/tools/tcmodchain.c
diff options
context:
space:
mode:
Diffstat (limited to 'debian/transcode/transcode-1.1.7/tools/tcmodchain.c')
-rw-r--r--debian/transcode/transcode-1.1.7/tools/tcmodchain.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/tools/tcmodchain.c b/debian/transcode/transcode-1.1.7/tools/tcmodchain.c
new file mode 100644
index 00000000..cd553190
--- /dev/null
+++ b/debian/transcode/transcode-1.1.7/tools/tcmodchain.c
@@ -0,0 +1,536 @@
+/*
+ * tcmodchain.c -- simple module system explorer frontend
+ * (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 <glob.h>
+#include "tcstub.h"
+
+#define EXE "tcmodchain"
+
+/*************************************************************************/
+
+
+void version(void)
+{
+ printf("%s v%s (C) 2006-2010 Transcode Team\n", EXE, VERSION);
+}
+
+enum {
+ STATUS_DONE = -1, /* used internally */
+ STATUS_OK = 0,
+ STATUS_BAD_PARAM,
+ STATUS_MODULE_ERROR,
+ STATUS_MODULE_MISMATCH,
+ STATUS_GLOB_FAILED,
+};
+
+
+#define MAX_MODS (16)
+
+typedef struct modrequest_ ModRequest;
+struct modrequest_ {
+ char **rawdata; /* main reference */
+
+ const char *type; /* commodity */
+ const char *name; /* commodity */
+
+ TCModule module;
+};
+
+
+static void modrequest_init(ModRequest *modr);
+static int modrequest_load(TCFactory factory,
+ ModRequest *modr, const char *str);
+static int modrequest_scan(const char *modpath, const char *modstr,
+ glob_t *globbuf);
+static int modrequest_fill(TCFactory factory, ModRequest *mods,
+ size_t maxmods, size_t *modnum, glob_t *globbuf);
+#define modrequest_free(GLOBBUF) globfree((GLOBBUF))
+static int modrequest_unload(TCFactory factory, ModRequest *modr);
+
+/*************************************************************************/
+
+enum {
+ TC_MODULE_DEMUXER = 1, /* future */
+ TC_MODULE_DECODER = 2, /* future */
+ TC_MODULE_FILTER = 4, /* future */
+ TC_MODULE_ENCODER = 8,
+ TC_MODULE_MUXER = 16,
+
+ TC_MODULE_FIXED = 1024,
+ TC_MODULE_TEMPLATE = 2048,
+};
+
+
+static uint32_t parse_modstr(const char *str)
+{
+ uint32_t ret = 0;
+ if (str != NULL && strlen(str) > 0) {
+ struct {
+ const char *name;
+ int kind;
+ size_t off;
+ } tags[] = {
+ { "encode:", TC_MODULE_ENCODER, strlen("encode:") },
+ { "multiplex:", TC_MODULE_MUXER, strlen("multiplex:") },
+ { NULL, 0, 0 },
+ };
+ int i = 0;
+
+ for (i = 0; tags[i].name != NULL; i++) {
+ if (strncmp(str, tags[i].name, tags[i].off) == 0) {
+ ret |= tags[i].kind;
+ str += tags[i].off;
+ break;
+ }
+ }
+
+ /* found something supported/making sense */
+ if (ret != 0 && (str != NULL && strlen(str) > 0)) {
+ if (!strcmp(str, "*")) {
+ ret |= TC_MODULE_TEMPLATE;
+ } else {
+ ret |= TC_MODULE_FIXED;
+ }
+ }
+ }
+ return ret;
+}
+
+static int parse_path(const char *fullpath, char *modstr, size_t buflen)
+{
+ const char *pc = NULL;
+ char *pr = NULL;
+
+ if (!fullpath || !modstr || (buflen < TC_BUF_MIN)) {
+ return TC_ERROR;
+ }
+
+ pc = strrchr(fullpath, '/');
+ if (pc == NULL || strlen(pc + 1) > buflen) {
+ return TC_ERROR;
+ }
+ strlcpy(modstr, pc + 1, buflen);
+
+ pr = strrchr(modstr, '.');
+ if (pr == NULL) {
+ return TC_ERROR;
+ }
+ *pr = '\0';
+
+ pr = strchr(modstr, '_');
+ if (pr == NULL) {
+ return TC_ERROR;
+ }
+ *pr = ':';
+
+ return TC_OK;
+}
+
+
+/*************************************************************************/
+
+static void modrequest_init(ModRequest *modr)
+{
+ if (modr != NULL) {
+ modr->rawdata = NULL;
+ modr->type = NULL;
+ modr->name = NULL;
+ modr->module = NULL;
+ }
+}
+
+static int modrequest_load(TCFactory factory,
+ ModRequest *modr, const char *str)
+{
+ size_t pieces = 0;
+
+ if (factory == NULL || modr == NULL || str == NULL) {
+ tc_log_warn(EXE, "wrong parameters for modrequest_load");
+ return TC_ERROR;
+ }
+
+ modr->rawdata = tc_strsplit(str, ':', &pieces);
+ if (modr->rawdata == NULL || pieces != 2) {
+ tc_log_warn(EXE, "malformed module string: %s", str);
+ return TC_ERROR;
+ }
+ modr->type = modr->rawdata[0];
+ modr->name = modr->rawdata[1];
+
+ modr->module = tc_new_module(factory, modr->type, modr->name, TC_NONE);
+ if (modr->module == NULL) {
+ tc_log_warn(EXE, "failed creation of module: %s", str);
+ return TC_ERROR;
+ }
+ return TC_OK;
+}
+
+static int modrequest_unload(TCFactory factory, ModRequest *modr)
+{
+ if (factory == NULL || modr == NULL) {
+ tc_log_warn(EXE, "wrong parameters for modrequest_load");
+ return TC_ERROR;
+ }
+
+ tc_del_module(factory, modr->module);
+ tc_strfreev(modr->rawdata);
+
+ /* re-blank fields */
+ modrequest_init(modr);
+
+ return TC_OK;
+}
+
+static int modrequest_scan(const char *modpath, const char *modstr,
+ glob_t *globbuf)
+{
+ char path_model[PATH_MAX];
+ char buf[TC_BUF_MIN];
+ const char *pc = NULL;
+ int err = 0;
+
+ pc = strchr(modstr, ':');
+ if (pc == NULL) {
+ return 1;
+ }
+ if ((pc - modstr + 1) > sizeof(buf)) {
+ return 2; /* XXX watch out here */
+ }
+ strlcpy(buf, modstr, pc - modstr + 1);
+
+ tc_snprintf(path_model, sizeof(path_model), "%s/%s_*.so", modpath, buf);
+ err = glob(path_model, GLOB_ERR, NULL, globbuf);
+
+ if (err) {
+ tc_log_error(EXE, "error while scanning for modules: %s",
+ (err == GLOB_NOSPACE) ?"can't get enough memory" :
+ (err == GLOB_ABORTED) ?"read error" :
+ /* GLOB_NOMATCH */ "no modules found");
+ return -1;
+ }
+ return 0;
+}
+
+static int modrequest_fill(TCFactory factory, ModRequest *mods,
+ size_t maxmods, size_t *modnum, glob_t *globbuf)
+{
+ char modstr[TC_BUF_MIN];
+ int i = 0, count = 0, lim = 0;
+
+ if (!factory || !mods || !globbuf) {
+ return TC_ERROR;
+ }
+ if (maxmods < globbuf->gl_pathc) {
+ tc_log_warn(EXE, "found %u candidate modules, but "
+ "only %u allowed (dropping remaining)",
+ (unsigned)globbuf->gl_pathc, (unsigned)maxmods);
+ }
+ lim = TC_MIN(maxmods, globbuf->gl_pathc);
+
+ for (i = 0; i < lim; i++) {
+ int ret;
+
+ ret = parse_path(globbuf->gl_pathv[i], modstr, TC_BUF_MIN);
+ if (ret != 0) {
+ tc_log_warn(EXE, "error while parsing '%s', skipping",
+ globbuf->gl_pathv[i]);
+ continue;
+ }
+ ret = modrequest_load(factory, &mods[i], modstr);
+ if (ret != 0) {
+ tc_log_warn(EXE, "error while loading '%s', skipping",
+ modstr);
+ continue;
+ }
+ count++;
+ }
+
+ if (modnum != NULL) {
+ *modnum += count;
+ }
+
+ return TC_OK;
+}
+
+/*************************************************************************/
+
+typedef struct cmdletdata_ CmdLetData;
+struct cmdletdata_ {
+ ModRequest mods[MAX_MODS];
+ size_t modsnum;
+
+ const char *modpath;
+ TCFactory factory;
+};
+
+typedef int (*CmdLet)(CmdLetData *cdata, int argc, char **argv);
+
+
+#define CLEANUP(CDATA) do { \
+ int i = 0; \
+ for (i = 0; i < (CDATA)->modsnum; i++) { \
+ modrequest_unload((CDATA)->factory, &((CDATA)->mods[i])); \
+ } \
+ (CDATA)->modsnum = 0; \
+} while (0)
+
+/* XXX */
+static int check_module_pair(const ModRequest *head,
+ const ModRequest *tail,
+ const ModRequest *ref,
+ int verbose)
+{
+ int ret = 0;
+
+ if (head->module == NULL || tail->module == NULL) {
+ tc_log_error(EXE, "check_module_pair: missing module handle");
+ return -1;
+ }
+
+ ret = tc_module_info_match(TC_CODEC_ANY,
+ tc_module_get_info(head->module),
+ tc_module_get_info(tail->module));
+ if (verbose >= TC_DEBUG) {
+ tc_log_info(EXE, "%s:%s | %s:%s [%s]",
+ head->type, head->name, tail->type, tail->name,
+ (ret == 1) ?"OK" :"MISMATCH");
+ } else if (verbose >= TC_INFO) {
+ if (ret == 1) {
+ printf("%s\n", ref->name);
+ }
+ }
+ return ret;
+}
+
+static int cmdlet_usage(CmdLetData *unused, int ac, char **av)
+{
+ version();
+ printf("Usage: %s [options] module [module... [module...]]\n",
+ EXE);
+ printf(" -L list mode (see manpage for details)\n");
+ printf(" -C check mode (see manpage for details)\n");
+ printf(" -d verbosity verbosity mode [1 == TC_INFO]\n");
+ printf(" -m PATH use PATH as module path\n");
+ printf(" -v show program version and exit\n");
+ printf(" -h show this help message\n");
+ return STATUS_OK;
+}
+
+
+static int cmdlet_check(CmdLetData *cdata, int ac, char **av)
+{
+ int i = 0, matches = 0;
+ int status = STATUS_OK; /* let's be optimisc, once in lifetime */
+
+ if (ac < 2) {
+ tc_log_error(EXE, "not enough arguments for `check' mode");
+ return STATUS_BAD_PARAM;
+ }
+
+ for (i = 0; i < ac; i++) {
+ modrequest_load(cdata->factory, &cdata->mods[cdata->modsnum], av[i]);
+ cdata->modsnum++;
+ }
+
+ status = STATUS_OK;
+ if (cdata->modsnum >= 2) {
+ /* N modules, so N - 1 interfaces */
+ for (i = 0; i < cdata->modsnum - 1; i++) {
+ int ret = check_module_pair(&cdata->mods[i], &cdata->mods[i + 1],
+ &cdata->mods[i],
+ (verbose >= TC_INFO) ?TC_DEBUG :TC_QUIET);
+ if (ret != -1) { /* no error */
+ matches += ret;
+ }
+
+ }
+ if (matches < cdata->modsnum - 1) {
+ status = STATUS_MODULE_MISMATCH;
+ }
+ }
+
+ if (verbose) {
+ if (status == STATUS_OK) {
+ tc_log_info(EXE, "module chain OK");
+ } else {
+ tc_log_info(EXE, "module chain ILLEGAL");
+ }
+ }
+
+ CLEANUP(cdata);
+ return status;
+}
+
+static int cmdlet_list(CmdLetData *cdata, int ac, char **av)
+{
+ glob_t globbuf;
+ int ret, i = 0, fid = 0 /* fixed id */, tid = 0; /* template id */
+ uint32_t modkind[2] = { 0, 0 };
+ ModRequest fixed;
+
+ if (ac != 2) {
+ tc_log_error(EXE, "wrong number of arguments for `list' mode");
+ return STATUS_BAD_PARAM;
+ }
+ /* we support only encoder|multiplexor, yet */
+ modkind[0] = parse_modstr(av[0]);
+ if (!(modkind[0] & TC_MODULE_ENCODER)) {
+ tc_log_error(EXE, "unknown/unsupported module '%s'", av[0]);
+ return STATUS_BAD_PARAM;
+ }
+ modkind[1] = parse_modstr(av[1]);
+ if (!(modkind[1] & TC_MODULE_MUXER)) {
+ tc_log_error(EXE, "unknown/unsupported module '%s'", av[1]);
+ return STATUS_BAD_PARAM;
+ }
+
+ if ((modkind[0] & TC_MODULE_FIXED)
+ && (modkind[1] & TC_MODULE_TEMPLATE)) {
+ fid = 0;
+ tid = 1;
+ } else if ((modkind[0] & TC_MODULE_TEMPLATE)
+ && (modkind[1] & TC_MODULE_FIXED)) {
+ fid = 1;
+ tid = 0;
+ } else {
+ tc_log_error(EXE, "incorrect arguments,"
+ " maybe you want to use `check' mode?");
+ return STATUS_BAD_PARAM;
+ }
+
+ modrequest_init(&fixed);
+ ret = modrequest_load(cdata->factory, &fixed, av[fid]);
+ if (ret != TC_OK) {
+ return STATUS_MODULE_ERROR;
+ }
+
+ ret = modrequest_scan(cdata->modpath, av[tid], &globbuf);
+ if (ret != 0) {
+ return STATUS_GLOB_FAILED;
+ }
+ ret = modrequest_fill(cdata->factory, cdata->mods, MAX_MODS,
+ &cdata->modsnum, &globbuf);
+ if (ret != TC_OK) {
+ return STATUS_MODULE_ERROR;
+ }
+
+ for (i = 0; i < cdata->modsnum; i++) {
+ const ModRequest *H = (tid == 0) ?(&cdata->mods[i]) :(&fixed);
+ const ModRequest *T = (tid == 1) ?(&cdata->mods[i]) :(&fixed);
+ check_module_pair(H, T, &(cdata->mods[i]),
+ (verbose == 0) ?TC_INFO :verbose);
+ }
+
+ CLEANUP(cdata);
+ modrequest_free(&globbuf);
+ ret = modrequest_unload(cdata->factory, &fixed);
+ if (ret != TC_OK) {
+ return STATUS_MODULE_ERROR;
+ }
+ return STATUS_OK;
+}
+
+/*************************************************************************/
+
+int main(int argc, char *argv[])
+{
+ /* needed by filter modules */
+ TCVHandle tcv_handle = tcv_init();
+ CmdLet cmdlet = cmdlet_usage;
+ int ch, ret, status, i = 0;
+
+ CmdLetData cdata = {
+ .modpath = MOD_PATH,
+ .factory = NULL,
+ .modsnum = 0,
+ };
+
+ ac_init(AC_ALL);
+ tc_set_config_dir(NULL);
+ libtc_init(&argc, &argv);
+
+ filter[0].id = 0; /* to make gcc happy */
+ for (i = 0; i < MAX_MODS; i++) {
+ modrequest_init(&cdata.mods[i]);
+ }
+
+ while (1) {
+ ch = getopt(argc, argv, "LCd:?vhm:");
+ if (ch == -1) {
+ break;
+ }
+
+ switch (ch) {
+ case 'L':
+ cmdlet = cmdlet_list;
+ break;
+ case 'C':
+ cmdlet = cmdlet_check;
+ break;
+ case 'd':
+ if (optarg[0] == '-') {
+ cmdlet_usage(&cdata, argc, argv);
+ return STATUS_BAD_PARAM;
+ }
+ verbose = atoi(optarg);
+ break;
+ case 'm':
+ cdata.modpath = optarg;
+ break;
+ case 'v':
+ version();
+ return STATUS_OK;
+ case '?': /* fallthrough */
+ case 'h': /* fallthrough */
+ default:
+ cmdlet_usage(&cdata, argc, argv);
+ return STATUS_OK;
+ }
+ }
+
+ /* XXX: watch out here */
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * we can't distinguish from OMS and NMS modules at glance, so try
+ * first using new module system
+ */
+ cdata.factory = tc_new_module_factory(cdata.modpath, verbose);
+
+ status = cmdlet(&cdata, argc, argv);
+
+ ret = tc_del_module_factory(cdata.factory); /* XXX: unchecked */
+ tcv_free(tcv_handle);
+ return status;
+}
+
+/*************************************************************************/
+
+/*
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * c-file-offsets: ((case-label . *) (statement-case-intro . *))
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vim: expandtab shiftwidth=4:
+ */