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