// cvlc --video-filter pulfrich // address@hidden /***************************************************************************** * Preamble *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #define _(str) (str) #define N_(str) (str) #include #include #include #include #include #include #include "filter_picture.h" #if 0 Yuv2Rgb( &r, &g, &b, src_y[(y * p_pic->Y_PITCH) + x], src_u[((y >> 1) * p_pic->U_PITCH) + (x >> 1)], src_v[((y >> 1) * p_pic->V_PITCH) + (x >> 1)]); rgb_to_yuv( &dst_y[(y * p_outpic->Y_PITCH) + x], &dst_u[((y >> 1) * p_outpic->U_PITCH) + (x >> 1)], &dst_v[((y >> 1) * p_outpic->V_PITCH) + (x >> 1)], rgb24_1[ywx3 + 0], rgb24_0[ywx3 + 1], rgb24_0[ywx3 + 2]); #endif #define NFRAME 2 #define RED_CYAN 1 #define GREEN_MAGENTA 2 #define MODE GREEN_MAGENTA #define USE_ARRAY #ifdef USE_ARRAY #define ARRAY16M ((256) * (256) * (256) * (3)) /* 16.777.216 * 3 = 50.331.648 :-) */ #endif /***************************************************************************** * Module descriptor *****************************************************************************/ static int Create ( vlc_object_t * ); static void Destroy ( vlc_object_t * ); vlc_module_begin () set_description( N_("Pulfrich video filter") ) set_shortname( N_( "Pulfrich" )) set_capability( "video filter2", 0 ) set_category( CAT_VIDEO ) set_subcategory( SUBCAT_VIDEO_VFILTER ) set_callbacks( Create, Destroy ) vlc_module_end () /***************************************************************************** * Local prototypes *****************************************************************************/ static picture_t *Filter( filter_t *, picture_t * ); #ifdef USE_ARRAY typedef struct { unsigned char r; unsigned char g; unsigned char b; } rgb_t; typedef struct { unsigned char y; unsigned char u; unsigned char v; } yuv_t; #endif /* */ struct filter_sys_t { image_handler_t *p_image; uint8_t *rx; uint8_t *lx; #ifdef USE_ARRAY yuv_t *rgb2yuv; rgb_t *yuv2rgb; #endif }; const char *codec_name(int codec) { static char unkn[80]; switch (codec) { case VLC_CODEC_I420: return "I420"; case VLC_CODEC_J420: return "J420"; case VLC_CODEC_YV12: return "YV12"; case VLC_CODEC_I411: return "I411"; case VLC_CODEC_I410: return "I410"; case VLC_CODEC_I444: return "I444"; case VLC_CODEC_J444: return "J444"; case VLC_CODEC_YUVA: return "YUVA"; case VLC_CODEC_I422: return "I422"; case VLC_CODEC_J422: return "J422"; default: sprintf(unkn, "UNKNOWN %d/0x%x", codec, codec); } return unkn; } #define SCALEBITS 10 #define ONE_HALF (1 << (SCALEBITS - 1)) #define FIX(x) ((int) ((x) * (1< 255 ) return 255; else if( v < 0 ) return 0; return v; } #ifdef USE_ARRAY static inline void do_yuv2rgb(int y1, int u1, int v1, rgb_t *rgb) { int y0, cb, cr, r_add, g_add, b_add; cb = u1 - 128; cr = v1 - 128; r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF; g_add = - FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr + ONE_HALF; b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF; // x, y y0 = (y1 - 16) * FIX(255.0/219.0); rgb->r = vlc_uint8( (y0 + r_add) >> SCALEBITS ); rgb->g = vlc_uint8( (y0 + g_add) >> SCALEBITS ); rgb->b = vlc_uint8( (y0 + b_add) >> SCALEBITS ); } static inline void do_rgb2yuv(int r, int g, int b, yuv_t *yuv) { yuv->y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 ); yuv->u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128; yuv->v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128; } #endif #define RGB2INDEX(r,g,b) ((((r) & 255) << 16) | (((g) & 255) << 8) | ((b) & 255)) #define YUV2INDEX(y,u,v) ((((y) & 255) << 16) | (((u) & 255) << 8) | ((v) & 255)) /***************************************************************************** * Create: *****************************************************************************/ static int Create( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; int w, h; /* */ fprintf(stderr, "codec: %s\n", codec_name(p_filter->fmt_in.i_codec)); switch( p_filter->fmt_in.i_codec ) { CASE_PLANAR_YUV // case VLC_CODEC_GREY: break; default: msg_Err( p_filter, "Unsupported chroma" ); return VLC_EGENERIC; } if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) ) { msg_Err( p_filter, "Input and output format does not match" ); return VLC_EGENERIC; } /* Allocate structure */ p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) ); if( !p_filter->p_sys ) return VLC_ENOMEM; #ifdef USE_ARRAY p_sys->rgb2yuv = NULL; p_sys->yuv2rgb = NULL; fprintf(stderr,"16M = %lu\n", ARRAY16M); fprintf(stderr,"sizeof(yuv_t) = %lu\n", sizeof(yuv_t)); fprintf(stderr,"sizeof(rgb_t) = %lu\n", sizeof(rgb_t)); p_sys->rgb2yuv = malloc(ARRAY16M); if (p_sys->rgb2yuv == NULL) { msg_Err( p_filter, "can't alloc rgb2yuv array" ); return VLC_ENOMEM; } fprintf(stderr,"allocated rgb2yuv\n"); { int r, g, b; void *yuv = p_sys->rgb2yuv; void *beg, *end; beg = yuv; end = beg + ARRAY16M; fprintf(stderr,"beg %p end %p %lu\n", beg, end, end - beg); for (r=0; r<256; r++) { for (g=0; g<256; g++) { for (b=0; b<256; b++) { yuv = beg + 3 * RGB2INDEX(r,g,b); if (yuv >= beg && yuv <= end) { do_rgb2yuv(r, g, b, yuv); } else { fprintf(stderr,"%x %d %d %d yuv %p\n", RGB2INDEX(r,g,b), r,g,b, yuv); goto exit2; } //yuv += 3; } } } exit2: ; } p_sys->yuv2rgb = malloc(ARRAY16M); if (p_sys->yuv2rgb == NULL) { msg_Err( p_filter, "can't alloc yuv2rgb array" ); return VLC_ENOMEM; } fprintf(stderr,"allocated yuv2rgb\n"); { int y, u, v; void *rgb = p_sys->yuv2rgb; void *beg, *end; beg = rgb; end = beg + ARRAY16M; fprintf(stderr,"beg %p end %p %lu\n", beg, end, end - beg); for (y=0; y<256; y++) { for (u=0; u<256; u++) { for (v=0; v<256; v++) { rgb = beg + 3 * YUV2INDEX(y,u,v); if (rgb >= beg && rgb <= end) { do_yuv2rgb(y, u, v, rgb); } else { fprintf(stderr,"%x %d %d %d yuv %p\n", YUV2INDEX(y,u,v), y,u,v, rgb); goto exit1; } //rgb += 3; } } } exit1: ; } #endif p_sys->p_image = image_HandlerCreate( p_filter ); if( !p_sys->p_image ) { free( p_sys ); return VLC_EGENERIC; } w = p_filter->fmt_in.video.i_width; h = p_filter->fmt_in.video.i_height; fprintf(stderr,"width: %d\n", w); fprintf(stderr,"height: %d\n", h); p_sys->lx = malloc ((w * h) * NFRAME); p_sys->rx = malloc (w * h * 2); /* */ p_filter->pf_video_filter = Filter; return VLC_SUCCESS; } /***************************************************************************** * Destroy: *****************************************************************************/ static void Destroy( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys = p_filter->p_sys; image_HandlerDelete( p_sys->p_image ); if (p_sys->lx) free( p_sys->lx ); if (p_sys->rx) free( p_sys->rx ); #ifdef USE_ARRAY if (p_sys->rgb2yuv) free(p_sys->rgb2yuv); if (p_sys->yuv2rgb) free(p_sys->yuv2rgb); #endif free( p_sys ); } static inline void chan2rgb( uint8_t c1, uint8_t c2, uint8_t c3, uint8_t *r, uint8_t *g, uint8_t *b) { #if MODE == RED_CYAN *r = c1; *g = c2; *b = c3; #elif MODE == GREEN_MAGENTA *r = c2; *g = c1; *b = c3; #else #error "unknown MODE defined" #endif } /***************************************************************************** * Render: displays previously rendered output *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_outpic; uint8_t *lx = p_sys->lx, *rx = p_sys->rx; int x, y, w, h, wh, wh_frame; uint8_t *src_y, *src_u, *src_v; uint8_t *dst_y, *dst_u, *dst_v; uint8_t r, g, b; int lxoff, rxoff; int yw, yw_1, w2, yw2, yw2_1; #ifndef USE_ARRAY int y0, cb, cr, r_add, g_add, b_add; #else rgb_t *rgb; yuv_t *yuv; #endif uint8_t y2, u2, v2; int y1, u1, v1; uint8_t c1, c2, c3; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic || !lx || !rx) { picture_Release( p_pic ); return NULL; } src_y = &p_pic->Y_PIXELS[0]; src_u = &p_pic->U_PIXELS[0]; src_v = &p_pic->V_PIXELS[0]; dst_y = &p_outpic->Y_PIXELS[0]; dst_u = &p_outpic->U_PIXELS[0]; dst_v = &p_outpic->V_PIXELS[0]; lxoff = 2; rxoff = 2; w = p_filter->fmt_in.video.i_width; h = p_filter->fmt_in.video.i_height; wh = w * h; wh_frame = wh * (NFRAME-1); w2 = w * 2; for (y = 0; y < h; y += 2) { yw = y * w; yw_1 = (y + 1) * w; yw2 = y * w2; yw2_1 = (y + 1) * w2; for (x = 0; x < w; x += 2) { y1 = src_y[(y * p_pic->Y_PITCH) + x]; u1 = src_u[((y >> 1) * p_pic->U_PITCH) + (x >> 1)]; v1 = src_v[((y >> 1) * p_pic->V_PITCH) + (x >> 1)]; #ifndef USE_ARRAY cb = u1 - 128; cr = v1 - 128; r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF; g_add = - FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr + ONE_HALF; b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF; #endif // x, y #ifndef USE_ARRAY y0 = (y1 - 16) * FIX(255.0/219.0); c1 = vlc_uint8( (y0 + r_add) >> SCALEBITS ); c2 = vlc_uint8( (y0 + g_add) >> SCALEBITS ); c3 = vlc_uint8( (y0 + b_add) >> SCALEBITS ); #else #if 1 rgb = &p_sys->yuv2rgb[YUV2INDEX(y1,u1,v1)]; c1 = rgb->r; c2 = rgb->g; c3 = rgb->b; #endif #endif chan2rgb(c1, c2, c3, &r, &g, &b); if (x > lxoff) { lx[wh_frame + (yw + (x - lxoff))] = r; } if (x + rxoff < w) { rx[yw2 + ((x + rxoff) * 2) + 0] = g; rx[yw2 + ((x + rxoff) * 2) + 1] = b; } // x + 1, y y1 = src_y[(y * p_pic->Y_PITCH) + x + 1]; #ifndef USE_ARRAY y0 = (y1 - 16) * FIX(255.0/219.0); c1 = vlc_uint8( (y0 + r_add) >> SCALEBITS ); c2 = vlc_uint8( (y0 + g_add) >> SCALEBITS ); c3 = vlc_uint8( (y0 + b_add) >> SCALEBITS ); #else #if 1 rgb = &p_sys->yuv2rgb[YUV2INDEX(y1,u1,v1)]; c1 = rgb->r; c2 = rgb->g; c3 = rgb->b; #endif #endif chan2rgb(c1, c2, c3, &r, &g, &b); if (x > lxoff && x + 1 < w) { lx[wh_frame + (yw + ((x + 1) - lxoff))] = r; } if (x + 1 + rxoff < w) { rx[yw2 + (((x + 1) + rxoff) * 2) + 0] = g; rx[yw2 + (((x + 1) + rxoff) * 2) + 1] = b; } // x, y + 1 y1 = src_y[((y + 1) * p_pic->Y_PITCH) + x]; #ifndef USE_ARRAY y0 = (y1 - 16) * FIX(255.0/219.0); c1 = vlc_uint8( (y0 + r_add) >> SCALEBITS ); c2 = vlc_uint8( (y0 + g_add) >> SCALEBITS ); c3 = vlc_uint8( (y0 + b_add) >> SCALEBITS ); #else #if 1 rgb = &p_sys->yuv2rgb[YUV2INDEX(y1,u1,v1)]; c1 = rgb->r; c2 = rgb->g; c3 = rgb->b; #endif #endif chan2rgb(c1, c2, c3, &r, &g, &b); if (x > lxoff) { lx[wh_frame + (yw_1 + (x - lxoff))] = r; } if (x + rxoff < w) { rx[yw2_1 + ((x + rxoff) * 2) + 0] = g; rx[yw2_1 + ((x + rxoff) * 2) + 1] = b; } // x + 1, y + 1 y1 = src_y[((y + 1) * p_pic->Y_PITCH) + x + 1]; #ifndef USE_ARRAY y0 = (y1 - 16) * FIX(255.0/219.0); c1 = vlc_uint8( (y0 + r_add) >> SCALEBITS ); c2 = vlc_uint8( (y0 + g_add) >> SCALEBITS ); c3 = vlc_uint8( (y0 + b_add) >> SCALEBITS ); #else #if 1 rgb = &p_sys->yuv2rgb[YUV2INDEX(y1,u1,v1)]; c1 = rgb->r; c2 = rgb->g; c3 = rgb->b; #endif #endif chan2rgb(c1, c2, c3, &r, &g, &b); if (x > lxoff) { lx[wh_frame + (yw_1 + ((x + 1) - lxoff))] = r; } if (x + 1 + rxoff < w) { rx[yw2_1 + (((x + 1) + rxoff) * 2) + 0] = g; rx[yw2_1 + (((x + 1) + rxoff) * 2) + 1] = b; } } } for (y = 0; y < h; y += 1) { yw = y * w; yw2 = y * w2; for (x = 0; x < w; x += 1) { c1 = lx[yw + x]; c2 = rx[yw2 + (x * 2) + 0]; c3 = rx[yw2 + (x * 2) + 1]; chan2rgb(c1, c2, c3, &r, &g, &b); #ifndef USE_ARRAY y2 = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 ); #else #if 1 yuv = &p_sys->rgb2yuv[RGB2INDEX(r,g,b)]; y2 = yuv->y; #endif #endif dst_y[(y * p_outpic->Y_PITCH) + x] = y2; if ((x & 1) == 0 && (y & 1) == 0) { #ifndef USE_ARRAY u2 = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128; v2 = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128; #else #if 1 u2 = yuv->u; v2 = yuv->v; #endif #endif dst_u[((y >> 1) * p_outpic->U_PITCH) + (x >> 1)] = u2; dst_v[((y >> 1) * p_outpic->V_PITCH) + (x >> 1)] = v2; } } } #if NFRAME > 1 // shift frames for (y = 0; y < NFRAME-1; y++ ) vlc_memcpy (&lx[y * wh], &lx[(y + 1) * wh], wh); #endif return CopyInfoAndRelease( p_outpic, p_pic ); } #undef FIX