hi all,
all things I said for filter_invert can be applied now too.
greetings, branko kokanovic
Index: filter/filter_facemask.c
===================================================================
RCS file: /cvstc/transcode/filter/filter_facemask.c,v
retrieving revision 1.18
diff -u -r1.18 filter_facemask.c
--- filter/filter_facemask.c 29 Sep 2006 05:03:09 -0000 1.18
+++ filter/filter_facemask.c 29 Jul 2007 18:20:46 -0000
@@ -1,9 +1,9 @@
/*
- * filter_facemask.c
+ * filter_facemask.c -- mask people faces in video interviews
*
* Copyright (C) Julien Tierny <[EMAIL PROTECTED]> - October 2004
* Copyright (C) Thomas Oestreich - June 2001
- *
+ * modified 2007 by Branko Kokanovic <branko.kokanovic at gmail dot com> to use NMS
* This file is part of transcode, a video stream processing tool
*
* transcode is free software; you can redistribute it and/or modify
@@ -23,27 +23,47 @@
*/
#define MOD_NAME "filter_facemask.so"
-#define MOD_VERSION "v0.2 (2004-11-01)"
+#define MOD_VERSION "v0.2.1 (2007-07-29)"
#define MOD_CAP "Mask people faces in video interviews."
#define MOD_AUTHOR "Julien Tierny"
+#define MOD_FEATURES \
+ TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO
+#define MOD_FLAGS \
+ TC_MODULE_FLAG_RECONFIGURABLE
+
+/* -------------------------------------------------
+ *
+ * mandatory include files
+ *
+ *-------------------------------------------------*/
#include "transcode.h"
#include "filter.h"
#include "libtc/libtc.h"
#include "libtc/optstr.h"
-
+#include "libtc/tcmodule-plugin.h"
/* For RGB->YUV conversion */
#include "libtcvideo/tcvideo.h"
+static const char facemask_help[]=""
+ "Overview:\n"
+ " This filter can mask people faces in video interviews.\n"
+ " Both YUV and RGB formats are supported, in multithreaded mode.\n"
+ "\n"
+ " Warning:\n"
+ " You have to calibrate by your own the mask dimensions and positions so as it fits to your video sample.\n"
+ " You also have to choose a resolution that is multiple of the mask dimensions.\n"
+ "\n"
+ "Options:\n"
+ " 'xpos': Position of the upper left corner of the mask (x)\n"
+ " 'ypos': Position of the upper left corner of the mask (y)\n"
+ " 'xresolution': Resolution of the mask (width)\n"
+ " 'yresolution': Resolution of the mask (height)\n"
+ " 'xdim': Width of the mask (= n*xresolution)\n"
+ " 'ydim': Height of the mask (= m*yresolution)\n";
-/*-------------------------------------------------
- *
- * single function interface
- *
- *-------------------------------------------------*/
-
-
-typedef struct parameter_struct {
+/*************************************************************************/
+typedef struct {
int xpos;
int ypos;
int xresolution;
@@ -51,30 +71,9 @@
int xdim;
int ydim;
TCVHandle tcvhandle;
-} parameter_struct;
-
-static parameter_struct *parameters = NULL;
-
-static void help_optstr(void)
-{
- tc_log_info(MOD_NAME, "(%s) help"
-"\n* Overview:\n"
-" This filter can mask people faces in video interviews.\n"
-" Both YUV and RGB formats are supported, in multithreaded mode.\n"
-"\n"
-"* Warning:\n"
-" You have to calibrate by your own the mask dimensions and positions so as it fits to your video sample.\n"
-" You also have to choose a resolution that is multiple of the mask dimensions.\n"
-"\n"
-"* Options:\n"
-" 'xpos': Position of the upper left corner of the mask (x)\n"
-" 'ypos': Position of the upper left corner of the mask (y)\n"
-" 'xresolution': Resolution of the mask (width)\n"
-" 'yresolution': Resolution of the mask (height)\n"
-" 'xdim': Width of the mask (= n*xresolution)\n"
-" 'ydim': Height of the mask (= m*yresolution)\n"
- , MOD_CAP);
-}
+ int codec;
+ char conf_str[TC_BUF_MIN];
+} FacemaskPrivateData;
static int check_parameters(int x, int y, int w, int h, int W, int H, vob_t *vob){
@@ -134,131 +133,331 @@
return 0;
}
-int tc_filter(frame_list_t *ptr_, char *options){
- vframe_list_t *ptr = (vframe_list_t *)ptr_;
- static vob_t *vob=NULL;
+/*************************************************************************/
+/* Module interface routines and data. */
- if(ptr->tag & TC_FILTER_GET_CONFIG) {
-
- optstr_filter_desc (options, MOD_NAME, MOD_CAP, MOD_VERSION, "Julien Tierny", "VRYMEO", "1");
- optstr_param(options, "xpos", "Position of the upper left corner of the mask (x)", "%d", "0", "0", "oo");
- optstr_param(options, "ypos", "Position of the upper left corner of the mask (y)", "%d", "0", "0", "oo");
- optstr_param(options, "xresolution", "Resolution of the mask (width)", "%d", "0", "1", "oo");
- optstr_param(options, "yresolution", "Resolution of the mask (height)", "%d", "0", "1", "oo");
- optstr_param(options, "xdim", "Width of the mask (= n*xresolution)", "%d", "0", "1", "oo");
- optstr_param(options, "ydim", "Height of the mask (= m*yresolution)", "%d", "0", "1", "oo");
- return 0;
- }
+/*************************************************************************/
- //----------------------------------
- //
- // filter init
- //
- //----------------------------------
+/**
+ * facemask_init: Initialize this instance of the module. See
+ * tcmodule-data.h for function details.
+ */
+static int facemask_init(TCModuleInstance *self, uint32_t features)
+{
+ FacemaskPrivateData *fpd = NULL;
- if(ptr->tag & TC_FILTER_INIT) {
+ TC_MODULE_SELF_CHECK(self, "init");
+ TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);
- if((vob = tc_get_vob())==NULL)
- return(-1);
+ fpd = tc_malloc(sizeof(FacemaskPrivateData));
+ if (!fpd) {
+ tc_log_error(MOD_NAME, "init: out of memory!");
+ return TC_ERROR;
+ }
+ self->userdata = fpd;
+
+ /* initialize data */
+ fpd->xpos = 0;
+ fpd->ypos = 0;
+ fpd->xresolution = 1;
+ fpd->yresolution = 1;
+ fpd->xdim = 1;
+ fpd->ydim = 1;
+ fpd->tcvhandle = 0;
+
+ if(verbose) {
+ tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
+ }
+ return TC_OK;
+}
+/*************************************************************************/
- /* Now, let's handle the options ... */
- parameters = tc_malloc (sizeof(parameter_struct));
- if(parameters == NULL)
- return -1;
+/**
+ * facemask_fini: Clean up after this instance of the module. See
+ * tcmodule-data.h for function details.
+ */
+
+static int facemask_fini(TCModuleInstance *self)
+{
+ FacemaskPrivateData *fpd = NULL;
+
+ TC_MODULE_SELF_CHECK(self, "fini");
+
+ fpd = self->userdata;
+
+ if (fpd->tcvhandle){
+ tcv_free(fpd->tcvhandle);
+ }
+
+ tc_free(self->userdata);
+ self->userdata = NULL;
+
+ return TC_OK;
+}
+
+/*************************************************************************/
+
+/**
+ * facemask_configure: Configure this instance of the module. See
+ * tcmodule-data.h for function details.
+ */
+
+static int facemask_configure(TCModuleInstance *self,
+ const char *options, vob_t *vob)
+{
+ FacemaskPrivateData *fpd = NULL;
+
+ TC_MODULE_SELF_CHECK(self, "configure");
+
+ fpd = self->userdata;
+
+ if(vob == NULL){
+ return TC_ERROR;
+ }
/* Filter default options */
- if (verbose & TC_DEBUG)
- tc_log_info(MOD_NAME, "Preparing default options.");
- parameters->xpos = 0;
- parameters->ypos = 0;
- parameters->xresolution = 1;
- parameters->yresolution = 1;
- parameters->xdim = 1;
- parameters->ydim = 1;
- parameters->tcvhandle = 0;
-
- if (options){
- /* Get filter options via transcode core */
- if (verbose & TC_DEBUG)
- tc_log_info(MOD_NAME, "Merging options from transcode.");
- optstr_get(options, "xpos", "%d", ¶meters->xpos);
- optstr_get(options, "ypos", "%d", ¶meters->ypos);
- optstr_get(options, "xresolution", "%d", ¶meters->xresolution);
- optstr_get(options, "yresolution", "%d", ¶meters->yresolution);
- optstr_get(options, "xdim", "%d", ¶meters->xdim);
- optstr_get(options, "ydim", "%d", ¶meters->ydim);
- if (optstr_lookup(options, "help") !=NULL) help_optstr();
+ if (verbose & TC_DEBUG)
+ tc_log_info(MOD_NAME, "Preparing default options.");
+ fpd->codec = vob->im_v_codec;
+ fpd->xpos = 0;
+ fpd->ypos = 0;
+ fpd->xresolution = 1;
+ fpd->yresolution = 1;
+ fpd->xdim = 1;
+ fpd->ydim = 1;
+ fpd->tcvhandle = 0;
+
+ if (options) {
+ if (verbose >= TC_STATS) {
+ tc_log_info(MOD_NAME, "options=%s", options);
+ }
+ optstr_get(options, "xpos", "%d", &fpd->xpos);
+ optstr_get(options, "ypos", "%d", &fpd->ypos);
+ optstr_get(options, "xresolution", "%d", &fpd->xresolution);
+ optstr_get(options, "yresolution", "%d", &fpd->yresolution);
+ optstr_get(options, "xdim", "%d", &fpd->xdim);
+ optstr_get(options, "ydim", "%d", &fpd->ydim);
}
- if (vob->im_v_codec == CODEC_YUV){
- if (!(parameters->tcvhandle = tcv_init())) {
- tc_log_error(MOD_NAME, "Error at image conversion initialization.");
- return(-1);
- }
- }
+ if (vob->im_v_codec == CODEC_YUV){
+ fpd->tcvhandle = tcv_init();
+ if (!fpd->tcvhandle) {
+ tc_log_error(MOD_NAME, "Error at image conversion initialization.");
+ return TC_ERROR;
+ }
+ }
+
+ if (check_parameters(fpd->xpos, fpd->ypos, fpd->xresolution, fpd->yresolution, fpd->xdim, fpd->ydim, vob) < 0){
+ return TC_ERROR;
+ }
- if (check_parameters(parameters->xpos, parameters->ypos, parameters->xresolution, parameters->yresolution, parameters->xdim, parameters->ydim, vob) < 0)
- return -1;
+ return TC_OK;
+}
- if(verbose)
- tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
+/*************************************************************************/
- return(0);
- }
+/**
+ * facemask_stop: Reset this instance of the module. See tcmodule-data.h
+ * for function details.
+ */
- //----------------------------------
- //
- // filter close
- //
- //----------------------------------
+static int facemask_stop(TCModuleInstance *self)
+{
+ TC_MODULE_SELF_CHECK(self, "stop");
+ return TC_OK;
+}
+/*************************************************************************/
- if(ptr->tag & TC_FILTER_CLOSE) {
+/**
+ * facemask_inspect: Return the value of an option in this instance of
+ * the module. See tcmodule-data.h for function details.
+ */
- tcv_free(parameters->tcvhandle);
+static int facemask_inspect(TCModuleInstance *self,
+ const char *param, const char **value)
+{
+ FacemaskPrivateData *fpd = NULL;
- /* Let's free the parameter structure */
- free(parameters);
- parameters = NULL;
+ TC_MODULE_SELF_CHECK(self, "inspect");
+ TC_MODULE_SELF_CHECK(param, "inspect");
+ TC_MODULE_SELF_CHECK(value, "inspect");
+
+ fpd = self->userdata;
+
+ if (optstr_lookup(param, "help")) {
+ *value = facemask_help;
+ }
+ if (optstr_lookup(param, "xpos")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"xpos=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
+ if (optstr_lookup(param, "ypos")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"ypos=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
+ if (optstr_lookup(param, "xresolution")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"xresolution=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
+ if (optstr_lookup(param, "yresolution")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"yresolution=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
+ if (optstr_lookup(param, "xdim")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"xdim=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
+ if (optstr_lookup(param, "ydim")) {
+ tc_snprintf(fpd->conf_str, sizeof(fpd->conf_str),"ydim=%d",fpd->xpos);
+ *value = fpd->conf_str;
+ }
- return(0);
- }
+ return TC_OK;
+}
- //----------------------------------
- //
- // filter frame routine
- //
- //----------------------------------
+/*************************************************************************/
- if(ptr->tag & TC_POST_M_PROCESS && ptr->tag & TC_VIDEO && !(ptr->attributes & TC_FRAME_IS_SKIPPED)) {
+/**
+ * facemask_filter_video: show something on given frame of the video
+ * stream. See tcmodule-data.h for function details.
+ */
+static int facemask_filter_video(TCModuleInstance *self, vframe_list_t *frame)
+{
+ FacemaskPrivateData *fpd = NULL;
+ int post = 0;
- switch(vob->im_v_codec){
- case CODEC_RGB:
- return print_mask(parameters->xpos, parameters->ypos, parameters->xresolution, parameters->yresolution, parameters->xdim, parameters->ydim, ptr);
- break;
+ TC_MODULE_SELF_CHECK(self, "filer_video");
+ TC_MODULE_SELF_CHECK(frame, "filer_video");
- case CODEC_YUV:
+ fpd = self->userdata;
+ post = (frame->tag & TC_POST_M_PROCESS);
- if (!tcv_convert(parameters->tcvhandle, ptr->video_buf, ptr->video_buf, ptr->v_width, ptr->v_height, IMG_YUV_DEFAULT, IMG_RGB24)){
- tc_log_error(MOD_NAME, "cannot convert YUV stream to RGB format !");
- return -1;
+ if(post && !(frame->attributes & TC_FRAME_IS_SKIPPED)) {
+ switch(fpd->codec){
+ case CODEC_RGB:
+ return print_mask(fpd->xpos, fpd->ypos, fpd->xresolution, fpd->yresolution, fpd->xdim, fpd->ydim, frame);
+ break;
+ case CODEC_YUV:
+ if (!tcv_convert(fpd->tcvhandle, frame->video_buf, frame->video_buf, frame->v_width, frame->v_height,
+ IMG_YUV_DEFAULT, IMG_RGB24)){
+ tc_log_error(MOD_NAME, "cannot convert YUV stream to RGB format !");
+ return TC_ERROR;
}
- if ((print_mask(parameters->xpos, parameters->ypos, parameters->xresolution, parameters->yresolution, parameters->xdim, parameters->ydim, ptr))<0) return -1;
- if (!tcv_convert(parameters->tcvhandle, ptr->video_buf, ptr->video_buf, ptr->v_width, ptr->v_height, IMG_RGB24, IMG_YUV_DEFAULT)){
- tc_log_error(MOD_NAME, "cannot convert RGB stream to YUV format !");
- return -1;
- }
- break;
+ if ((print_mask(fpd->xpos, fpd->ypos, fpd->xresolution, fpd->yresolution, fpd->xdim, fpd->ydim, frame))<0) {
+ return TC_ERROR;
+ }
+
+ if (!tcv_convert(fpd->tcvhandle, frame->video_buf, frame->video_buf, frame->v_width, frame->v_height,
+ IMG_RGB24, IMG_YUV_DEFAULT)){
+ tc_log_error(MOD_NAME, "cannot convert RGB stream to YUV format !");
+ return TC_ERROR;
+ }
+ break;
+ default:
+ tc_log_error(MOD_NAME, "Internal video codec is not supported.");
+ return TC_ERROR;
+ }
+ }
+ return TC_OK;
+}
- default:
- tc_log_error(MOD_NAME, "Internal video codec is not supported.");
- return -1;
- }
- }
- return(0);
+
+/*************************************************************************/
+
+static const TCCodecID facemask_codecs_in[] = {
+ TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR
+};
+static const TCCodecID facemask_codecs_out[] = {
+ TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR
+};
+static const TCFormatID facemask_formats[] = {
+ TC_FORMAT_ERROR
+};
+
+static const TCModuleInfo facemask_info = {
+ .features = MOD_FEATURES,
+ .flags = MOD_FLAGS,
+ .name = MOD_NAME,
+ .version = MOD_VERSION,
+ .description = MOD_CAP,
+ .codecs_in = facemask_codecs_in,
+ .codecs_out = facemask_codecs_out,
+ .formats_in = facemask_formats,
+ .formats_out = facemask_formats
+};
+
+static const TCModuleClass facemask_class = {
+ .info = &facemask_info,
+
+ .init = facemask_init,
+ .fini = facemask_fini,
+ .configure = facemask_configure,
+ .stop = facemask_stop,
+ .inspect = facemask_inspect,
+
+ .filter_video = facemask_filter_video
+};
+
+extern const TCModuleClass *tc_plugin_setup(void)
+{
+ return &facemask_class;
}
+
+/*************************************************************************/
+
+static int facemask_get_config(TCModuleInstance *self, char *options)
+{
+ FacemaskPrivateData *fpd = NULL;
+
+ TC_MODULE_SELF_CHECK(self, "get_config");
+
+ fpd = self->userdata;
+
+ optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION,
+ MOD_AUTHOR, "VRYMEO", "1");
+
+ optstr_param (options, "help", "Mask people faces in video interviews", "", "0");
+ optstr_param(options, "xpos", "Position of the upper left corner of the mask (x)", "%d", "0", "0", "oo");
+ optstr_param(options, "ypos", "Position of the upper left corner of the mask (y)", "%d", "0", "0", "oo");
+ optstr_param(options, "xresolution", "Resolution of the mask (width)", "%d", "0", "1", "oo");
+ optstr_param(options, "yresolution", "Resolution of the mask (height)", "%d", "0", "1", "oo");
+ optstr_param(options, "xdim", "Width of the mask (= n*xresolution)", "%d", "0", "1", "oo");
+ optstr_param(options, "ydim", "Height of the mask (= m*yresolution)", "%d", "0", "1", "oo");
+
+ return TC_OK;
+}
+
+static int facemask_process(TCModuleInstance *self,
+ frame_list_t *frame)
+{
+ TC_MODULE_SELF_CHECK(self, "process");
+
+ if (frame->tag & TC_VIDEO) {
+ return facemask_filter_video(self, (vframe_list_t*)frame);
+ }
+ return TC_OK;
+}
+
+/*************************************************************************/
+
+/* Old-fashioned module interface. */
+
+TC_FILTER_OLDINTERFACE(facemask)
+
+/*************************************************************************/
+
+/*
+ * Local variables:
+ * c-file-style: "stroustrup"
+ * c-file-offsets: ((case-label . *) (statement-case-intro . *))
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vim: expandtab shiftwidth=4:
+ */