Update of /cvsroot/deinterlace/DScaler5/ffmpeg/vhook
In directory sc8-pr-cvs12.sourceforge.net:/tmp/cvs-serv8413/vhook
Added Files:
.cvsignore drawtext.c fish.c imlib2.c null.c ppm.c watermark.c
Log Message:
Added latest ffmpeg files
--- NEW FILE ---
*.o
*.exe
*.dll
--- NEW FILE ---
/*
* drawtext.c: print text over the screen
******************************************************************************
* Options:
* -f <filename> font filename (MANDATORY!!!)
* -s <pixel_size> font size in pixels [default 16]
* -b print background
* -o outline glyphs (use the bg color)
* -x <pos> x position ( >= 0) [default 0]
* -y <pos> y position ( >= 0) [default 0]
* -t <text> text to print (will be passed to strftime())
* MANDATORY: will be used even when -T is used.
* in this case, -t will be used if some error
* occurs
* -T <filename> file with the text (re-read every frame)
* -c <#RRGGBB> foreground color ('internet' way) [default #ffffff]
* -C <#RRGGBB> background color ('internet' way) [default #000000]
*
******************************************************************************
* Features:
* - True Type, Type1 and others via FreeType2 library
* - Font kerning (better output)
* - Line Wrap (if the text doesn't fit, the next char go to the next line)
* - Background box
* - Outline
******************************************************************************
* Author: Gustavo Sverzut Barbieri <gsb...@ya...>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define MAXSIZE_TEXT 1024
#include "framehook.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#undef time
#include <sys/time.h>
#include <time.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#define SCALEBITS 10
#define ONE_HALF (1 << (SCALEBITS - 1))
#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
#define RGB_TO_YUV(rgb_color, yuv_color) do { \
yuv_color[0] = (FIX(0.29900) * rgb_color[0] + FIX(0.58700) * rgb_color[1] + FIX(0.11400) * rgb_color[2] + ONE_HALF) >> SCALEBITS; \
yuv_color[2] = ((FIX(0.50000) * rgb_color[0] - FIX(0.41869) * rgb_color[1] - FIX(0.08131) * rgb_color[2] + ONE_HALF - 1) >> SCALEBITS) + 128; \
yuv_color[1] = ((- FIX(0.16874) * rgb_color[0] - FIX(0.33126) * rgb_color[1] + FIX(0.50000) * rgb_color[2] + ONE_HALF - 1) >> SCALEBITS) + 128; \
} while (0)
#define COPY_3(dst,src) { \
dst[0]=src[0]; \
dst[1]=src[1]; \
dst[2]=src[2]; \
}
#define SET_PIXEL(picture, yuv_color, x, y) { \
picture->data[0][ (x) + (y)*picture->linesize[0] ] = yuv_color[0]; \
picture->data[1][ ((x/2) + (y/2)*picture->linesize[1]) ] = yuv_color[1]; \
picture->data[2][ ((x/2) + (y/2)*picture->linesize[2]) ] = yuv_color[2]; \
}
#define GET_PIXEL(picture, yuv_color, x, y) { \
yuv_color[0] = picture->data[0][ (x) + (y)*picture->linesize[0] ]; \
yuv_color[1] = picture->data[1][ (x/2) + (y/2)*picture->linesize[1] ]; \
yuv_color[2] = picture->data[2][ (x/2) + (y/2)*picture->linesize[2] ]; \
}
typedef struct {
unsigned char *text;
char *file;
unsigned int x;
unsigned int y;
int bg;
int outline;
unsigned char bgcolor[3]; /* YUV */
unsigned char fgcolor[3]; /* YUV */
FT_Library library;
FT_Face face;
FT_Glyph glyphs[ 255 ];
FT_Bitmap bitmaps[ 255 ];
int advance[ 255 ];
int bitmap_left[ 255 ];
int bitmap_top[ 255 ];
unsigned int glyphs_index[ 255 ];
int text_height;
int baseline;
int use_kerning;
} ContextInfo;
void Release(void *ctx)
{
if (ctx)
av_free(ctx);
}
static int ParseColor(char *text, unsigned char yuv_color[3])
{
char tmp[3];
unsigned char rgb_color[3];
int i;
tmp[2] = '\0';
if ((!text) || (strlen(text) != 7) || (text[0] != '#') )
return -1;
for (i=0; i < 3; i++)
{
tmp[0] = text[i*2+1];
tmp[1] = text[i*2+2];
rgb_color[i] = strtol(tmp, NULL, 16);
}
RGB_TO_YUV(rgb_color, yuv_color);
return 0;
}
int Configure(void **ctxp, int argc, char *argv[])
{
int c;
int error;
ContextInfo *ci=NULL;
char *font=NULL;
unsigned int size=16;
FT_BBox bbox;
int yMax, yMin;
*ctxp = av_mallocz(sizeof(ContextInfo));
ci = (ContextInfo *) *ctxp;
/* configure Context Info */
ci->text = NULL;
ci->file = NULL;
ci->x = ci->y = 0;
ci->fgcolor[0]=255;
ci->fgcolor[1]=128;
ci->fgcolor[2]=128;
ci->bgcolor[0]=0;
ci->fgcolor[1]=128;
ci->fgcolor[2]=128;
ci->bg = 0;
ci->outline = 0;
ci->text_height = 0;
optind = 0;
while ((c = getopt(argc, argv, "f:t:T:x:y:s:c:C:bo")) > 0) {
switch (c) {
case 'f':
font = optarg;
break;
case 't':
ci->text = av_strdup(optarg);
break;
case 'T':
ci->file = av_strdup(optarg);
break;
case 'x':
ci->x = (unsigned int) atoi(optarg);
break;
case 'y':
ci->y = (unsigned int) atoi(optarg);
break;
case 's':
size = (unsigned int) atoi(optarg);
break;
case 'c':
if (ParseColor(optarg, ci->fgcolor) == -1)
{
av_log(NULL, AV_LOG_ERROR, "Invalid foreground color: '%s'. You must specify the color in the internet way(packaged hex): #RRGGBB, ie: -c #ffffff (for white foreground)\n", optarg);
return -1;
}
break;
case 'C':
if (ParseColor(optarg, ci->bgcolor) == -1)
{
av_log(NULL, AV_LOG_ERROR, "Invalid background color: '%s'. You must specify the color in the internet way(packaged hex): #RRGGBB, ie: -C #ffffff (for white background)\n", optarg);
return -1;
}
break;
case 'b':
ci->bg=1;
break;
case 'o':
ci->outline=1;
break;
case '?':
av_log(NULL, AV_LOG_ERROR, "Unrecognized argument '%s'\n", argv[optind]);
return -1;
}
}
if (!ci->text)
{
av_log(NULL, AV_LOG_ERROR, "No text provided (-t text)\n");
return -1;
}
if (ci->file)
{
FILE *fp;
if ((fp=fopen(ci->file, "r")) == NULL)
{
av_log(NULL, AV_LOG_INFO, "WARNING: The file could not be opened. Using text provided with -t switch: %s", strerror(errno));
}
else
{
fclose(fp);
}
}
if (!font)
{
av_log(NULL, AV_LOG_ERROR, "No font file provided! (-f filename)\n");
return -1;
}
if ((error = FT_Init_FreeType(&(ci->library))) != 0)
{
av_log(NULL, AV_LOG_ERROR, "Could not load FreeType (error# %d).\n", error);
return -1;
}
if ((error = FT_New_Face( ci->library, font, 0, &(ci->face) )) != 0)
{
av_log(NULL, AV_LOG_ERROR, "Could not load face: %s (error# %d).\n", font, error);
return -1;
}
if ((error = FT_Set_Pixel_Sizes( ci->face, 0, size)) != 0)
{
av_log(NULL, AV_LOG_ERROR, "Could not set font size to %d pixels (error# %d).\n", size, error);
return -1;
}
ci->use_kerning = FT_HAS_KERNING(ci->face);
/* load and cache glyphs */
yMax = -32000;
yMin = 32000;
for (c=0; c < 256; c++)
{
/* Load char */
error = FT_Load_Char( ci->face, (unsigned char) c, FT_LOAD_RENDER | FT_LOAD_MONOCHROME );
if (error) continue; /* ignore errors */
/* Save bitmap */
ci->bitmaps[c] = ci->face->glyph->bitmap;
/* Save bitmap left */
ci->bitmap_left[c] = ci->face->glyph->bitmap_left;
/* Save bitmap top */
ci->bitmap_top[c] = ci->face->glyph->bitmap_top;
/* Save advance */
ci->advance[c] = ci->face->glyph->advance.x >> 6;
/* Save glyph */
error = FT_Get_Glyph( ci->face->glyph, &(ci->glyphs[c]) );
/* Save glyph index */
ci->glyphs_index[c] = FT_Get_Char_Index( ci->face, (unsigned char) c );
/* Measure text height to calculate text_height (or the maximum text height) */
FT_Glyph_Get_CBox( ci->glyphs[ c ], ft_glyph_bbox_pixels, &bbox );
if (bbox.yMax > yMax)
yMax = bbox.yMax;
if (bbox.yMin < yMin)
yMin = bbox.yMin;
}
ci->text_height = yMax - yMin;
ci->baseline = yMax;
return 0;
}
static inline void draw_glyph(AVPicture *picture, FT_Bitmap *bitmap, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned char yuv_fgcolor[3], unsigned char yuv_bgcolor[3], int outline)
{
int r, c;
int spixel, dpixel[3], in_glyph=0;
if (bitmap->pixel_mode == ft_pixel_mode_mono)
{
in_glyph = 0;
for (r=0; (r < bitmap->rows) && (r+y < height); r++)
{
for (c=0; (c < bitmap->width) && (c+x < width); c++)
{
/* pixel in the picture (destination) */
GET_PIXEL(picture, dpixel, (c+x), (y+r));
/* pixel in the glyph bitmap (source) */
spixel = bitmap->buffer[r*bitmap->pitch +c/8] & (0x80>>(c%8));
if (spixel)
COPY_3(dpixel, yuv_fgcolor);
if (outline)
{
/* border detection: */
if ( (!in_glyph) && (spixel) )
/* left border detected */
{
in_glyph = 1;
/* draw left pixel border */
if (c-1 >= 0)
SET_PIXEL(picture, yuv_bgcolor, (c+x-1), (y+r));
}
else if ( (in_glyph) && (!spixel) )
/* right border detected */
{
in_glyph = 0;
/* 'draw' right pixel border */
COPY_3(dpixel, yuv_bgcolor);
}
if (in_glyph)
/* see if we have a top/bottom border */
{
/* top */
if ( (r-1 >= 0) && (! bitmap->buffer[(r-1)*bitmap->pitch +c/8] & (0x80>>(c%8))) )
/* we have a top border */
SET_PIXEL(picture, yuv_bgcolor, (c+x), (y+r-1));
/* bottom */
if ( (r+1 < height) && (! bitmap->buffer[(r+1)*bitmap->pitch +c/8] & (0x80>>(c%8))) )
/* we have a bottom border */
SET_PIXEL(picture, yuv_bgcolor, (c+x), (y+r+1));
}
}
SET_PIXEL(picture, dpixel, (c+x), (y+r));
}
}
}
}
static inline void draw_box(AVPicture *picture, unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned char yuv_color[3])
{
int i, j;
for (j = 0; (j < height); j++)
for (i = 0; (i < width); i++)
{
SET_PIXEL(picture, yuv_color, (i+x), (y+j));
}
}
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
ContextInfo *ci = (ContextInfo *) ctx;
FT_Face face = ci->face;
FT_GlyphSlot slot = face->glyph;
unsigned char *text = ci->text;
unsigned char c;
int x = 0, y = 0, i=0, size=0;
unsigned char buff[MAXSIZE_TEXT];
unsigned char tbuff[MAXSIZE_TEXT];
time_t now = time(0);
int str_w, str_w_max;
FT_Vector pos[MAXSIZE_TEXT];
FT_Vector delta;
if (ci->file)
{
int fd = open(ci->file, O_RDONLY);
if (fd < 0)
{
text = ci->text;
av_log(NULL, AV_LOG_INFO, "WARNING: The file could not be opened. Using text provided with -t switch: %s", strerror(errno));
}
else
{
int l = read(fd, tbuff, sizeof(tbuff) - 1);
if (l >= 0)
{
tbuff[l] = 0;
text = tbuff;
}
else
{
text = ci->text;
av_log(NULL, AV_LOG_INFO, "WARNING: The file could not be read. Using text provided with -t switch: %s", strerror(errno));
}
close(fd);
}
}
else
{
text = ci->text;
}
strftime(buff, sizeof(buff), text, localtime(&now));
text = buff;
size = strlen(text);
/* measure string size and save glyphs position*/
str_w = str_w_max = 0;
x = ci->x;
y = ci->y;
for (i=0; i < size; i++)
{
c = text[i];
/* kerning */
if ( (ci->use_kerning) && (i > 0) && (ci->glyphs_index[c]) )
{
FT_Get_Kerning( ci->face,
ci->glyphs_index[ text[i-1] ],
ci->glyphs_index[c],
ft_kerning_default,
&delta );
x += delta.x >> 6;
}
if (( (x + ci->advance[ c ]) >= width ) || ( c == '\n' ))
{
str_w = width - ci->x - 1;
y += ci->text_height;
x = ci->x;
}
/* save position */
pos[i].x = x + ci->bitmap_left[c];
pos[i].y = y - ci->bitmap_top[c] + ci->baseline;
x += ci->advance[c];
if (str_w > str_w_max)
str_w_max = str_w;
}
if (ci->bg)
{
/* Check if it doesn't pass the limits */
if ( str_w_max + ci->x >= width )
str_w_max = width - ci->x - 1;
if ( y >= height )
y = height - 1 - 2*ci->y;
/* Draw Background */
draw_box( picture, ci->x, ci->y, str_w_max, y - ci->y, ci->bgcolor );
}
/* Draw Glyphs */
for (i=0; i < size; i++)
{
c = text[i];
if (
( (c == '_') && (text == ci->text) ) || /* skip '_' (consider as space)
IF text was specified in cmd line
(which doesn't like neasted quotes) */
( c == '\n' ) /* Skip new line char, just go to new line */
)
continue;
/* now, draw to our target surface */
draw_glyph( picture,
&(ci->bitmaps[ c ]),
pos[i].x,
pos[i].y,
width,
height,
ci->fgcolor,
ci->bgcolor,
ci->outline );
/* increment pen position */
x += slot->advance.x >> 6;
}
}
--- NEW FILE ---
/*
* Fish Detector Hook
* Copyright (c) 2002 Philip Gladstone
*
* This file implements a fish detector. It is used to see when a
* goldfish passes in front of the camera. It does this by counting
* the number of input pixels that fall within a particular HSV
* range.
*
* It takes a multitude of arguments:
*
* -h <num>-<num> the range of H values that are fish
* -s <num>-<num> the range of S values that are fish
* -v <num>-<num> the range of V values that are fish
* -z zap all non-fish values to black
* -l <num> limit the number of saved files to <num>
* -i <num> only check frames every <num> seconds
* -t <num> the threshold for the amount of fish pixels (range 0-1)
* -d turn debugging on
* -D <directory> where to put the fish images
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <dirent.h>
#include "framehook.h"
#include "dsputil.h"
#include "avformat.h"
#include "swscale.h"
static int sws_flags = SWS_BICUBIC;
#define SCALEBITS 10
#define ONE_HALF (1 << (SCALEBITS - 1))
#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
#define YUV_TO_RGB1_CCIR(cb1, cr1)\
{\
cb = (cb1) - 128;\
cr = (cr1) - 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;\
}
#define YUV_TO_RGB2_CCIR(r, g, b, y1)\
{\
yt = ((y1) - 16) * FIX(255.0/219.0);\
r = cm[(yt + r_add) >> SCALEBITS];\
g = cm[(yt + g_add) >> SCALEBITS];\
b = cm[(yt + b_add) >> SCALEBITS];\
}
typedef struct {
int h; /* 0 .. 360 */
int s; /* 0 .. 255 */
int v; /* 0 .. 255 */
} HSV;
typedef struct {
int zapping;
int threshold;
HSV dark, bright;
char *dir;
int file_limit;
int debug;
int min_interval;
int64_t next_pts;
int inset;
int min_width;
struct SwsContext *toRGB_convert_ctx;
} ContextInfo;
static void dorange(const char *s, int *first, int *second, int maxval)
{
sscanf(s, "%d-%d", first, second);
if (*first > maxval)
*first = maxval;
if (*second > maxval)
*second = maxval;
}
void Release(void *ctx)
{
ContextInfo *ci;
ci = (ContextInfo *) ctx;
if (ctx) {
sws_freeContext(ci->toRGB_convert_ctx);
av_free(ctx);
}
}
int Configure(void **ctxp, int argc, char *argv[])
{
ContextInfo *ci;
int c;
*ctxp = av_mallocz(sizeof(ContextInfo));
ci = (ContextInfo *) *ctxp;
optind = 0;
ci->dir = "/tmp";
ci->threshold = 100;
ci->file_limit = 100;
ci->min_interval = 1000000;
ci->inset = 10; /* Percent */
while ((c = getopt(argc, argv, "w:i:dh:s:v:zl:t:D:")) > 0) {
switch (c) {
case 'h':
dorange(optarg, &ci->dark.h, &ci->bright.h, 360);
break;
case 's':
dorange(optarg, &ci->dark.s, &ci->bright.s, 255);
break;
case 'v':
dorange(optarg, &ci->dark.v, &ci->bright.v, 255);
break;
case 'z':
ci->zapping = 1;
break;
case 'l':
ci->file_limit = atoi(optarg);
break;
case 'i':
ci->min_interval = 1000000 * atof(optarg);
break;
case 't':
ci->threshold = atof(optarg) * 1000;
if (ci->threshold > 1000 || ci->threshold < 0) {
fprintf(stderr, "Invalid threshold value '%s' (range is 0-1)\n", optarg);
return -1;
}
break;
case 'w':
ci->min_width = atoi(optarg);
break;
case 'd':
ci->debug++;
break;
case 'D':
ci->dir = av_strdup(optarg);
break;
default:
fprintf(stderr, "Unrecognized argument '%s'\n", argv[optind]);
return -1;
}
}
fprintf(stderr, "Fish detector configured:\n");
fprintf(stderr, " HSV range: %d,%d,%d - %d,%d,%d\n",
ci->dark.h,
ci->dark.s,
ci->dark.v,
ci->bright.h,
ci->bright.s,
ci->bright.v);
fprintf(stderr, " Threshold is %d%% pixels\n", ci->threshold / 10);
return 0;
}
static void get_hsv(HSV *hsv, int r, int g, int b)
{
int i, v, x, f;
x = (r < g) ? r : g;
if (b < x)
x = b;
v = (r > g) ? r : g;
if (b > v)
v = b;
if (v == x) {
hsv->h = 0;
hsv->s = 0;
hsv->v = v;
return;
}
if (r == v) {
f = g - b;
i = 0;
} else if (g == v) {
f = b - r;
i = 2 * 60;
} else {
f = r - g;
i = 4 * 60;
}
hsv->h = i + (60 * f) / (v - x);
if (hsv->h < 0)
hsv->h += 360;
hsv->s = (255 * (v - x)) / v;
hsv->v = v;
return;
}
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
ContextInfo *ci = (ContextInfo *) ctx;
uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
int rowsize = picture->linesize[0];
#if 0
printf("pix_fmt = %d, width = %d, pts = %lld, ci->next_pts = %lld\n",
pix_fmt, width, pts, ci->next_pts);
#endif
if (pts < ci->next_pts)
return;
if (width < ci->min_width)
return;
ci->next_pts = pts + 1000000;
if (pix_fmt == PIX_FMT_YUV420P) {
uint8_t *y, *u, *v;
int width2 = width >> 1;
int inrange = 0;
int pixcnt;
int h;
int h_start, h_end;
int w_start, w_end;
h_end = 2 * ((ci->inset * height) / 200);
h_start = height - h_end;
w_end = (ci->inset * width2) / 100;
w_start = width2 - w_end;
pixcnt = ((h_start - h_end) >> 1) * (w_start - w_end);
y = picture->data[0] + h_end * picture->linesize[0] + w_end * 2;
u = picture->data[1] + h_end * picture->linesize[1] / 2 + w_end;
v = picture->data[2] + h_end * picture->linesize[2] / 2 + w_end;
for (h = h_start; h > h_end; h -= 2) {
int w;
for (w = w_start; w > w_end; w--) {
unsigned int r,g,b;
HSV hsv;
int cb, cr, yt, r_add, g_add, b_add;
YUV_TO_RGB1_CCIR(u[0], v[0]);
YUV_TO_RGB2_CCIR(r, g, b, y[0]);
get_hsv(&hsv, r, g, b);
if (ci->debug > 1)
fprintf(stderr, "(%d,%d,%d) -> (%d,%d,%d)\n",
r,g,b,hsv.h,hsv.s,hsv.v);
if (hsv.h >= ci->dark.h && hsv.h <= ci->bright.h &&
hsv.s >= ci->dark.s && hsv.s <= ci->bright.s &&
hsv.v >= ci->dark.v && hsv.v <= ci->bright.v) {
inrange++;
} else if (ci->zapping) {
y[0] = y[1] = y[rowsize] = y[rowsize + 1] = 16;
u[0] = 128;
v[0] = 128;
}
y+= 2;
u++;
v++;
}
y += picture->linesize[0] * 2 - (w_start - w_end) * 2;
u += picture->linesize[1] - (w_start - w_end);
v += picture->linesize[2] - (w_start - w_end);
}
if (ci->debug)
fprintf(stderr, "Fish: Inrange=%d of %d = %d threshold\n", inrange, pixcnt, 1000 * inrange / pixcnt);
if (inrange * 1000 / pixcnt >= ci->threshold) {
/* Save to file */
int size;
char *buf;
AVPicture picture1;
static int frame_counter;
static int foundfile;
if ((frame_counter++ % 20) == 0) {
/* Check how many files we have */
DIR *d;
foundfile = 0;
d = opendir(ci->dir);
if (d) {
struct dirent *dent;
while ((dent = readdir(d))) {
if (strncmp("fishimg", dent->d_name, 7) == 0) {
if (strcmp(".ppm", dent->d_name + strlen(dent->d_name) - 4) == 0) {
foundfile++;
}
}
}
closedir(d);
}
}
if (foundfile < ci->file_limit) {
FILE *f;
char fname[256];
size = avpicture_get_size(PIX_FMT_RGB24, width, height);
buf = av_malloc(size);
avpicture_fill(&picture1, buf, PIX_FMT_RGB24, width, height);
// if we already got a SWS context, let's realloc if is not re-useable
ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
width, height, pix_fmt,
width, height, PIX_FMT_RGB24,
sws_flags, NULL, NULL, NULL);
if (ci->toRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the toRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->toRGB_convert_ctx,
picture->data, picture->linesize, 0, height,
picture1.data, picture1.linesize);
/* Write out the PPM file */
snprintf(fname, sizeof(fname), "%s/fishimg%ld_%"PRId64".ppm", ci->dir, (long)(av_gettime() / 1000000), pts);
f = fopen(fname, "w");
if (f) {
fprintf(f, "P6 %d %d 255\n", width, height);
fwrite(buf, width * height * 3, 1, f);
fclose(f);
}
av_free(buf);
ci->next_pts = pts + ci->min_interval;
}
}
}
}
--- NEW FILE ---
/*
* imlib2 based hook
* Copyright (c) 2002 Philip Gladstone
*
* This module is very much intended as an example of what could be done.
*
* One caution is that this is an expensive process -- in particular the
* conversion of the image into RGB and back is time consuming. For some
* special cases -- e.g. painting black text -- it would be faster to paint
* the text into a bitmap and then combine it directly into the YUV
* image. However, this code is fast enough to handle 10 fps of 320x240 on a
* 900MHz Duron in maybe 15% of the CPU.
* See further statistics on Pentium4, 3GHz, FFMpeg is SVN-r6798
* Input movie is 20.2 seconds of PAL DV on AVI
* Output movie is DVD compliant VOB.
*
ffmpeg -i input.avi -target pal-dvd out.vob
# 13.516s just transcode
ffmpeg -i input.avi -vhook /usr/local/bin/vhook/null.dll -target pal-dvd out.vob
# 23.546s transcode and img_convert
ffmpeg -i input.avi -vhook \
'vhook/imlib2.dll -c red -F Vera/20 -x 150-0.5*N -y 70+0.25*N -t Hello_person' \
-target pal-dvd out.vob
# 21.454s transcode, img_convert and move text around
ffmpeg -i input.avi -vhook \
'vhook/imlib2.dll -x 150-0.5*N -y 70+0.25*N -i /usr/share/imlib2/data/images/bulb.png' \
-target pal-dvd out.vob
# 20.828s transcode, img_convert and move image around
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "framehook.h"
#include "swscale.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#undef time
#include <sys/time.h>
#include <time.h>
#include <Imlib2.h>
#include "eval.h"
const char *const_names[]={
"PI",
"E",
"N", // frame number (starting at zero)
"H", // frame height
"W", // frame width
"h", // image height
"w", // image width
"X", // previous x
"Y", // previous y
NULL
};
static int sws_flags = SWS_BICUBIC;
typedef struct {
int dummy;
Imlib_Font fn;
char *text;
char *file;
int r, g, b, a;
AVEvalExpr *eval_r, *eval_g, *eval_b, *eval_a;
char *expr_R, *expr_G, *expr_B, *expr_A;
int eval_colors;
double x, y;
char *fileImage;
struct _CachedImage *cache;
Imlib_Image imageOverlaid;
AVEvalExpr *eval_x, *eval_y;
char *expr_x, *expr_y;
int frame_number;
int imageOverlaid_width, imageOverlaid_height;
// This vhook first converts frame to RGB ...
struct SwsContext *toRGB_convert_ctx;
// ... and then converts back frame from RGB to initial format
struct SwsContext *fromRGB_convert_ctx;
} ContextInfo;
typedef struct _CachedImage {
struct _CachedImage *next;
Imlib_Image image;
int width;
int height;
} CachedImage;
void Release(void *ctx)
{
ContextInfo *ci;
ci = (ContextInfo *) ctx;
if (ci->cache) {
imlib_context_set_image(ci->cache->image);
imlib_free_image();
av_free(ci->cache);
}
if (ctx) {
if (ci->imageOverlaid) {
imlib_context_set_image(ci->imageOverlaid);
imlib_free_image();
}
ff_eval_free(ci->eval_x);
ff_eval_free(ci->eval_y);
ff_eval_free(ci->eval_r);
ff_eval_free(ci->eval_g);
ff_eval_free(ci->eval_b);
ff_eval_free(ci->eval_a);
av_free(ci->expr_x);
av_free(ci->expr_y);
av_free(ci->expr_R);
av_free(ci->expr_G);
av_free(ci->expr_B);
av_free(ci->expr_A);
sws_freeContext(ci->toRGB_convert_ctx);
sws_freeContext(ci->fromRGB_convert_ctx);
av_free(ctx);
}
}
int Configure(void **ctxp, int argc, char *argv[])
{
int c;
ContextInfo *ci;
char *rgbtxt = 0;
char *font = "LucidaSansDemiBold/16";
char *fp = getenv("FONTPATH");
char *color = 0;
FILE *f;
char *p;
char *error;
*ctxp = av_mallocz(sizeof(ContextInfo));
ci = (ContextInfo *) *ctxp;
ci->x = 0.0;
ci->y = 0.0;
ci->expr_x = "0.0";
ci->expr_y = "0.0";
optind = 0;
/* Use ':' to split FONTPATH */
if (fp)
while (p = strchr(fp, ':')) {
*p = 0;
imlib_add_path_to_font_path(fp);
fp = p + 1;
}
if ((fp) && (*fp))
imlib_add_path_to_font_path(fp);
while ((c = getopt(argc, argv, "R:G:B:A:C:c:f:F:t:x:y:i:")) > 0) {
switch (c) {
case 'R':
ci->expr_R = av_strdup(optarg);
ci->eval_colors = 1;
break;
case 'G':
ci->expr_G = av_strdup(optarg);
ci->eval_colors = 1;
break;
case 'B':
ci->expr_B = av_strdup(optarg);
ci->eval_colors = 1;
break;
case 'A':
ci->expr_A = av_strdup(optarg);
break;
case 'C':
rgbtxt = optarg;
break;
case 'c':
color = optarg;
break;
case 'F':
font = optarg;
break;
case 't':
ci->text = av_strdup(optarg);
break;
case 'f':
ci->file = av_strdup(optarg);
break;
case 'x':
ci->expr_x = av_strdup(optarg);
break;
case 'y':
ci->expr_y = av_strdup(optarg);
break;
case 'i':
ci->fileImage = av_strdup(optarg);
break;
case '?':
fprintf(stderr, "Unrecognized argument '%s'\n", argv[optind]);
return -1;
}
}
if (ci->eval_colors && !(ci->expr_R && ci->expr_G && ci->expr_B))
{
fprintf(stderr, "You must specify expressions for all or no colors.\n");
return -1;
}
if (ci->text || ci->file) {
ci->fn = imlib_load_font(font);
if (!ci->fn) {
fprintf(stderr, "Failed to load font '%s'\n", font);
return -1;
}
imlib_context_set_font(ci->fn);
imlib_context_set_direction(IMLIB_TEXT_TO_RIGHT);
}
if (color) {
char buff[256];
int done = 0;
if (ci->eval_colors)
{
fprintf(stderr, "You must not specify both a color name and expressions for the colors.\n");
return -1;
}
if (rgbtxt)
f = fopen(rgbtxt, "r");
else
{
f = fopen("/usr/share/X11/rgb.txt", "r");
if (!f)
f = fopen("/usr/lib/X11/rgb.txt", "r");
}
if (!f) {
fprintf(stderr, "Failed to find RGB color names file\n");
return -1;
}
while (fgets(buff, sizeof(buff), f)) {
int r, g, b;
char colname[80];
if (sscanf(buff, "%d %d %d %64s", &r, &g, &b, colname) == 4 &&
strcasecmp(colname, color) == 0) {
ci->r = r;
ci->g = g;
ci->b = b;
/* fprintf(stderr, "%s -> %d,%d,%d\n", colname, r, g, b); */
done = 1;
break;
}
}
fclose(f);
if (!done) {
fprintf(stderr, "Unable to find color '%s' in rgb.txt\n", color);
return -1;
}
} else if (ci->eval_colors) {
if (!(ci->eval_r = ff_parse(ci->expr_R, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse R expression '%s': %s\n", ci->expr_R, error);
return -1;
}
if (!(ci->eval_g = ff_parse(ci->expr_G, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse G expression '%s': %s\n", ci->expr_G, error);
return -1;
}
if (!(ci->eval_b = ff_parse(ci->expr_B, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse B expression '%s': %s\n", ci->expr_B, error);
return -1;
}
}
if (ci->expr_A) {
if (!(ci->eval_a = ff_parse(ci->expr_A, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse A expression '%s': %s\n", ci->expr_A, error);
return -1;
}
} else {
ci->a = 255;
}
if (!(ci->eval_colors || ci->eval_a))
imlib_context_set_color(ci->r, ci->g, ci->b, ci->a);
/* load the image (for example, credits for a movie) */
if (ci->fileImage) {
ci->imageOverlaid = imlib_load_image_immediately(ci->fileImage);
if (!(ci->imageOverlaid)){
av_log(NULL, AV_LOG_ERROR, "Couldn't load image '%s'\n", ci->fileImage);
return -1;
}
imlib_context_set_image(ci->imageOverlaid);
ci->imageOverlaid_width = imlib_image_get_width();
ci->imageOverlaid_height = imlib_image_get_height();
}
if (!(ci->eval_x = ff_parse(ci->expr_x, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse x expression '%s': %s\n", ci->expr_x, error);
return -1;
}
if (!(ci->eval_y = ff_parse(ci->expr_y, const_names, NULL, NULL, NULL, NULL, &error))){
av_log(NULL, AV_LOG_ERROR, "Couldn't parse y expression '%s': %s\n", ci->expr_y, error);
return -1;
}
return 0;
}
static Imlib_Image get_cached_image(ContextInfo *ci, int width, int height)
{
CachedImage *cache;
for (cache = ci->cache; cache; cache = cache->next) {
if (width == cache->width && height == cache->height)
return cache->image;
}
return NULL;
}
static void put_cached_image(ContextInfo *ci, Imlib_Image image, int width, int height)
{
CachedImage *cache = av_mallocz(sizeof(*cache));
cache->image = image;
cache->width = width;
cache->height = height;
cache->next = ci->cache;
ci->cache = cache;
}
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
ContextInfo *ci = (ContextInfo *) ctx;
AVPicture picture1;
Imlib_Image image;
DATA32 *data;
image = get_cached_image(ci, width, height);
if (!image) {
image = imlib_create_image(width, height);
put_cached_image(ci, image, width, height);
}
imlib_context_set_image(image);
data = imlib_image_get_data();
avpicture_fill(&picture1, (uint8_t *) data, PIX_FMT_RGB32, width, height);
// if we already got a SWS context, let's realloc if is not re-useable
ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
width, height, pix_fmt,
width, height, PIX_FMT_RGB32,
sws_flags, NULL, NULL, NULL);
if (ci->toRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the toRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->toRGB_convert_ctx,
picture->data, picture->linesize, 0, height,
picture1.data, picture1.linesize);
imlib_image_set_has_alpha(0);
{
int wid, hig, h_a, v_a;
char buff[1000];
char tbuff[1000];
char *tbp = ci->text;
time_t now = time(0);
char *p, *q;
int y;
double const_values[]={
M_PI,
M_E,
ci->frame_number, // frame number (starting at zero)
height, // frame height
width, // frame width
ci->imageOverlaid_height, // image height
ci->imageOverlaid_width, // image width
ci->x, // previous x
ci->y, // previous y
0
};
if (ci->file) {
int fd = open(ci->file, O_RDONLY);
if (fd < 0) {
tbp = "[File not found]";
} else {
int l = read(fd, tbuff, sizeof(tbuff) - 1);
if (l >= 0) {
tbuff[l] = 0;
tbp = tbuff;
} else {
tbp = "[I/O Error]";
}
close(fd);
}
}
if (tbp)
strftime(buff, sizeof(buff), tbp, localtime(&now));
else if (!(ci->imageOverlaid))
strftime(buff, sizeof(buff), "[No data]", localtime(&now));
ci->x = ff_parse_eval(ci->eval_x, const_values, ci);
ci->y = ff_parse_eval(ci->eval_y, const_values, ci);
y = ci->y;
if (ci->eval_a) {
ci->a = ff_parse_eval(ci->eval_a, const_values, ci);
}
if (ci->eval_colors) {
ci->r = ff_parse_eval(ci->eval_r, const_values, ci);
ci->g = ff_parse_eval(ci->eval_g, const_values, ci);
ci->b = ff_parse_eval(ci->eval_b, const_values, ci);
}
if (ci->eval_colors || ci->eval_a) {
imlib_context_set_color(ci->r, ci->g, ci->b, ci->a);
}
if (!(ci->imageOverlaid))
for (p = buff; p; p = q) {
q = strchr(p, '\n');
if (q)
*q++ = 0;
imlib_text_draw_with_return_metrics(ci->x, y, p, &wid, &hig, &h_a, &v_a);
y += v_a;
}
if (ci->imageOverlaid) {
imlib_context_set_image(image);
imlib_blend_image_onto_image(ci->imageOverlaid, 0,
0, 0, ci->imageOverlaid_width, ci->imageOverlaid_height,
ci->x, ci->y, ci->imageOverlaid_width, ci->imageOverlaid_height);
}
}
ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
width, height, PIX_FMT_RGB32,
width, height, pix_fmt,
sws_flags, NULL, NULL, NULL);
if (ci->fromRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the fromRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->fromRGB_convert_ctx,
picture1.data, picture1.linesize, 0, height,
picture->data, picture->linesize);
ci->frame_number++;
}
--- NEW FILE ---
/*
* Null Video Hook
* Copyright (c) 2002 Philip Gladstone
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include "framehook.h"
#include "swscale.h"
static int sws_flags = SWS_BICUBIC;
typedef struct {
int dummy;
// This vhook first converts frame to RGB ...
struct SwsContext *toRGB_convert_ctx;
// ... and later converts back frame from RGB to initial format
struct SwsContext *fromRGB_convert_ctx;
} ContextInfo;
void Release(void *ctx)
{
ContextInfo *ci;
ci = (ContextInfo *) ctx;
if (ctx) {
sws_freeContext(ci->toRGB_convert_ctx);
sws_freeContext(ci->fromRGB_convert_ctx);
av_free(ctx);
}
}
int Configure(void **ctxp, int argc, char *argv[])
{
fprintf(stderr, "Called with argc=%d\n", argc);
*ctxp = av_mallocz(sizeof(ContextInfo));
return 0;
}
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
ContextInfo *ci = (ContextInfo *) ctx;
char *buf = 0;
AVPicture picture1;
AVPicture *pict = picture;
(void) ci;
if (pix_fmt != PIX_FMT_RGB24) {
int size;
size = avpicture_get_size(PIX_FMT_RGB24, width, height);
buf = av_malloc(size);
avpicture_fill(&picture1, buf, PIX_FMT_RGB24, width, height);
// if we already got a SWS context, let's realloc if is not re-useable
ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
width, height, pix_fmt,
width, height, PIX_FMT_RGB24,
sws_flags, NULL, NULL, NULL);
if (ci->toRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the toRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->toRGB_convert_ctx,
picture->data, picture->linesize, 0, height,
picture1.data, picture1.linesize);
pict = &picture1;
}
/* Insert filter code here */
if (pix_fmt != PIX_FMT_RGB24) {
ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
width, height, PIX_FMT_RGB24,
width, height, pix_fmt,
sws_flags, NULL, NULL, NULL);
if (ci->fromRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the fromRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->fromRGB_convert_ctx,
picture1.data, picture1.linesize, 0, height,
picture->data, picture->linesize);
}
av_free(buf);
}
--- NEW FILE ---
/*
* PPM Video Hook
* Copyright (c) 2003 Charles Yates
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include "framehook.h"
#include "avformat.h"
#include "swscale.h"
#include "avstring.h"
static int sws_flags = SWS_BICUBIC;
/** Bi-directional pipe structure.
*/
typedef struct rwpipe
{
int pid;
FILE *reader;
FILE *writer;
}
rwpipe;
/** Create a bidirectional pipe for the given command.
*/
static rwpipe *rwpipe_open( int argc, char *argv[] )
{
rwpipe *this = av_mallocz( sizeof( rwpipe ) );
if ( this != NULL )
{
int input[ 2 ];
int output[ 2 ];
pipe( input );
pipe( output );
this->pid = fork();
if ( this->pid == 0 )
{
#define COMMAND_SIZE 10240
char *command = av_mallocz( COMMAND_SIZE );
int i;
strcpy( command, "" );
for ( i = 0; i < argc; i ++ )
{
av_strlcat( command, argv[ i ], COMMAND_SIZE );
av_strlcat( command, " ", COMMAND_SIZE );
}
dup2( output[ 0 ], STDIN_FILENO );
dup2( input[ 1 ], STDOUT_FILENO );
close( input[ 0 ] );
close( input[ 1 ] );
close( output[ 0 ] );
close( output[ 1 ] );
execl("/bin/sh", "sh", "-c", command, (char*)NULL );
_exit( 255 );
}
else
{
close( input[ 1 ] );
close( output[ 0 ] );
this->reader = fdopen( input[ 0 ], "r" );
this->writer = fdopen( output[ 1 ], "w" );
}
}
return this;
}
/** Read data from the pipe.
*/
static FILE *rwpipe_reader( rwpipe *this )
{
if ( this != NULL )
return this->reader;
else
return NULL;
}
/** Write data to the pipe.
*/
static FILE *rwpipe_writer( rwpipe *this )
{
if ( this != NULL )
return this->writer;
else
return NULL;
}
/* Read a number from the pipe - assumes PNM style headers.
*/
static int rwpipe_read_number( rwpipe *rw )
{
int value = 0;
int c = 0;
FILE *in = rwpipe_reader( rw );
do
{
c = fgetc( in );
while( c != EOF && !isdigit( c ) && c != '#' )
c = fgetc( in );
if ( c == '#' )
while( c != EOF && c != '\n' )
c = fgetc( in );
}
while ( c != EOF && !isdigit( c ) );
while( c != EOF && isdigit( c ) )
{
value = value * 10 + ( c - '0' );
c = fgetc( in );
}
return value;
}
/** Read a PPM P6 header.
*/
static int rwpipe_read_ppm_header( rwpipe *rw, int *width, int *height )
{
char line[ 3 ];
FILE *in = rwpipe_reader( rw );
int max;
fgets( line, 3, in );
if ( !strncmp( line, "P6", 2 ) )
{
*width = rwpipe_read_number( rw );
*height = rwpipe_read_number( rw );
max = rwpipe_read_number( rw );
return max != 255 || *width <= 0 || *height <= 0;
}
return 1;
}
/** Close the pipe and process.
*/
static void rwpipe_close( rwpipe *this )
{
if ( this != NULL )
{
fclose( this->reader );
fclose( this->writer );
waitpid( this->pid, NULL, 0 );
av_free( this );
}
}
/** Context info for this vhook - stores the pipe and image buffers.
*/
typedef struct
{
rwpipe *rw;
int size1;
char *buf1;
int size2;
char *buf2;
// This vhook first converts frame to RGB ...
struct SwsContext *toRGB_convert_ctx;
// ... then processes it via a PPM command pipe ...
// ... and finally converts back frame from RGB to initial format
struct SwsContext *fromRGB_convert_ctx;
}
ContextInfo;
/** Initialise the context info for this vhook.
*/
int Configure(void **ctxp, int argc, char *argv[])
{
if ( argc > 1 )
{
*ctxp = av_mallocz(sizeof(ContextInfo));
if ( ctxp != NULL && argc > 1 )
{
ContextInfo *info = (ContextInfo *)*ctxp;
info->rw = rwpipe_open( argc - 1, &argv[ 1 ] );
return 0;
}
}
return 1;
}
/** Process a frame.
*/
void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
int err = 0;
ContextInfo *ci = (ContextInfo *) ctx;
AVPicture picture1;
AVPicture picture2;
AVPicture *pict = picture;
int out_width;
int out_height;
int i;
uint8_t *ptr = NULL;
FILE *in = rwpipe_reader( ci->rw );
FILE *out = rwpipe_writer( ci->rw );
/* Check that we have a pipe to talk to. */
if ( in == NULL || out == NULL )
err = 1;
/* Convert to RGB24 if necessary */
if ( !err && pix_fmt != PIX_FMT_RGB24 )
{
int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
if ( size != ci->size1 )
{
av_free( ci->buf1 );
ci->buf1 = av_malloc(size);
ci->size1 = size;
err = ci->buf1 == NULL;
}
if ( !err )
{
avpicture_fill(&picture1, ci->buf1, PIX_FMT_RGB24, width, height);
// if we already got a SWS context, let's realloc if is not re-useable
ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
width, height, pix_fmt,
width, height, PIX_FMT_RGB24,
sws_flags, NULL, NULL, NULL);
if (ci->toRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the toRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->toRGB_convert_ctx,
picture->data, picture->linesize, 0, height,
picture1.data, picture1.linesize);
pict = &picture1;
}
}
/* Write out the PPM */
if ( !err )
{
ptr = pict->data[ 0 ];
fprintf( out, "P6\n%d %d\n255\n", width, height );
for ( i = 0; !err && i < height; i ++ )
{
err = !fwrite( ptr, width * 3, 1, out );
ptr += pict->linesize[ 0 ];
}
if ( !err )
err = fflush( out );
}
/* Read the PPM returned. */
if ( !err && !rwpipe_read_ppm_header( ci->rw, &out_width, &out_height ) )
{
int size = avpicture_get_size(PIX_FMT_RGB24, out_width, out_height);
if ( size != ci->size2 )
{
av_free( ci->buf2 );
ci->buf2 = av_malloc(size);
ci->size2 = size;
err = ci->buf2 == NULL;
}
if ( !err )
{
avpicture_fill(&picture2, ci->buf2, PIX_FMT_RGB24, out_width, out_height);
ptr = picture2.data[ 0 ];
for ( i = 0; !err && i < out_height; i ++ )
{
err = !fread( ptr, out_width * 3, 1, in );
ptr += picture2.linesize[ 0 ];
}
}
}
/* Convert the returned PPM back to the input format */
if ( !err )
{
/* The out_width/out_height returned from the PPM
* filter won't necessarily be the same as width and height
* but it will be scaled anyway to width/height.
*/
av_log(NULL, AV_LOG_DEBUG,
"PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
width, height, out_width, out_height);
ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
out_width, out_height, PIX_FMT_RGB24,
width, height, pix_fmt,
sws_flags, NULL, NULL, NULL);
if (ci->fromRGB_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the fromRGB conversion context\n");
return;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->fromRGB_convert_ctx,
picture2.data, picture2.linesize, 0, out_height,
picture->data, picture->linesize);
}
}
/** Clean up the effect.
*/
void Release(void *ctx)
{
ContextInfo *ci;
ci = (ContextInfo *) ctx;
if (ctx)
{
rwpipe_close( ci->rw );
av_free( ci->buf1 );
av_free( ci->buf2 );
sws_freeContext(ci->toRGB_convert_ctx);
sws_freeContext(ci->fromRGB_convert_ctx);
av_free(ctx);
}
}
--- NEW FILE ---
/*
* Watermark Hook
* Copyright (c) 2005 Marcus Engene myfirstname(at)mylastname.se
*
* parameters for 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 watermark image filename. You must specify this!
*
* MODE 0:
* The watermark picture works like this (assuming color intensities 0..0xff):
* Per color do this:
* If mask color is 0x80, no change to the original frame.
* If mask color is < 0x80 the abs difference is subtracted from the frame. If
* result < 0, result = 0
* If mask color is > 0x80 the abs difference is added to the frame. If result
* > 0xff, result = 0xff
*
* You can override the 0x80 level with the -t flag. E.g. if threshold is
* 000000 the color value of watermark is added to the 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 then the watermark pixel is used.
*
* Example usage:
* 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 for ffmpeg.
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
//#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>
#include "common.h"
#include "avformat.h"
#include "framehook.h"
#include "cmdutils.h"
#include "swscale.h"
static int sws_flags = SWS_BICUBIC;
typedef struct {
char filename[2000];
int x_size;
int y_size;
/* get_watermark_picture() variables */
AVFormatContext *pFormatCtx;
const char *p_ext;
int videoStream;
int frameFinished;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVPacket packet;
int numBytes;
uint8_t *buffer;
int i;
AVInputFormat *file_iformat;
AVStream *st;
int is_done;
AVFrame *pFrameRGB;
int thrR;
int thrG;
int thrB;
int mode;
// This vhook first converts frame to RGB ...
struct SwsContext *toRGB_convert_ctx;
// ... then converts a watermark and applies it to the RGB frame ...
struct SwsContext *watermark_convert_ctx;
// ... and finally converts back frame from RGB to initial format
struct SwsContext *fromRGB_convert_ctx;
} ContextInfo;
int get_watermark_picture(ContextInfo *ci, int cleanup);
/****************************************************************************
*
****************************************************************************/
void Release(void *ctx)
{
ContextInfo *ci;
ci = (ContextInfo *) ctx;
if (ci) {
get_watermark_picture(ci, 1);
sws_freeContext(ci->toRGB_convert_ctx);
sws_freeContext(ci->watermark_convert_ctx);
sws_freeContext(ci->fromRGB_convert_ctx);
}
av_free(ctx);
}
/****************************************************************************
*
****************************************************************************/
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;
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: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;
...
[truncated message content] |