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: */