diff --git a/vhook/watermark.c b/vhook/watermark.c index f61f3a1242..cf89e60994 100644 --- a/vhook/watermark.c +++ b/vhook/watermark.c @@ -2,6 +2,12 @@ * Watermark Hook * Copyright (c) 2005 Marcus Engene myfirstname(at)mylastname.se * + * flags to watermark: + * -m nbr = nbr is 0..1. 0 is the default mode, see below. + * -t nbr = nbr is six digit hex. Threshold. + * -f file = File is the filename of watermark image. You must specify this! + * + * MODE 0: * The watermarkpicture works like this. (Assuming colorintencities 0..0xff) * Per color do this: * If mask color is 0x80, no change to original frame. @@ -10,14 +16,22 @@ * If mask color is > 0x80 the abs difference is added to frame. If result * > 0xff, result = 0xff * + * You can override the 0x80 level with the -t flag. Eg if threshold is 000000 + * the color values of watermark is added to destination. + * * This way a mask that is visible both in light pictures and in dark can be * made (fex by using a picture generated by gimp and the bump map tool). * * An example watermark file is at * http://engene.se/ffmpeg_watermark.gif * + * MODE 1: + * Per color do this: + * If mask color > threshold color, watermark pixel is going to be used. + * * Example usage: - * ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif' out.mov + * ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif' -an out.mov + * ffmpeg -i infile -vhook '/path/watermark.so -f wm.gif -m 1 -t 222222' -an out.mov * * Note that the entire vhook argument is encapsulated in ''. This * way, arguments to the vhook won't be mixed up with those to ffmpeg. @@ -37,7 +51,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -//#include +#include //#include #include #include @@ -69,6 +83,10 @@ typedef struct { AVStream *st; int is_done; AVFrame *pFrameRGB; + int thrR; + int thrG; + int thrB; + int mode; } ContextInfo; int get_watermark_picture(ContextInfo *ci, int cleanup); @@ -96,6 +114,7 @@ int Configure(void **ctxp, int argc, char *argv[]) { ContextInfo *ci; int c; + int tmp = 0; if (0 == (*ctxp = av_mallocz(sizeof(ContextInfo)))) return -1; ci = (ContextInfo *) *ctxp; @@ -103,13 +122,28 @@ int Configure(void **ctxp, int argc, char *argv[]) optind = 1; // Struct is mallocz:ed so no need to reset. + ci->thrR = 0x80; + ci->thrG = 0x80; + ci->thrB = 0x80; - while ((c = getopt(argc, argv, "f:")) > 0) { + while ((c = getopt(argc, argv, "f:m:t:")) > 0) { switch (c) { case 'f': strncpy(ci->filename, optarg, 1999); ci->filename[1999] = 0; break; + case 'm': + ci->mode = atoi(optarg); + break; + case 't': + if (1 != sscanf(optarg, "%x", &tmp)) { + av_log(NULL, AV_LOG_ERROR, "Watermark: argument to -t must be a 6 digit hex number\n"); + return -1; + } + ci->thrR = (tmp >> 16) & 0xff; + ci->thrG = (tmp >> 8) & 0xff; + ci->thrB = (tmp >> 0) & 0xff; + break; default: av_log(NULL, AV_LOG_ERROR, "Watermark: Unrecognized argument '%s'\n", argv[optind]); return -1; @@ -128,14 +162,14 @@ int Configure(void **ctxp, int argc, char *argv[]) /**************************************************************************** - * Why is this a void returning functions? I want to be able to go wrong! + * For mode 0 (the original one) ****************************************************************************/ -void Process(void *ctx, - AVPicture *picture, - enum PixelFormat pix_fmt, - int src_width, - int src_height, - int64_t pts) +void Process0(void *ctx, + AVPicture *picture, + enum PixelFormat pix_fmt, + int src_width, + int src_height, + int64_t pts) { ContextInfo *ci = (ContextInfo *) ctx; char *buf = 0; @@ -146,7 +180,6 @@ void Process(void *ctx, int xm_size; int ym_size; -// int retval = -1; int x; int y; int offs, offsm; @@ -156,9 +189,9 @@ void Process(void *ctx, uint32_t pixel; uint32_t pixelm; int tmp; - - -//?? (void) ci; + int thrR = ci->thrR; + int thrG = ci->thrG; + int thrB = ci->thrB; if (pix_fmt != PIX_FMT_RGBA32) { int size; @@ -201,17 +234,17 @@ void Process(void *ctx, pixel_meck = pixel & 0xff000000; // R - tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - 0x80; + tmp = (int)((pixel >> 16) & 0xff) + (int)((pixelm >> 16) & 0xff) - thrR; if (tmp > 255) tmp = 255; if (tmp < 0) tmp = 0; pixel_meck |= (tmp << 16) & 0xff0000; // G - tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - 0x80; + tmp = (int)((pixel >> 8) & 0xff) + (int)((pixelm >> 8) & 0xff) - thrG; if (tmp > 255) tmp = 255; if (tmp < 0) tmp = 0; pixel_meck |= (tmp << 8) & 0xff00; // B - tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - 0x80; + tmp = (int)((pixel >> 0) & 0xff) + (int)((pixelm >> 0) & 0xff) - thrB; if (tmp > 255) tmp = 255; if (tmp < 0) tmp = 0; pixel_meck |= (tmp << 0) & 0xff; @@ -240,6 +273,112 @@ void Process(void *ctx, } +/**************************************************************************** + * For mode 1 (the original one) + ****************************************************************************/ +void Process1(void *ctx, + AVPicture *picture, + enum PixelFormat pix_fmt, + int src_width, + int src_height, + int64_t pts) +{ + ContextInfo *ci = (ContextInfo *) ctx; + char *buf = 0; + AVPicture picture1; + AVPicture *pict = picture; + + AVFrame *pFrameRGB; + int xm_size; + int ym_size; + + int x; + int y; + int offs, offsm; + int mpoffs; + uint32_t *p_pixel = 0; + uint32_t pixel; + uint32_t pixelm; + + if (pix_fmt != PIX_FMT_RGBA32) { + int size; + + size = avpicture_get_size(PIX_FMT_RGBA32, src_width, src_height); + buf = av_malloc(size); + + avpicture_fill(&picture1, buf, PIX_FMT_RGBA32, src_width, src_height); + if (img_convert(&picture1, PIX_FMT_RGBA32, + picture, pix_fmt, src_width, src_height) < 0) { + av_free(buf); + return; + } + pict = &picture1; + } + + /* Insert filter code here */ /* ok */ + + // Get me next frame + if (0 > get_watermark_picture(ci, 0)) { + return; + } + // These are the three original static variables in the ffmpeg hack. + pFrameRGB = ci->pFrameRGB; + xm_size = ci->x_size; + ym_size = ci->y_size; + + // I'll do the *4 => <<2 crap later. Most compilers understand that anyway. + // According to avcodec.h PIX_FMT_RGBA32 is handled in endian specific manner. + for (y=0; ydata[0])[mpoffs]); + pixelm = *p_pixel; /* watermark pixel */ + p_pixel = (uint32_t *)&((pict->data[0])[offs]); + pixel = *p_pixel; + + if (((pixelm >> 16) & 0xff) > ci->thrR || + ((pixelm >> 8) & 0xff) > ci->thrG || + ((pixelm >> 0) & 0xff) > ci->thrB) + { + *p_pixel = pixelm; + } else { + *p_pixel = pixel; + } + offs += 4; + } // foreach X + } // foreach Y + + if (pix_fmt != PIX_FMT_RGBA32) { + if (img_convert(picture, pix_fmt, + &picture1, PIX_FMT_RGBA32, src_width, src_height) < 0) { + } + } + + av_free(buf); +} + + +/**************************************************************************** + * This is the function ffmpeg.c callbacks. + ****************************************************************************/ +void Process(void *ctx, + AVPicture *picture, + enum PixelFormat pix_fmt, + int src_width, + int src_height, + int64_t pts) +{ + ContextInfo *ci = (ContextInfo *) ctx; + if (1 == ci->mode) { + return Process1(ctx, picture, pix_fmt, src_width, src_height, pts); + } else { + return Process0(ctx, picture, pix_fmt, src_width, src_height, pts); + } +} + + /**************************************************************************** * When cleanup == 0, we try to get the next frame. If no next frame, nothing * is done.