Yet another stupid filter:)
RGB and YUV supported (with YUV->RGB conversion for YUV)
Parameters are:
corner (=tl, tr, bl, br) (top left, top right, bottom left, bottom
right) that gets copied around frame
range (start-end/step - standard, like in other filters)
Example:
transcode ... -J kaleidoscope=corner=tl

This is not generalized form of kaleidoscope effect, but this is the
most sane for videos. I should add all those options found here:
http://www.filterforge.com/more/help/Components/Patterns/Kaleidoscope.html
(currently it looks like 'Kino' one)

Hope you like it (and don't get epileptic seizure:o)

This is (probably) last thing from me, back to work 01.08 (if you see
new filter or NMS port of existing filter, that means I got fired:)

greetings, branko kokanovic
/*
 * filter_kaleidoscope.c -- kaleidoscope filter: does kaleidoscoping of frames
 * Written     by Branko Kokanovic <branko.kokanovic at gmail> - July 2007
 *
 * This file is part of transcode, a video stream processing tool.
 * transcode is free software, distributable under the terms of the GNU
 * General Public License (version 2 or later).  See the file COPYING
 * for details.
 */

#define MOD_NAME    "filter_kaleidoscope.so"
#define MOD_VERSION "v1.0.0 (2007-07-30)"
#define MOD_CAP     "kaleidoscope filter plugin; does frame kaleidoscoping"
#define MOD_AUTHOR  "Branko Kokanovic"
#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 kaleidoscope_help[] = ""
    "Overview:\n"
    "    This filter does kaleidoscoping of frames\n"
    "Options:\n"
    "   'corner'   Frame corner that gets kaleidoscoping. Can be one of: "
    "       tl (Top Left), tr (Top Right), bl (Bottom Left), br (Bottom Right) [tl]\n"
    "   'range' apply filter to [start-end]/step frames [0-oo/1]\n";

static const char kaleidoscope_tl[]="Top Left";
static const char kaleidoscope_tr[]="Top Right";
static const char kaleidoscope_bl[]="Bottom Left";
static const char kaleidoscope_br[]="Bottom Right";

/*************************************************************************/

typedef enum { KALEIDOSCOPE_TL=0, KALEIDOSCOPE_TR, KALEIDOSCOPE_BL, KALEIDOSCOPE_BR} Corners;

typedef struct {
	unsigned int start;     /* start frame */
	unsigned int end;       /* end frame */
	unsigned int step;      /* every Nth frame */
    int boolstep;
    unsigned int corner;    /* corner that gets kaleidoscoping */
    int codec;              /* remembering codec */
    TCVHandle tcvhandle;
} KaleidoscopeData;

/*************************************************************************/

/* Module interface routines and data. */

/*************************************************************************/

/**
 * kaleidoscope_init:  Initialize this instance of the module.  See
 * tcmodule-data.h for function details.
 */

static int kaleidoscope_init(TCModuleInstance *self, uint32_t features)
{
    KaleidoscopeData *kd=NULL;

    TC_MODULE_SELF_CHECK(self, "init");
    TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features);

    kd = tc_malloc(sizeof(KaleidoscopeData));
    if (!kd) {
        tc_log_error(MOD_NAME, "init: out of memory!");
        return TC_ERROR;
    }
    self->userdata = kd;

    /* initialize */
    kd->corner = KALEIDOSCOPE_TL;
    kd->start=0;
    kd->end=(unsigned int)-1;
    kd->step=1;

    if (verbose) {
        tc_log_info(MOD_NAME, "%s %s", MOD_VERSION, MOD_CAP);
    }
    return TC_OK;
}

/*************************************************************************/

/**
 * kaleidoscope_fini:  Clean up after this instance of the module.  See
 * tcmodule-data.h for function details.
 */

static int kaleidoscope_fini(TCModuleInstance *self)
{
    KaleidoscopeData *kd = NULL;
    TC_MODULE_SELF_CHECK(self, "fini");

    kd = self->userdata;

    if (kd->tcvhandle){
        tcv_free(kd->tcvhandle);
    }
    tc_free(self->userdata);
    self->userdata = NULL;
    return TC_OK;
}

/*************************************************************************/

/**
 * kaleidoscope_configure:  Configure this instance of the module.  See
 * tcmodule-data.h for function details.
 */

static int kaleidoscope_configure(TCModuleInstance *self,
                          const char *options, vob_t *vob)
{
    KaleidoscopeData *kd = NULL;

    TC_MODULE_SELF_CHECK(self, "configure");

    kd = self->userdata;

    /* checks for RGB or YUV */
    if ((vob->im_v_codec != CODEC_YUV) && (vob->im_v_codec != CODEC_RGB)){
        tc_log_error(MOD_NAME, "This filter is only capable of RGB and YUV mode");
        return TC_ERROR;
    }
    /* setup defaults */
    kd->corner = KALEIDOSCOPE_TL;
    kd->codec = vob->im_v_codec;
    if (vob->im_v_codec == CODEC_YUV){
        kd->tcvhandle = tcv_init();
        if (!kd->tcvhandle) {
            tc_log_error(MOD_NAME, "Error at image conversion initialization.");
            return TC_ERROR;
	    }
    }
    kd->start=0;
    kd->end=(unsigned int)-1;
    kd->step=1;

    if (options) {
        int ret;
        char buf[TC_BUF_MAX];
        if (verbose >= TC_STATS) {
            tc_log_info(MOD_NAME, "options=%s", options);
        }
        ret=optstr_get(options, "corner","%[^:]",buf);
        if (ret>0){
            if      (strcmp(buf,"tl")==0)
                kd->corner=KALEIDOSCOPE_TL;
            else if (strcmp(buf,"tr")==0)
                kd->corner=KALEIDOSCOPE_TR;
            else if (strcmp(buf,"bl")==0)
                kd->corner=KALEIDOSCOPE_BL;
            else if (strcmp(buf,"br")==0)
                kd->corner=KALEIDOSCOPE_BR;
        }
        optstr_get(options, "range",  "%u-%u/%d", &kd->start, &kd->end, &kd->step);
    }

    if (kd->start % kd->step == 0)
        kd->boolstep = 0;
    else
        kd->boolstep = 1;

    return TC_OK;
}

/*************************************************************************/

/**
 * kaleidoscope_stop:  Reset this instance of the module.  See tcmodule-data.h
 * for function details.
 */

static int kaleidoscope_stop(TCModuleInstance *self)
{
    TC_MODULE_SELF_CHECK(self, "stop");
    return TC_OK;
}

/*************************************************************************/

/**
 * kaleidoscope_inspect:  Return the value of an option in this instance of
 * the module.  See tcmodule-data.h for function details.
 */

static int kaleidoscope_inspect(TCModuleInstance *self,
                        const char *param, const char **value)
{
    KaleidoscopeData *kd = NULL;

    TC_MODULE_SELF_CHECK(self, "inspect");
    TC_MODULE_SELF_CHECK(param, "inspect");
    TC_MODULE_SELF_CHECK(value, "inspect");

    kd = self->userdata;

    if (optstr_lookup(param, "help")) {
        *value = kaleidoscope_help; 
    }else if (optstr_lookup(param, "corner")) {
        switch (kd->corner){
            case KALEIDOSCOPE_TL:
                *value=kaleidoscope_tl;
                break;
            case KALEIDOSCOPE_TR:
                *value=kaleidoscope_tr;
                break;
            case KALEIDOSCOPE_BL:
                *value=kaleidoscope_bl;
                break;
            case KALEIDOSCOPE_BR:
                *value=kaleidoscope_br;
                break;
        }
    }
    return TC_OK;
}

/*************************************************************************/

/**
 * kaleidoscope_filter_video:  kaleidoscops the frame
 * See tcmodule-data.h for function details.
 */

static int kaleidoscope_filter_video(TCModuleInstance *self, vframe_list_t *frame)
{
    KaleidoscopeData *kd = NULL;
    int w,h,i,j,i_start,i_end,j_start,j_end;
    uint8_t temp;

    TC_MODULE_SELF_CHECK(self, "filer_video");
    TC_MODULE_SELF_CHECK(frame, "filer_video");

    kd = self->userdata;
    if (kd->start <= frame->id && frame->id <= kd->end && frame->id%kd->step == kd->boolstep) { /* in range */
        /* converting YUV->RGB */
        if (kd->codec==CODEC_YUV){
        	if (!tcv_convert(kd->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;
            }
        }

        w=frame->v_width;
        h=frame->v_height;

        /* first we set limit for i and j (coordinates of pixels) (what to copy) */
        /* defaults first */
        i_start = 0;
        i_end   = w/2;
        j_start = 0;
        j_end   = h/2;        
        if (kd->corner==KALEIDOSCOPE_TL){
            i_start = 0;
            i_end   = w/2;
            j_start = 0;
            j_end   = h/2;
        }else if (kd->corner==KALEIDOSCOPE_TR){
            i_start = w/2;
            i_end   = w;
            j_start = 0;
            j_end   = h/2;
        }else if (kd->corner==KALEIDOSCOPE_BL){
            i_start = 0;
            i_end   = w/2;
            j_start = h/2;
            j_end   = h;
        }else if (kd->corner==KALEIDOSCOPE_BR){
            i_start = w/2;
            i_end   = w;
            j_start = h/2;
            j_end   = h;
        }

        /* then we loop them storing value of pixel from one quadrant to other three */
        for(i=i_start;i<i_end;i++){
            for(j=j_start;j<j_end;j++){
                /* R */
                temp=frame->video_buf[3*w*j+3*i];
                frame->video_buf[3*w*j+3*(w-i-1)]           = temp;
                frame->video_buf[3*w*(h-j-1)+3*i]           = temp;
                frame->video_buf[3*w*(h-j-1)+3*(w-i-1)]     = temp;
                /* G */
                temp=frame->video_buf[3*w*j+3*i+1];
                frame->video_buf[3*w*j+3*(w-i-1)+1]         = temp;
                frame->video_buf[3*w*(h-j-1)+3*i+1]         = temp;
                frame->video_buf[3*w*(h-j-1)+3*(w-i-1)+1]   = temp;
                /* B */
                temp=frame->video_buf[3*w*j+3*i+2];
                frame->video_buf[3*w*j+3*(w-i-1)+2]         = temp;
                frame->video_buf[3*w*(h-j-1)+3*i+2]         = temp;
                frame->video_buf[3*w*(h-j-1)+3*(w-i-1)+2]   = temp;

            }
        }

        /* converting RGB->YUV */
        if (kd->codec==CODEC_YUV){
            if (!tcv_convert(kd->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;
	        }
        }
    } /* end if in range */
    return TC_OK;
}

/*************************************************************************/

static const TCCodecID kaleidoscope_codecs_in[] = { 
    TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR
};
static const TCCodecID kaleidoscope_codecs_out[] = {
    TC_CODEC_RGB, TC_CODEC_YUV420P, TC_CODEC_ERROR
};
static const TCFormatID kaleidoscope_formats[] = {
    TC_FORMAT_ERROR
};

static const TCModuleInfo kaleidoscope_info = {
    .features    = MOD_FEATURES,
    .flags       = MOD_FLAGS,
    .name        = MOD_NAME,
    .version     = MOD_VERSION,
    .description = MOD_CAP,
    .codecs_in   = kaleidoscope_codecs_in,
    .codecs_out  = kaleidoscope_codecs_out,
    .formats_in  = kaleidoscope_formats,
    .formats_out = kaleidoscope_formats
};

static const TCModuleClass kaleidoscope_class = {
    .info         = &kaleidoscope_info,

    .init         = kaleidoscope_init,
    .fini         = kaleidoscope_fini,
    .configure    = kaleidoscope_configure,
    .stop         = kaleidoscope_stop,
    .inspect      = kaleidoscope_inspect,

    .filter_video = kaleidoscope_filter_video
};

extern const TCModuleClass *tc_plugin_setup(void)
{
    return &kaleidoscope_class;
}

/*************************************************************************/

static int kaleidoscope_get_config(TCModuleInstance *self, char *options)
{
    KaleidoscopeData *kd = NULL;
    char b[TC_BUF_MIN];

    TC_MODULE_SELF_CHECK(self, "get_config");

    kd = self->userdata;

    optstr_filter_desc(options, MOD_NAME, MOD_CAP, MOD_VERSION, MOD_AUTHOR, "VRYME", "1");
    optstr_param (options, "help", "Kaleidoscops the frames", "",   "0");
    optstr_param(options,  "corner",  "Frame corner that gets kaleidoscoping (tl, tr, bl, br)",  "%s", "");
    tc_snprintf(b, TC_BUF_MIN, "%u-%u/%d", kd->start, kd->end, kd->step);
    optstr_param (options, "range", "apply filter to [start-end]/step frames",
        "%u-%u/%d", b, "0", "oo", "0", "oo", "1", "oo");

    return TC_OK;
}

static int kaleidoscope_process(TCModuleInstance *self, 
                            frame_list_t *frame)
{
    TC_MODULE_SELF_CHECK(self, "process");

    /* choose what to do by frame->tag */
    if ((frame->tag & TC_VIDEO) && !(frame->attributes & TC_FRAME_IS_SKIPPED)
        && (frame->tag & TC_PRE_M_PROCESS)) {
            return kaleidoscope_filter_video(self, (vframe_list_t*)frame);
    }
    return TC_OK;
}

/*************************************************************************/

/* Old-fashioned module interface. */

TC_FILTER_OLDINTERFACE(kaleidoscope)

/*************************************************************************/

/*
 * Local variables:
 *   c-file-style: "stroustrup"
 *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
 *   indent-tabs-mode: nil
 * End:
 *
 * vim: expandtab shiftwidth=4:
 */

Reply via email to