Remove deprecated vhook subsystem.

Originally committed as revision 17769 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Diego Biurrun 2009-03-03 14:09:10 +00:00
parent f989d39752
commit fdf119062e
16 changed files with 7 additions and 3177 deletions

View File

@ -18,15 +18,6 @@ Applications
ffmpeg:
ffmpeg.c Michael Niedermayer
Video Hooks:
vhook
vhook/watermark.c Marcus Engene
vhook/ppm.c
vhook/drawtext.c
vhook/fish.c
vhook/null.c
vhook/imlib2.c
ffplay:
ffplay.c Michael Niedermayer

View File

@ -32,10 +32,8 @@ FF_LDFLAGS := $(FFLDFLAGS)
FF_EXTRALIBS := $(FFEXTRALIBS)
FF_DEP_LIBS := $(DEP_LIBS)
ALL_TARGETS-$(CONFIG_VHOOK) += videohook
ALL_TARGETS-$(BUILD_DOC) += documentation
INSTALL_TARGETS-$(CONFIG_VHOOK) += install-vhook
ifneq ($(PROGS),)
INSTALL_TARGETS-yes += install-progs install-data
INSTALL_TARGETS-$(BUILD_DOC) += install-man
@ -81,41 +79,8 @@ cmdutils.o cmdutils.d: version.h
alltools: $(addsuffix $(EXESUF),$(addprefix tools/, cws2fws pktdumper qt-faststart trasher))
VHOOKCFLAGS += $(filter-out -mdynamic-no-pic,$(CFLAGS))
BASEHOOKS = fish null watermark
ALLHOOKS = $(BASEHOOKS) drawtext imlib2 ppm
ALLHOOKS_SRCS = $(addprefix vhook/, $(addsuffix .c, $(ALLHOOKS)))
HOOKS-$(HAVE_FORK) += ppm
HOOKS-$(HAVE_IMLIB2) += imlib2
HOOKS-$(HAVE_FREETYPE2) += drawtext
HOOKS = $(addprefix vhook/, $(addsuffix $(SLIBSUF), $(BASEHOOKS) $(HOOKS-yes)))
VHOOKCFLAGS-$(HAVE_IMLIB2) += `imlib2-config --cflags`
LIBS_imlib2$(SLIBSUF) = `imlib2-config --libs`
VHOOKCFLAGS-$(HAVE_FREETYPE2) += `freetype-config --cflags`
LIBS_drawtext$(SLIBSUF) = `freetype-config --libs`
VHOOKCFLAGS += $(VHOOKCFLAGS-yes)
vhook/%.o vhook/%.d: CFLAGS:=$(VHOOKCFLAGS)
# vhooks compile fine without libav*, but need them nonetheless.
videohook: $(FF_DEP_LIBS) $(HOOKS)
$(eval VHOOKSHFLAGS=$(VHOOKSHFLAGS))
vhook/%$(SLIBSUF): vhook/%.o
$(CC) $(LDFLAGS) -o $@ $(VHOOKSHFLAGS) $< $(VHOOKLIBS) $(LIBS_$(@F))
VHOOK_DEPS = $(HOOKS:$(SLIBSUF)=.d)
depend dep: $(VHOOK_DEPS)
documentation: $(addprefix doc/, ffmpeg-doc.html faq.html ffserver-doc.html \
ffplay-doc.html general.html hooks.html \
$(ALLMANPAGES))
ffplay-doc.html general.html $(ALLMANPAGES))
doc/%.html: doc/%.texi
texi2html -monolithic -number $<
@ -141,11 +106,7 @@ install-man: $(MANPAGES)
install -d "$(MANDIR)/man1"
install -m 644 $(MANPAGES) "$(MANDIR)/man1"
install-vhook: videohook
install -d "$(SHLIBDIR)/vhook"
install -m 755 $(HOOKS) "$(SHLIBDIR)/vhook"
uninstall: uninstall-progs uninstall-data uninstall-man uninstall-vhook
uninstall: uninstall-progs uninstall-data uninstall-man
uninstall-progs:
rm -f $(addprefix "$(BINDIR)/", $(ALLPROGS))
@ -156,10 +117,6 @@ uninstall-data:
uninstall-man:
rm -f $(addprefix "$(MANDIR)/man1/",$(ALLMANPAGES))
uninstall-vhook:
rm -f $(addprefix "$(SHLIBDIR)/",$(ALLHOOKS_SRCS:.c=$(SLIBSUF)))
-rmdir "$(SHLIBDIR)/vhook/"
testclean:
rm -rf tests/vsynth1 tests/vsynth2 tests/data tests/asynth1.sw tests/*~
@ -168,10 +125,9 @@ clean:: testclean
rm -f doc/*.html doc/*.pod doc/*.1
rm -f $(addprefix tests/,$(addsuffix $(EXESUF),audiogen videogen rotozoom seek_test tiny_psnr))
rm -f $(addprefix tools/,$(addsuffix $(EXESUF),cws2fws pktdumper qt-faststart trasher))
rm -f vhook/*.o vhook/*~ vhook/*.so vhook/*.dylib vhook/*.dll
distclean::
rm -f version.h config.* vhook/*.d
rm -f version.h config.*
# regression tests
@ -355,6 +311,4 @@ tests/seek_test$(EXESUF): tests/seek_test.c $(FF_DEP_LIBS)
$(CC) $(FF_LDFLAGS) $(CFLAGS) -o $@ $< $(FF_EXTRALIBS)
.PHONY: lib videohook documentation *test regtest-* swscale-error zlib-error alltools check
-include $(VHOOK_DEPS)
.PHONY: lib documentation *test regtest-* swscale-error zlib-error alltools check

57
configure vendored
View File

@ -82,9 +82,8 @@ show_help(){
echo " --disable-ffserver disable ffserver build"
echo " --enable-postproc enable GPLed postprocessing support [no]"
echo " --enable-swscale enable GPLed software scaler support [no]"
echo " --enable-avfilter video filter support (replaces vhook) [no]"
echo " --enable-avfilter video filter support [no]"
echo " --enable-avfilter-lavf video filters dependent on avformat [no]"
echo " --disable-vhook disable video hooking support"
echo " --enable-beosthreads use BeOS threads [no]"
echo " --enable-os2threads use OS/2 threads [no]"
echo " --enable-pthreads use pthreads [no]"
@ -799,7 +798,6 @@ CONFIG_LIST="
static
swscale
vdpau
vhook
x11grab
zlib
"
@ -873,11 +871,9 @@ HAVE_LIST="
fast_cmov
fast_unaligned
fork
freetype2
gethrtime
GetProcessTimes
getrusage
imlib2
inet_aton
inline_asm
libdc1394_1
@ -1133,7 +1129,6 @@ movie_filter_deps="avfilter_lavf"
ffplay_deps="sdl"
ffserver_deps="ffm_muxer rtp_protocol rtsp_demuxer"
ffserver_extralibs='$ldl'
vhook_extralibs='$ldl'
# default parameters
@ -1180,12 +1175,10 @@ enable optimizations
enable protocols
enable static
enable stripping
vhook="default"
# build settings
add_cflags -D_ISOC99_SOURCE -D_POSIX_C_SOURCE=200112
SHFLAGS='-shared -Wl,-soname,$$(@F)'
VHOOKSHFLAGS='$(SHFLAGS)'
FFSERVERLDFLAGS=-Wl,-E
LIBPREF="lib"
LIBSUF=".a"
@ -1560,7 +1553,6 @@ case $target_os in
darwin)
disable need_memalign
SHFLAGS='-dynamiclib -Wl,-single_module -Wl,-install_name,$(SHLIBDIR)/$(SLIBNAME),-current_version,$(LIBVERSION),-compatibility_version,$(LIBMAJOR) -Wl,-read_only_relocs,suppress'
VHOOKSHFLAGS='-dynamiclib -Wl,-single_module -flat_namespace -undefined suppress -Wl,-install_name,$(SHLIBDIR)/vhook/$$(@F)'
strip="strip -x"
FFLDFLAGS="-Wl,-dynamic,-search_paths_first"
SLIBSUF=".dylib"
@ -1578,12 +1570,6 @@ case $target_os in
LIBTARGET=x64
fi
shlibdir_default="$bindir_default"
VHOOKSHFLAGS='-shared -L$(BUILD_ROOT)/libavformat -L$(BUILD_ROOT)/libavcodec -L$(BUILD_ROOT)/libavutil'
VHOOKLIBS='-lavformat$(BUILDSUF) -lavcodec$(BUILDSUF) -lavutil$(BUILDSUF) $(EXTRALIBS)'
if enabled swscale; then
VHOOKSHFLAGS="$VHOOKSHFLAGS -L\$(BUILD_ROOT)/libswscale"
VHOOKLIBS="$VHOOKLIBS -lswscale\$(BUILDSUF)"
fi
disable ffserver
SLIBPREF=""
SLIBSUF=".dll"
@ -1607,12 +1593,6 @@ case $target_os in
cygwin*)
target_os=cygwin
shlibdir_default="$bindir_default"
VHOOKSHFLAGS='-shared -L$(BUILD_ROOT)/libavformat -L$(BUILD_ROOT)/libavcodec -L$(BUILD_ROOT)/libavutil'
VHOOKLIBS='-lavformat$(BUILDSUF) -lavcodec$(BUILDSUF) -lavutil$(BUILDSUF) $(EXTRALIBS)'
if enabled swscale; then
VHOOKSHFLAGS="$VHOOKSHFLAGS -L\$(BUILD_ROOT)/libswscale"
VHOOKLIBS="$VHOOKLIBS -lswscale\$(BUILDSUF)"
fi
SLIBPREF="cyg"
SLIBSUF=".dll"
SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)'
@ -1622,7 +1602,7 @@ case $target_os in
enable dos_paths
;;
*-dos|freedos|opendos)
disable ffplay ffserver vhook
disable ffplay ffserver
disable $INDEV_LIST $OUTDEV_LIST
network_extralibs="-lsocket"
objformat="coff"
@ -1656,12 +1636,8 @@ case $target_os in
emximp -o $(SUBDIR)$(LIBPREF)$(NAME)_dll.lib $(SUBDIR)$(NAME).def;'
SLIB_INSTALL_EXTRA_CMD='install -m 644 $(SUBDIR)$(LIBPREF)$(NAME)_dll.a $(SUBDIR)$(LIBPREF)$(NAME)_dll.lib "$(LIBDIR)"'
SLIB_UNINSTALL_EXTRA_CMD='rm -f "$(LIBDIR)"/$(LIBPREF)$(NAME)_dll.a "$(LIBDIR)"/$(LIBPREF)$(NAME)_dll.lib'
disable vhook
enable dos_paths
;;
interix)
disable vhook
;;
*)
die "Unknown OS '$target_os'."
@ -2040,24 +2016,6 @@ void foo(char * $restrict_keyword p);
EOF
done
test "$vhook" = "default" && vhook="$dlopen"
if test "$target_os" = cygwin -o "$target_os" = mingw32 && enabled_all static vhook ; then
disable vhook
echo
echo "At the moment vhooks don't work on Cygwin or MinGW static builds."
echo "Patches welcome."
echo
fi
if enabled vhook; then
check_ldflags -rdynamic
check_ldflags -export-dynamic
fi
check_foo_config imlib2 imlib2 Imlib2.h imlib_load_font
check_foo_config freetype2 freetype ft2build.h FT_Init_FreeType
##########################################
# SDL check
@ -2225,8 +2183,6 @@ if enabled gprof; then
add_ldflags -p
fi
VHOOKCFLAGS="-fPIC"
# Find out if the .align argument is a power of two or not.
check_asm asmalign_pot '".align 3"'
@ -2312,11 +2268,6 @@ echo "postprocessing support ${postproc-no}"
echo "software scaler enabled ${swscale-no}"
echo "new filter support ${avfilter-no}"
echo "filters using lavformat ${avfilter_lavf-no}"
echo "video hooking ${vhook-no}"
if enabled vhook; then
echo "Imlib2 support ${imlib2-no}"
echo "FreeType support ${freetype2-no}"
fi
echo "network support ${network-no}"
if enabled network; then
echo "IPv6 support ${ipv6-no}"
@ -2395,13 +2346,10 @@ enabled stripping &&
echo "STRIP=echo ignoring strip" >> config.mak
echo "OPTFLAGS=$CFLAGS" >> config.mak
echo "VHOOKCFLAGS=$VHOOKCFLAGS" >> config.mak
echo "LDFLAGS=$LDFLAGS" >> config.mak
echo "FFSERVERLDFLAGS=$FFSERVERLDFLAGS" >> config.mak
echo "SHFLAGS=$SHFLAGS" >> config.mak
echo "YASMFLAGS=$YASMFLAGS" >> config.mak
echo "VHOOKSHFLAGS=$VHOOKSHFLAGS" >> config.mak
echo "VHOOKLIBS=$VHOOKLIBS" >> config.mak
echo "LIBOBJFLAGS=$LIBOBJFLAGS" >> config.mak
echo "BUILD_STATIC=$static" >> config.mak
echo "BUILDSUF=$build_suffix" >> config.mak
@ -2529,7 +2477,6 @@ if enabled source_path_used; then
libswscale \
tests \
tools \
vhook \
"
FILES="\
Makefile \

View File

@ -660,9 +660,6 @@ Calculate PSNR of compressed frames.
Dump video coding statistics to @file{vstats_HHMMSS.log}.
@item -vstats_file @var{file}
Dump video coding statistics to @var{file}.
@item -vhook @var{module}
Insert video processing @var{module}. @var{module} contains the module
name and its parameters separated by spaces.
@item -top @var{n}
top=1/bottom=0/auto=-1 field first
@item -dc @var{precision}

View File

@ -691,10 +691,6 @@ Notes:
@itemize
@item In order to compile vhooks, you must have a POSIX-compliant libdl in
your MinGW system. Get dlfcn-win32 from
@url{http://code.google.com/p/dlfcn-win32}.
@item In order to compile FFplay, you must have the MinGW development library
of SDL. Get it from @url{http://www.libsdl.org}.
Edit the @file{bin/sdl-config} script so that it points to the correct prefix

View File

@ -1,299 +0,0 @@
\input texinfo @c -*- texinfo -*-
@settitle Video Hook Documentation
@titlepage
@sp 7
@center @titlefont{Video Hook Documentation}
@sp 3
@end titlepage
@chapter Introduction
@var{Please be aware that vhook is deprecated, and hence its development is
frozen (bug fixes are still accepted).
The substitute will be 'libavfilter', the result of our 'Video Filter API'
Google Summer of Code project. You may monitor its progress by subscribing to
the ffmpeg-soc mailing list at
@url{http://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc}.}
The video hook functionality is designed (mostly) for live video. It allows
the video to be modified or examined between the decoder and the encoder.
Any number of hook modules can be placed inline, and they are run in the
order that they were specified on the ffmpeg command line.
The video hook modules are provided for use as a base for your own modules,
and are described below.
Modules are loaded using the -vhook option to ffmpeg. The value of this parameter
is a space separated list of arguments. The first is the module name, and the rest
are passed as arguments to the Configure function of the module.
The modules are dynamic libraries: They have different suffixes (.so, .dll, .dylib)
depending on your platform. And your platform dictates if they need to be
somewhere in your PATH, or in your LD_LIBRARY_PATH. Otherwise you will need to
specify the full path of the vhook file that you are using.
@section null.c
This does nothing. Actually it converts the input image to RGB24 and then converts
it back again. This is meant as a sample that you can use to test your setup.
@section fish.c
This implements a 'fish detector'. Essentially it converts the image into HSV
space and tests whether more than a certain percentage of the pixels fall into
a specific HSV cuboid. If so, then the image is saved into a file for processing
by other bits of code.
Why use HSV? It turns out that HSV cuboids represent a more compact range of
colors than would an RGB cuboid.
@section imlib2.c
This module implements a text overlay for a video image. Currently it
supports a fixed overlay or reading the text from a file. The string
is passed through strftime() so that it is easy to imprint the date and
time onto the image.
This module depends on the external library imlib2, available on
Sourceforge, among other places, if it is not already installed on
your system.
You may also overlay an image (even semi-transparent) like TV stations do.
You may move either the text or the image around your video to create
scrolling credits, for example.
The font file used is looked for in a FONTPATH environment variable, and
prepended to the point size as a command line option and can be specified
with the full path to the font file, as in:
@example
-F /usr/X11R6/lib/X11/fonts/TTF/VeraBd.ttf/20
@end example
where 20 is the point size.
You can specify the filename to read RGB color names from. If it is not
specified, these defaults are used: @file{/usr/share/X11/rgb.txt} and
@file{/usr/lib/X11/rgb.txt}
Options:
@multitable @columnfractions .2 .8
@item @option{-C <rgb.txt>} @tab The filename to read RGB color names from
@item @option{-c <color>} @tab The color of the text
@item @option{-F <fontname>} @tab The font face and size
@item @option{-t <text>} @tab The text
@item @option{-f <filename>} @tab The filename to read text from
@item @option{-x <expression>}@tab x coordinate of text or image
@item @option{-y <expression>}@tab y coordinate of text or image
@item @option{-i <filename>} @tab The filename to read a image from
@item @option{-R <expression>}@tab Value for R color
@item @option{-G <expression>}@tab Value for G color
@item @option{-B <expression>}@tab Value for B color
@item @option{-A <expression>}@tab Value for Alpha channel
@end multitable
Expressions are functions of these variables:
@multitable @columnfractions .2 .8
@item @var{N} @tab frame number (starting at zero)
@item @var{H} @tab frame height
@item @var{W} @tab frame width
@item @var{h} @tab image height
@item @var{w} @tab image width
@item @var{X} @tab previous x coordinate of text or image
@item @var{Y} @tab previous y coordinate of text or image
@end multitable
You may also use the constants @var{PI}, @var{E}, and the math functions available at the
FFmpeg formula evaluator at (@url{ffmpeg-doc.html#SEC13}), except @var{bits2qp(bits)}
and @var{qp2bits(qp)}.
Usage examples:
@example
# Remember to set the path to your fonts
FONTPATH="/cygdrive/c/WINDOWS/Fonts/"
FONTPATH="$FONTPATH:/usr/share/imlib2/data/fonts/"
FONTPATH="$FONTPATH:/usr/X11R6/lib/X11/fonts/TTF/"
export FONTPATH
# Bulb dancing in a Lissajous pattern
ffmpeg -i input.avi -vhook \
'vhook/imlib2.dll -x W*(0.5+0.25*sin(N/47*PI))-w/2 -y H*(0.5+0.50*cos(N/97*PI))-h/2 -i /usr/share/imlib2/data/images/bulb.png' \
-acodec copy -sameq output.avi
# Text scrolling
ffmpeg -i input.avi -vhook \
'vhook/imlib2.dll -c red -F Vera.ttf/20 -x 150+0.5*N -y 70+0.25*N -t Hello' \
-acodec copy -sameq output.avi
# Date and time stamp, security-camera style:
ffmpeg -r 29.97 -s 320x256 -f video4linux -i /dev/video0 \
-vhook 'vhook/imlib2.so -x 0 -y 0 -i black-260x20.png' \
-vhook 'vhook/imlib2.so -c white -F VeraBd.ttf/12 -x 0 -y 0 -t %A-%D-%T' \
output.avi
In this example the video is captured from the first video capture card as a
320x256 AVI, and a black 260 by 20 pixel PNG image is placed in the upper
left corner, with the day, date and time overlaid on it in Vera Bold 12
point font. A simple black PNG file 260 pixels wide and 20 pixels tall
was created in the GIMP for this purpose.
# Scrolling credits from a text file
ffmpeg -i input.avi -vhook \
'vhook/imlib2.so -c white -F VeraBd.ttf/16 -x 100 -y -1.0*N -f credits.txt' \
-sameq output.avi
In this example, the text is stored in a file, and is positioned 100
pixels from the left hand edge of the video. The text is scrolled from the
bottom up. Making the y factor positive will scroll from the top down.
Increasing the magnitude of the y factor makes the text scroll faster,
decreasing it makes it scroll slower. Hint: Blank lines containing only
a newline are treated as end-of-file. To create blank lines, use lines
that consist of space characters only.
# Scrolling credits with custom color from a text file
ffmpeg -i input.avi -vhook \
'vhook/imlib2.so -C rgb.txt -c CustomColor1 -F VeraBd.ttf/16 -x 100 -y -1.0*N -f credits.txt' \
-sameq output.avi
This example does the same as the one above, but specifies an rgb.txt file
to be used, which has a custom-made color in it.
# Variable colors
ffmpeg -i input.avi -vhook \
'vhook/imlib2.so -t Hello -R abs(255*sin(N/47*PI)) -G abs(255*sin(N/47*PI)) -B abs(255*sin(N/47*PI))' \
-sameq output.avi
In this example, the color for the text goes up and down from black to
white.
# Text fade-out
ffmpeg -i input.avi -vhook \
'vhook/imlib2.so -t Hello -A max(0,255-exp(N/47))' \
-sameq output.avi
In this example, the text fades out in about 10 seconds for a 25 fps input
video file.
# scrolling credits from a graphics file
ffmpeg -sameq -i input.avi \
-vhook 'vhook/imlib2.so -x 0 -y -1.0*N -i credits.png' output.avi
In this example, a transparent PNG file the same width as the video
(e.g. 320 pixels), but very long, (e.g. 3000 pixels), was created, and
text, graphics, brushstrokes, etc, were added to the image. The image
is then scrolled up, from the bottom of the frame.
@end example
@section ppm.c
It's basically a launch point for a PPM pipe, so you can use any
executable (or script) which consumes a PPM on stdin and produces a PPM
on stdout (and flushes each frame). The Netpbm utilities are a series of
such programs.
A list of them is here:
@url{http://netpbm.sourceforge.net/doc/directory.html}
Usage example:
@example
ffmpeg -i input -vhook "/path/to/ppm.so some-ppm-filter args" output
@end example
@section drawtext.c
This module implements a text overlay for a video image. Currently it
supports a fixed overlay or reading the text from a file. The string
is passed through strftime() so that it is easy to imprint the date and
time onto the image.
Features:
@itemize @minus
@item TrueType, Type1 and others via the FreeType2 library
@item Font kerning (better output)
@item Line Wrap (put the text that doesn't fit one line on the next line)
@item Background box (currently in development)
@item Outline
@end itemize
Options:
@multitable @columnfractions .2 .8
@item @option{-c <color>} @tab Foreground color of the text ('internet' way) <#RRGGBB> [default #FFFFFF]
@item @option{-C <color>} @tab Background color of the text ('internet' way) <#RRGGBB> [default #000000]
@item @option{-f <font-filename>} @tab font file to use
@item @option{-t <text>} @tab text to display
@item @option{-T <filename>} @tab file to read text from
@item @option{-x <pos>} @tab x coordinate of the start of the text
@item @option{-y <pos>} @tab y coordinate of the start of the text
@end multitable
Text fonts are being looked for in a FONTPATH environment variable.
If the FONTPATH environment variable is not available, or is not checked by
your target (i.e. Cygwin), then specify the full path to the font file as in:
@example
-f /usr/X11R6/lib/X11/fonts/TTF/VeraBd.ttf
@end example
Usage Example:
@example
# Remember to set the path to your fonts
FONTPATH="/cygdrive/c/WINDOWS/Fonts/"
FONTPATH="$FONTPATH:/usr/share/imlib2/data/fonts/"
FONTPATH="$FONTPATH:/usr/X11R6/lib/X11/fonts/TTF/"
export FONTPATH
# Time and date display
ffmpeg -f video4linux2 -i /dev/video0 \
-vhook 'vhook/drawtext.so -f VeraBd.ttf -t %A-%D-%T' movie.mpg
This example grabs video from the first capture card and outputs it to an
MPEG video, and places "Weekday-dd/mm/yy-hh:mm:ss" at the top left of the
frame, updated every second, using the Vera Bold TrueType Font, which
should exist in: /usr/X11R6/lib/X11/fonts/TTF/
@end example
Check the man page for strftime() for all the various ways you can format
the date and time.
@section watermark.c
Command Line options:
@multitable @columnfractions .2 .8
@item @option{-m [0|1]} @tab Mode (default: 0, see below)
@item @option{-t 000000 - FFFFFF} @tab Threshold, six digit hex number
@item @option{-f <filename>} @tab Watermark image filename, must be specified!
@end multitable
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 absolute difference is subtracted from the
frame. If result < 0, result = 0.
If mask color is > 0x80 the absolute 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 and dark pictures can be made
(e.g. by using a picture generated by the Gimp and the bump map tool).
An example watermark file is at:
@url{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:
@example
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
@end example
@bye

View File

@ -34,7 +34,6 @@
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavformat/framehook.h"
#include "libavcodec/opt.h"
#include "libavcodec/audioconvert.h"
#include "libavutil/fifo.h"
@ -203,7 +202,6 @@ static int audio_volume = 256;
static int exit_on_error = 0;
static int using_stdin = 0;
static int using_vhook = 0;
static int verbose = 1;
static int thread_count= 1;
static int q_pressed = 0;
@ -736,7 +734,7 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void
dec = ist->st->codec;
/* deinterlace : must be done before any resize */
if (do_deinterlace || using_vhook) {
if (do_deinterlace) {
int size;
/* create temporary picture */
@ -764,10 +762,6 @@ static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void
picture2 = picture;
}
if (CONFIG_VHOOK)
frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height,
1000000 * ist->pts / AV_TIME_BASE);
if (picture != picture2)
*picture = *picture2;
*bufp = buf;
@ -1772,10 +1766,6 @@ static int av_encode(AVFormatContext **output_files,
codec->block_align= 0;
break;
case CODEC_TYPE_VIDEO:
if(using_vhook) {
fprintf(stderr,"-vcodec copy and -vhook are incompatible (frames are not decoded)\n");
av_exit(1);
}
codec->pix_fmt = icodec->pix_fmt;
codec->width = icodec->width;
codec->height = icodec->height;
@ -2651,29 +2641,6 @@ static void opt_video_tag(const char *arg)
video_codec_tag= arg[0] + (arg[1]<<8) + (arg[2]<<16) + (arg[3]<<24);
}
#if CONFIG_VHOOK
static void add_frame_hooker(const char *arg)
{
int argc = 0;
char *argv[64];
int i;
char *args = av_strdup(arg);
using_vhook = 1;
argv[0] = strtok(args, " ");
while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
}
i = frame_hook_add(argc, argv);
if (i != 0) {
fprintf(stderr, "Failed to add video hook function: %s\n", arg);
av_exit(1);
}
}
#endif
static void opt_video_codec(const char *arg)
{
opt_codec(&video_stream_copy, &video_codec_name, CODEC_TYPE_VIDEO, arg);
@ -3840,9 +3807,6 @@ static const OptionDef options[] = {
{ "psnr", OPT_BOOL | OPT_EXPERT | OPT_VIDEO, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
{ "vstats", OPT_EXPERT | OPT_VIDEO, {(void*)&opt_vstats}, "dump video coding statistics to file" },
{ "vstats_file", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_vstats_file}, "dump video coding statistics to file", "file" },
#if CONFIG_VHOOK
{ "vhook", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)add_frame_hooker}, "insert video processing module", "module" },
#endif
{ "intra_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_intra_matrix}, "specify intra matrix coeffs", "matrix" },
{ "inter_matrix", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_inter_matrix}, "specify inter matrix coeffs", "matrix" },
{ "top", HAS_ARG | OPT_EXPERT | OPT_VIDEO, {(void*)opt_top_field_first}, "top=1/bottom=0/auto=-1 field first", "" },

View File

@ -228,8 +228,6 @@ OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpeg.o
OBJS-$(CONFIG_LIBNUT_DEMUXER) += libnut.o riff.o
OBJS-$(CONFIG_LIBNUT_MUXER) += libnut.o riff.o
OBJS-$(CONFIG_VHOOK) += framehook.o
# protocols I/O
OBJS+= avio.o aviobuf.o

View File

@ -1,115 +0,0 @@
/*
* Video processing hooks
* Copyright (c) 2000, 2001 Fabrice Bellard
*
* 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 <errno.h>
#include "config.h"
#include "avformat.h"
#include "framehook.h"
#if HAVE_DLFCN_H
#include <dlfcn.h>
#endif
typedef struct FrameHookEntry {
struct FrameHookEntry *next;
FrameHookConfigureFn Configure;
FrameHookProcessFn Process;
FrameHookReleaseFn Release;
void *ctx;
} FrameHookEntry;
static FrameHookEntry *first_hook;
/* Returns 0 on OK */
int frame_hook_add(int argc, char *argv[])
{
void *loaded;
FrameHookEntry *fhe, **fhep;
if (argc < 1) {
return ENOENT;
}
loaded = dlopen(argv[0], RTLD_NOW);
if (!loaded) {
av_log(NULL, AV_LOG_ERROR, "%s\n", dlerror());
return -1;
}
fhe = av_mallocz(sizeof(*fhe));
if (!fhe) {
return AVERROR(ENOMEM);
}
fhe->Configure = dlsym(loaded, "Configure");
fhe->Process = dlsym(loaded, "Process");
fhe->Release = dlsym(loaded, "Release"); /* Optional */
if (!fhe->Process) {
av_log(NULL, AV_LOG_ERROR, "Failed to find Process entrypoint in %s\n", argv[0]);
return AVERROR(ENOENT);
}
if (!fhe->Configure && argc > 1) {
av_log(NULL, AV_LOG_ERROR, "Failed to find Configure entrypoint in %s\n", argv[0]);
return AVERROR(ENOENT);
}
if (argc > 1 || fhe->Configure) {
if (fhe->Configure(&fhe->ctx, argc, argv)) {
av_log(NULL, AV_LOG_ERROR, "Failed to Configure %s\n", argv[0]);
return AVERROR(EINVAL);
}
}
for (fhep = &first_hook; *fhep; fhep = &((*fhep)->next)) {
}
*fhep = fhe;
return 0;
}
void frame_hook_process(AVPicture *pict, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
{
if (first_hook) {
FrameHookEntry *fhe;
for (fhe = first_hook; fhe; fhe = fhe->next) {
fhe->Process(fhe->ctx, pict, pix_fmt, width, height, pts);
}
}
}
void frame_hook_release(void)
{
FrameHookEntry *fhe;
FrameHookEntry *fhenext;
for (fhe = first_hook; fhe; fhe = fhenext) {
fhenext = fhe->next;
if (fhe->Release)
fhe->Release(fhe->ctx);
av_free(fhe);
}
first_hook = NULL;
}

View File

@ -1,52 +0,0 @@
/*
* video processing hooks
* copyright (c) 2000, 2001 Fabrice Bellard
*
* 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
*/
#ifndef AVFORMAT_FRAMEHOOK_H
#define AVFORMAT_FRAMEHOOK_H
#warning VHOOK is deprecated. Please help finishing libavfilter instead of wasting your time writing new filters for this crappy filter system.
/*
* Prototypes for interface to .so that implement a video processing hook
*/
#include "libavcodec/avcodec.h"
/* Function must be called 'Configure' */
typedef int (FrameHookConfigure)(void **ctxp, int argc, char *argv[]);
typedef FrameHookConfigure *FrameHookConfigureFn;
extern FrameHookConfigure Configure;
/* Function must be called 'Process' */
typedef void (FrameHookProcess)(void *ctx, struct AVPicture *pict, enum PixelFormat pix_fmt, int width, int height, int64_t pts);
typedef FrameHookProcess *FrameHookProcessFn;
extern FrameHookProcess Process;
/* Function must be called 'Release' */
typedef void (FrameHookRelease)(void *ctx);
typedef FrameHookRelease *FrameHookReleaseFn;
extern FrameHookRelease Release;
int frame_hook_add(int argc, char *argv[]);
void frame_hook_process(struct AVPicture *pict, enum PixelFormat pix_fmt, int width, int height, int64_t pts);
void frame_hook_release(void);
#endif /* AVFORMAT_FRAMEHOOK_H */

View File

@ -1,531 +0,0 @@
/*
* 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 <gsbarbieri@yahoo.com.br>
*
* 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 "libavformat/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 = 1;
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 nested 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;
}
}

View File

@ -1,382 +0,0 @@
/*
* 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 "libavformat/avformat.h"
#include "libavformat/framehook.h"
#include "libavcodec/dsputil.h"
#include "libswscale/swscale.h"
#undef fprintf
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 = 1;
ci->dir = av_strdup("/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) {
av_log(NULL, AV_LOG_ERROR, "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:
av_log(NULL, AV_LOG_ERROR, "Unrecognized argument '%s'\n", argv[optind]);
return -1;
}
}
av_log(NULL, AV_LOG_INFO, "Fish detector configured:\n");
av_log(NULL, AV_LOG_INFO, " 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);
av_log(NULL, AV_LOG_INFO, " 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
av_log(NULL, AV_LOG_DEBUG, "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)
av_log(NULL, AV_LOG_DEBUG, "(%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)
av_log(NULL, AV_LOG_INFO, "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);
if (!fwrite(buf, width * height * 3, 1, f))
av_log(ctx, AV_LOG_ERROR, "Couldn't write to PPM file %s\n", fname);
fclose(f);
}
av_free(buf);
ci->next_pts = pts + ci->min_interval;
}
}
}
}

View File

@ -1,493 +0,0 @@
/*
* 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 "libavformat/framehook.h"
#include "libswscale/swscale.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#undef time
#include <sys/time.h>
#include <time.h>
#include <Imlib2.h>
#include "libavcodec/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;
const char *font = "LucidaSansDemiBold/16";
char *fp = getenv("FONTPATH");
char *color = 0;
FILE *f;
char *p;
const 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 = 1;
/* 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 '?':
av_log(NULL, AV_LOG_ERROR, "Unrecognized argument '%s'\n", argv[optind]);
return -1;
}
}
if (ci->eval_colors && !(ci->expr_R && ci->expr_G && ci->expr_B))
{
av_log(NULL, AV_LOG_ERROR, "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) {
av_log(NULL, AV_LOG_ERROR, "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)
{
av_log(NULL, AV_LOG_ERROR, "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) {
av_log(NULL, AV_LOG_ERROR, "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) {
av_log(NULL, AV_LOG_ERROR, "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];
const 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++;
}

View File

@ -1,116 +0,0 @@
/*
* 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 "libavformat/framehook.h"
#include "libswscale/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[])
{
av_log(NULL, AV_LOG_DEBUG, "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);
}

View File

@ -1,374 +0,0 @@
/*
* 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 "libavutil/avstring.h"
#include "libavformat/framehook.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#undef fprintf
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 ];
if (!pipe( input ))
return NULL;
if (!pipe( output ))
return NULL;
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;
if (!fgets( line, 3, in ))
return -1;
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);
}
}

View File

@ -1,655 +0,0 @@
/*
* 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 "libavutil/common.h"
#include "libavformat/avformat.h"
#include "libavformat/framehook.h"
#include "libswscale/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;
}
}
//
if (0 == ci->filename[0]) {
av_log(NULL, AV_LOG_ERROR, "Watermark: There is no filename specified.\n");
return -1;
}
av_register_all();
return get_watermark_picture(ci, 0);
}
/****************************************************************************
* For mode 0 (the original one)
****************************************************************************/
static 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;
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_meck;
uint32_t pixel;
uint32_t pixelm;
int tmp;
int thrR = ci->thrR;
int thrG = ci->thrG;
int thrB = ci->thrB;
if (pix_fmt != PIX_FMT_RGB32) {
int size;
size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
buf = av_malloc(size);
avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_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,
src_width, src_height, pix_fmt,
src_width, src_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, src_height,
picture1.data, picture1.linesize);
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_RGB32 is handled in endian specific manner.
for (y=0; y<src_height; y++) {
offs = y * (src_width * 4);
offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
for (x=0; x<src_width; x++) {
mpoffs = offsm + (((x * xm_size) / src_width) * 4);
p_pixel = (uint32_t *)&((pFrameRGB->data[0])[mpoffs]);
pixelm = *p_pixel;
p_pixel = (uint32_t *)&((pict->data[0])[offs]);
pixel = *p_pixel;
// pixelm = *((uint32_t *)&(pFrameRGB->data[mpoffs]));
pixel_meck = pixel & 0xff000000;
// R
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) - 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) - thrB;
if (tmp > 255) tmp = 255;
if (tmp < 0) tmp = 0;
pixel_meck |= (tmp << 0) & 0xff;
// test:
//pixel_meck = pixel & 0xff000000;
//pixel_meck |= (pixelm & 0x00ffffff);
*p_pixel = pixel_meck;
offs += 4;
} // foreach X
} // foreach Y
if (pix_fmt != PIX_FMT_RGB32) {
ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
src_width, src_height, PIX_FMT_RGB32,
src_width, src_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, src_height,
picture->data, picture->linesize);
}
av_free(buf);
}
/****************************************************************************
* For mode 1 (the original one)
****************************************************************************/
static 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_RGB32) {
int size;
size = avpicture_get_size(PIX_FMT_RGB32, src_width, src_height);
buf = av_malloc(size);
avpicture_fill(&picture1, buf, PIX_FMT_RGB32, src_width, src_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,
src_width, src_height, pix_fmt,
src_width, src_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, src_height,
picture1.data, picture1.linesize);
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_RGB32 is handled in endian specific manner.
for (y=0; y<src_height; y++) {
offs = y * (src_width * 4);
offsm = (((y * ym_size) / src_height) * 4) * xm_size; // offsm first in maskline. byteoffs!
for (x=0; x<src_width; x++) {
mpoffs = offsm + (((x * xm_size) / src_width) * 4);
p_pixel = (uint32_t *)&((pFrameRGB->data[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_RGB32) {
ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
src_width, src_height, PIX_FMT_RGB32,
src_width, src_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, src_height,
picture->data, picture->linesize);
}
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) {
Process1(ctx, picture, pix_fmt, src_width, src_height, pts);
} else {
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.
*
* This code follows the example on
* http://www.inb.uni-luebeck.de/~boehme/using_libavcodec.html
*
* 0 = ok, -1 = error
****************************************************************************/
int get_watermark_picture(ContextInfo *ci, int cleanup)
{
if (1 == ci->is_done && 0 == cleanup) return 0;
// Yes, *pFrameRGB arguments must be null the first time otherwise it's not good..
// This block is only executed the first time we enter this function.
if (0 == ci->pFrameRGB &&
0 == cleanup)
{
/*
* The last three parameters specify the file format, buffer size and format
* parameters; by simply specifying NULL or 0 we ask libavformat to auto-detect
* the format and use a default buffer size. (Didn't work!)
*/
if (av_open_input_file(&ci->pFormatCtx, ci->filename, NULL, 0, NULL) != 0) {
// Martin says this should not be necessary but it failed for me sending in
// NULL instead of file_iformat to av_open_input_file()
ci->i = strlen(ci->filename);
if (0 == ci->i) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() No filename to watermark vhook\n");
return -1;
}
while (ci->i > 0) {
if (ci->filename[ci->i] == '.') {
ci->i++;
break;
}
ci->i--;
}
ci->p_ext = &(ci->filename[ci->i]);
ci->file_iformat = av_find_input_format (ci->p_ext);
if (0 == ci->file_iformat) {
av_log(NULL, AV_LOG_INFO, "get_watermark_picture() attempt to use image2 for [%s]\n", ci->p_ext);
ci->file_iformat = av_find_input_format ("image2");
}
if (0 == ci->file_iformat) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Really failed to find iformat [%s]\n", ci->p_ext);
return -1;
}
// now continues the Martin template.
if (av_open_input_file(&ci->pFormatCtx, ci->filename, ci->file_iformat, 0, NULL)!=0) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open input file [%s]\n", ci->filename);
return -1;
}
}
/*
* This fills the streams field of the AVFormatContext with valid information.
*/
if(av_find_stream_info(ci->pFormatCtx)<0) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find stream info\n");
return -1;
}
/*
* As mentioned in the introduction, we'll handle only video streams, not audio
* streams. To make things nice and easy, we simply use the first video stream we
* find.
*/
ci->videoStream=-1;
for(ci->i = 0; ci->i < ci->pFormatCtx->nb_streams; ci->i++)
if(ci->pFormatCtx->streams[ci->i]->codec->codec_type==CODEC_TYPE_VIDEO)
{
ci->videoStream = ci->i;
break;
}
if(ci->videoStream == -1) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any video stream\n");
return -1;
}
ci->st = ci->pFormatCtx->streams[ci->videoStream];
ci->x_size = ci->st->codec->width;
ci->y_size = ci->st->codec->height;
// Get a pointer to the codec context for the video stream
ci->pCodecCtx = ci->pFormatCtx->streams[ci->videoStream]->codec;
/*
* OK, so now we've got a pointer to the so-called codec context for our video
* stream, but we still have to find the actual codec and open it.
*/
// Find the decoder for the video stream
ci->pCodec = avcodec_find_decoder(ci->pCodecCtx->codec_id);
if(ci->pCodec == NULL) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to find any codec\n");
return -1;
}
// Open codec
if(avcodec_open(ci->pCodecCtx, ci->pCodec)<0) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to open codec\n");
return -1;
}
// Hack to correct wrong frame rates that seem to be generated by some
// codecs
if (ci->pCodecCtx->time_base.den>1000 && ci->pCodecCtx->time_base.num==1)
ci->pCodecCtx->time_base.num=1000;
/*
* Allocate a video frame to store the decoded images in.
*/
ci->pFrame = avcodec_alloc_frame();
/*
* The RGB image pFrameRGB (of type AVFrame *) is allocated like this:
*/
// Allocate an AVFrame structure
ci->pFrameRGB=avcodec_alloc_frame();
if(ci->pFrameRGB==NULL) {
av_log(NULL, AV_LOG_ERROR, "get_watermark_picture() Failed to alloc pFrameRGB\n");
return -1;
}
// Determine required buffer size and allocate buffer
ci->numBytes = avpicture_get_size(PIX_FMT_RGB32, ci->pCodecCtx->width,
ci->pCodecCtx->height);
ci->buffer = av_malloc(ci->numBytes);
// Assign appropriate parts of buffer to image planes in pFrameRGB
avpicture_fill((AVPicture *)ci->pFrameRGB, ci->buffer, PIX_FMT_RGB32,
ci->pCodecCtx->width, ci->pCodecCtx->height);
}
// TODO loop, pingpong etc?
if (0 == cleanup)
{
// av_log(NULL, AV_LOG_DEBUG, "get_watermark_picture() Get a frame\n");
while(av_read_frame(ci->pFormatCtx, &ci->packet)>=0)
{
// Is this a packet from the video stream?
if(ci->packet.stream_index == ci->videoStream)
{
// Decode video frame
avcodec_decode_video(ci->pCodecCtx, ci->pFrame, &ci->frameFinished,
ci->packet.data, ci->packet.size);
// Did we get a video frame?
if(ci->frameFinished)
{
// Convert the image from its native format to RGB32
ci->watermark_convert_ctx =
sws_getCachedContext(ci->watermark_convert_ctx,
ci->pCodecCtx->width, ci->pCodecCtx->height, ci->pCodecCtx->pix_fmt,
ci->pCodecCtx->width, ci->pCodecCtx->height, PIX_FMT_RGB32,
sws_flags, NULL, NULL, NULL);
if (ci->watermark_convert_ctx == NULL) {
av_log(NULL, AV_LOG_ERROR,
"Cannot initialize the watermark conversion context\n");
return -1;
}
// img_convert parameters are 2 first destination, then 4 source
// sws_scale parameters are context, 4 first source, then 2 destination
sws_scale(ci->watermark_convert_ctx,
ci->pFrame->data, ci->pFrame->linesize, 0, ci->pCodecCtx->height,
ci->pFrameRGB->data, ci->pFrameRGB->linesize);
// Process the video frame (save to disk etc.)
//fprintf(stderr,"banan() New frame!\n");
//DoSomethingWithTheImage(ci->pFrameRGB);
return 0;
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&ci->packet);
}
ci->is_done = 1;
return 0;
} // if 0 != cleanup
if (0 != cleanup)
{
// Free the RGB image
av_freep(&ci->buffer);
av_freep(&ci->pFrameRGB);
// Close the codec
if (0 != ci->pCodecCtx) {
avcodec_close(ci->pCodecCtx);
ci->pCodecCtx = 0;
}
// Close the video file
if (0 != ci->pFormatCtx) {
av_close_input_file(ci->pFormatCtx);
ci->pFormatCtx = 0;
}
ci->is_done = 0;
}
return 0;
}
void parse_arg_file(const char *filename)
{
}