On 04/09/2010 04:18 PM, Stefano Sabatini wrote:
User-documentation for filters should be put in doc/libavfilter.texi,
also I don't like this syntax, possibly we should try hard at giving a
consistent interface to the user, so we should either use
PARAM-1:PARAM-2:...:PARAM-N either use libavutil/parseutils.c (which
still depends on opt.c so I don't believe Michail won't accept this to
be included in the main repo, but that's not a problem for now).
Done. Moved documentation to libavfilter.texi, syntax is now of the form :
./ffplay -vfilters
drawtext=font=FreeSerif.ttf:text=TestText:file=tfil.txt:x=100:y=50:size=24:fgcolor=Yellow:bgcolor=Red:outline=1:bg=1
in.avi
Is this too descriptive?
please avoid unnecessary headers inclusion
Removed 3 unnecessary headers.
+
+#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)
use the macro defined in "libavcodec/colorspace.h"
Done.
+#define COPY_3(dst,src) { \
+ dst[0]=src[0]; \
+ dst[1]=src[1]; \
+ dst[2]=src[2]; \
+}
I don't think this is necessary, a simple memcpy should be enough.
Done.
please use DrawTextContext, no need to use obfuscated names, chars are
cheapers these days.
Also all the variables should be documented when their meaning is not
obvious.
Changed to DrawText, added comments for variables.
Are you sure all these formats are supported?
Only YUV pixel formats supported for now. Updated query_formats.
av_parse_color()
Done. Removed the local parse_color function.
General stylistic note: use K&R style,
if (cond) {
...
}
style is preferred, plain_variable is preferred over camelVariable
style, try also the patcheck tool for checking the most common trivial
errors.
Fixed style.
+ av_log(NULL, AV_LOG_ERROR, "Could not load FreeType (error# %d).\n",
err);
Use the filter context for logging.
Fixed.
+ return -1;
I'd like to start to use meaningful error codes in libavfilter, use
AVERROR(EINVAL) in this case.
Done. It looks like invalid value and unknown error both are EINVAL. Is
this OK?
All this can be greatly simplified and made more robust using
parseutils.c.
Using parseutils function now.
[...]
+AVFilter avfilter_vf_drawtext = {
+ .name = "drawtext",
missing long name.
Added description.
Also added FIXME for Unicode support later on as Victor suggested.
Tested font/background colors/sizes, wrap-around text, displaying from
file, drawing box and outline around text, ran valgrind.
Attached is the diff of vf_drawtext.c, allfilters.c, libavfilter.texi
and libavfilter Makefile. Diff is with soc/libavfilter repo and not
trunk. However configure.diff has configure script changes with respect
to trunk.
Currently freetype requires complete font path to be specified. Should
we add code for retrieving FONTPATH and appending to font file name or
should the user be expected to provide it?
Please let me know if anything else needs to be fixed.
Ronald,
I will use just memcpy instead of fast_memcpy. Is that OK?
Thanks,
Index: allfilters.c
===================================================================
--- allfilters.c (revision 5734)
+++ allfilters.c (working copy)
@@ -54,6 +54,7 @@
REGISTER_FILTER (SPLIT, split, vf);
REGISTER_FILTER (TRANSPOSE, transpose, vf);
REGISTER_FILTER (VFLIP, vflip, vf);
+ REGISTER_FILTER (DRAWTEXT, drawtext, vf);
REGISTER_FILTER (BUFFER, buffer, vsrc);
REGISTER_FILTER (MOVIE, movie, vsrc);
Index: diffs/03_libavfilter_doc.diff
===================================================================
--- diffs/03_libavfilter_doc.diff (revision 5734)
+++ diffs/03_libavfilter_doc.diff (working copy)
@@ -1,8 +1,8 @@
-Index: doc/libavfilter.texi
+Index: libavfilter.texi
===================================================================
---- doc/libavfilter.texi (revision 22749)
-+++ doc/libavfilter.texi (working copy)
-@@ -139,6 +139,20 @@
+--- libavfilter.texi (revision 22749)
++++ libavfilter.texi (working copy)
+@@ -139,6 +139,30 @@
The default value of ``width'' and ``height'' is 0.
@@ -14,6 +14,16 @@
+
+Draw a box with x:y:width:height dimensions in a chosen color.
+
+...@section drawtext
++
+...@example
++./ffmpeg -i in.avi -vfilters drawtext=font=FreeSerif.ttf:text=TestText
++ :x=100:y=50:size=24:fgcolor=Yellow:bgcolor=Red:bg=1 out.avi
+...@end example
++
++Draw 'TestText' with font FreeSerif of size 24 at (100,50), text color is
yellow,
++background color is red, draw a box around text.
++
+...@section fifo
+
+...@example
@@ -23,7 +33,7 @@
@section format
Convert the input video to one of the specified pixel formats.
-@@ -156,6 +170,30 @@
+@@ -156,6 +180,30 @@
will convert the input video to the format ``yuv420p''.
@@ -54,7 +64,7 @@
@section noformat
Force libavfilter not to use any of the specified pixel formats for the
-@@ -177,6 +215,98 @@
+@@ -177,6 +225,98 @@
Pass the source unchanged to the output.
@@ -153,7 +163,7 @@
@section scale
Scale the input video to width:height and/or convert the image format.
-@@ -202,6 +332,24 @@
+@@ -202,6 +342,24 @@
The default value of ``width'' and ``height'' is 0.
@@ -178,7 +188,7 @@
@section slicify
Pass the images of input video on to next video filter as multiple
-@@ -217,6 +365,19 @@
+@@ -217,6 +375,19 @@
Adding this in the beginning of filter chains should make filtering
faster due to better use of the memory cache.
@@ -198,7 +208,7 @@
@section vflip
Flip the input video vertically.
-@@ -229,6 +390,32 @@
+@@ -229,6 +400,32 @@
Below is a description of the currently available video sources.
Index: Makefile
===================================================================
--- Makefile (revision 5734)
+++ Makefile (working copy)
@@ -35,6 +35,7 @@
OBJS-$(CONFIG_SPLIT_FILTER) += vf_split.o
OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o
OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o
+OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o
OBJS-$(CONFIG_BUFFER_FILTER) += vsrc_buffer.o
OBJS-$(CONFIG_MOVIE_FILTER) += vsrc_movie.o
Index: vf_drawtext.c
===================================================================
--- vf_drawtext.c (revision 0)
+++ vf_drawtext.c (revision 0)
@@ -0,0 +1,494 @@
+/*
+ * vf_drawtext.c: print text over the screen
+ * Original vhook author: Gustavo Sverzut Barbieri <[email protected]>
+ * Libavfilter version : S.N. Hemanth Meenakshisundaram <[email protected]>
+ *
+ * Example usage with all available options:
+ * ./ffplay -vfilters drawtext=font=FreeSerif.ttf:text=TestText:file=tfil.txt:\
+ * x=100:y=50:size=24:fgcolor=Yellow:bgcolor=Red:outline=1:bg=1 in.avi
+ *
+ * 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
+ */
+
+/**
+ * @file libavfilter/vf_drawtext.c
+ * video filter to draw text over screen
+ */
+
+#define MAXSIZE_TEXT 1024
+
+#include "avfilter.h"
+#include "parseutils.h"
+#include "libavutil/pixdesc.h"
+#include "libavcodec/colorspace.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#undef time
+#include <sys/time.h>
+#include <time.h>
+
+#include <ft2build.h>
+#include <freetype/config/ftheader.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+#define SCALEBITS 10
+#define DEF_DRAWTEXT_FONT_SZ 16
+#define MAX_DRAWTEXT_OPT 10
+#define ONE_HALF (1 << (SCALEBITS - 1))
+#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
+
+#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 {
+ const AVClass *class; /* To help parseutils to fill in
structure */
+ unsigned char *font; /* Font to be used for drawing text */
+ unsigned char *text; /* Text to be drawn */
+ char *file; /* File with text to be drawn */
+ char *fgcolor; /* Text color */
+ char *bgcolor; /* Background/Box colour */
+ unsigned int x; /* x position to start drawing text */
+ unsigned int y; /* y position to start drawing text */
+ unsigned int size; /* Font size to use */
+ unsigned char bcolor[3]; /* Text color in YUV */
+ unsigned char fcolor[3]; /* Background/Box color in YUV */
+ short int bg; /* Draw box around text - true or false
*/
+ short int outline; /* Draw outline in bg color around text
*/
+ int text_height; /* Height of a font symbol */
+ int baseline; /* Baseline to draw fonts from */
+ int use_kerning; /* Font kerning is used - true/false */
+ FT_Library library; /* Freetype font library handle */
+ FT_Face face; /* Freetype font face handle */
+ FT_Glyph glyphs[ 256 ]; /* Array holding glyphs of font */
+ FT_Bitmap bitmaps[ 256 ]; /* Array holding bitmaps of font */
+ /* Glyph bitmap dimensions */
+ int advance[ 256 ];
+ int bitmap_left[ 256 ];
+ int bitmap_top[ 256 ];
+ unsigned int glyphs_index[ 256 ];
+} DrawTextContext;
+
+#define OFFSET(x) offsetof(DrawTextContext, x)
+
+static const AVOption drawtext_options[]= {
+{"font", "set font", OFFSET(font), FF_OPT_TYPE_STRING, 0,
CHAR_MIN, CHAR_MAX },
+{"text", "set text", OFFSET(text), FF_OPT_TYPE_STRING, 0,
CHAR_MIN, CHAR_MAX },
+{"file", "set file", OFFSET(file), FF_OPT_TYPE_STRING, 0,
CHAR_MIN, CHAR_MAX },
+{"fgcolor", "set fgcolor", OFFSET(fgcolor), FF_OPT_TYPE_STRING, 0,
CHAR_MIN, CHAR_MAX },
+{"bgcolor", "set bgcolor", OFFSET(bgcolor), FF_OPT_TYPE_STRING, 0,
CHAR_MIN, CHAR_MAX },
+{"bg", "set bg", OFFSET(bg), FF_OPT_TYPE_INT, 0,
0, 1 },
+{"outline", "set outline", OFFSET(outline), FF_OPT_TYPE_INT, 0,
0, 1 },
+{"size", "set size", OFFSET(size), FF_OPT_TYPE_INT, 16,
1, 72 },
+{"x", "set x", OFFSET(x), FF_OPT_TYPE_INT, 0,
0, INT_MAX },
+{"y", "set y", OFFSET(y), FF_OPT_TYPE_INT, 0,
0, INT_MAX },
+{NULL},
+};
+
+static const char *drawtext_get_name(void *ctx)
+{
+ return "drawtext";
+}
+
+static const AVClass drawtext_class = {
+ "DrawTextContext",
+ drawtext_get_name,
+ drawtext_options
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+ /* FIXME : Supports only YUV now. Add RGB support */
+ enum PixelFormat pix_fmts[] = {
+ PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV420P,
+ PIX_FMT_YUV411P, PIX_FMT_YUV410P,
+ PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
+ PIX_FMT_YUV440P, PIX_FMT_YUVJ440P,
+ PIX_FMT_NONE
+ };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ unsigned short int c;
+ uint8_t rgba[4];
+ uint8_t err, file_valid = 0;
+ int yMax, yMin;
+ char *arg_cpy = NULL;
+ FT_BBox bbox;
+ DrawTextContext *dtext = ctx->priv;
+
+ dtext->class = &drawtext_class;
+ dtext->font = NULL;
+ dtext->text = NULL;
+ dtext->file = NULL;
+ dtext->fgcolor = NULL;
+ dtext->bgcolor = NULL;
+ dtext->x = dtext->y = 0;
+ dtext->size=DEF_DRAWTEXT_FONT_SZ;
+ dtext->fcolor[0]=255;
+ dtext->fcolor[1]=128;
+ dtext->fcolor[2]=128;
+ dtext->bcolor[0]=0;
+ dtext->fcolor[1]=128;
+ dtext->fcolor[2]=128;
+ dtext->bg = 0;
+ dtext->outline = 0;
+ dtext->text_height = 0;
+
+ arg_cpy = av_strdup(args);
+ if (av_set_options_string(dtext, arg_cpy, "=", ":") < 0) {
+ av_log(dtext, AV_LOG_ERROR, "Error parsing options string: '%s'\n",
args);
+ return AVERROR(EINVAL);
+ }
+
+ if (!dtext->font || *(dtext->font) == 0) {
+ av_log(dtext, AV_LOG_ERROR, "No font file provided! (-f filename)\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (!dtext->text || *(dtext->text) == 0) {
+ av_log(dtext, AV_LOG_ERROR, "No text provided (-t text)\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (dtext->file && *(dtext->file) != 0) {
+ FILE *fp;
+ if ((fp=fopen(dtext->file, "r")) == NULL) {
+ av_log(dtext, AV_LOG_INFO, "WARNING: The file could not be opened.\
+ Using text provided with -t switch: %s", dtext->text);
+ }
+ else {
+ fclose(fp);
+ file_valid = 1;
+ }
+ }
+
+ if ((dtext->fgcolor) && (av_parse_color(rgba, dtext->fgcolor, dtext) !=
0)) {
+ av_log(dtext, AV_LOG_ERROR, "Invalid foreground color: '%s'.\n",
dtext->fgcolor);
+ return AVERROR(EINVAL);
+ }
+ dtext->fcolor[0] = RGB_TO_Y(rgba[0], rgba[1], rgba[2]);
+ dtext->fcolor[1] = RGB_TO_U(rgba[0], rgba[1], rgba[2], 0);
+ dtext->fcolor[2] = RGB_TO_V(rgba[0], rgba[1], rgba[2], 0);
+
+ if ((dtext->bgcolor) && (av_parse_color(rgba, dtext->bgcolor, dtext) !=
0)) {
+ av_log(dtext, AV_LOG_ERROR, "Invalid background color: '%s'.\n",
dtext->bgcolor);
+ return AVERROR(EINVAL);
+ }
+
+ dtext->bcolor[0] = RGB_TO_Y(rgba[0], rgba[1], rgba[2]);
+ dtext->bcolor[1] = RGB_TO_U(rgba[0], rgba[1], rgba[2], 0);
+ dtext->bcolor[2] = RGB_TO_V(rgba[0], rgba[1], rgba[2], 0);
+
+ if ((err = FT_Init_FreeType(&(dtext->library))) != 0) {
+ av_log(dtext, AV_LOG_ERROR, "Could not load FreeType (error# %d).\n",
err);
+ return AVERROR(EINVAL);
+ }
+
+ if ((err = FT_New_Face( dtext->library, dtext->font, 0, &(dtext->face) ))
!= 0) {
+ av_log(dtext, AV_LOG_ERROR, "Could not load face: %s (error# %d).\n",
dtext->font, err);
+ return AVERROR(EINVAL);
+ }
+ if ((err = FT_Set_Pixel_Sizes( dtext->face, 0, dtext->size)) != 0) {
+ av_log(dtext, AV_LOG_ERROR, "Could not set font size to %d pixels
(error# %d).\n", dtext->size, err);
+ return AVERROR(EINVAL);
+ }
+
+ dtext->use_kerning = FT_HAS_KERNING(dtext->face);
+
+ /* load and cache glyphs */
+ yMax = -32000;
+ yMin = 32000;
+ /* FIXME : Supports only ASCII text now. Add Unicode support */
+ for (c=0; c <= 255; c++) {
+
+ if (!file_valid && !strrchr(dtext->text,(unsigned char)c))
+ continue;
+
+ /* Load char */
+ err = FT_Load_Char( dtext->face, (unsigned char) c, FT_LOAD_RENDER |
FT_LOAD_MONOCHROME );
+ if (err) continue; /* ignore errors */
+
+ /* Save bitmap */
+ dtext->bitmaps[c] = dtext->face->glyph->bitmap;
+ /* Save bitmap left */
+ dtext->bitmap_left[c] = dtext->face->glyph->bitmap_left;
+ /* Save bitmap top */
+ dtext->bitmap_top[c] = dtext->face->glyph->bitmap_top;
+ /* Save advance */
+ dtext->advance[c] = dtext->face->glyph->advance.x >> 6;
+ /* Save glyph */
+ err = FT_Get_Glyph( dtext->face->glyph, &(dtext->glyphs[c]) );
+ /* Save glyph index */
+ av_log(dtext, AV_LOG_ERROR, "c is %d\n", c);
+ dtext->glyphs_index[c] = FT_Get_Char_Index( dtext->face, (unsigned
char) c );
+
+ /* Measure text height to calculate text_height (or the maximum text
height) */
+ FT_Glyph_Get_CBox( dtext->glyphs[ c ], ft_glyph_bbox_pixels, &bbox );
+ if (bbox.yMax > yMax)
+ yMax = bbox.yMax;
+ if (bbox.yMin < yMin)
+ yMin = bbox.yMin;
+ }
+
+ dtext->text_height = yMax - yMin;
+ dtext->baseline = yMax;
+
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ DrawTextContext *dtext = ctx->priv;
+ av_freep(&dtext->font);
+ av_freep(&dtext->text);
+ av_freep(&dtext->file);
+ av_freep(&dtext->fgcolor);
+ av_freep(&dtext->bgcolor);
+ FT_Done_Face(dtext->face);
+ FT_Done_FreeType(dtext->library);
+}
+
+static int config_input(AVFilterLink *link)
+{
+ 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_fcolor[3], unsigned char yuv_bcolor[3], short
int outline)
+{
+ int r, c;
+ uint8_t 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)
+ memcpy(dpixel, yuv_fcolor, 3);
+
+ 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_bcolor, (c+x-1), (y+r));
+ }
+ else if ( in_glyph && !spixel ) {
+ /* right border detected */
+ in_glyph = 0;
+ /* 'draw' right pixel border */
+ memcpy(dpixel, yuv_bcolor, 3);
+ }
+
+ 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_bcolor, (c+x), (y+r-1));
+
+ /* bottom border detection */
+ if ((r+1 < height) && (!
bitmap->buffer[(r+1)*bitmap->pitch +c/8] & (0x80>>(c%8))))
+ /* draw bottom border */
+ SET_PIXEL(picture, yuv_bcolor, (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));
+ }
+}
+
+static void draw_text(DrawTextContext *dtext, AVPicture *picture, int width,
int height)
+{
+ FT_Face face = dtext->face;
+ FT_GlyphSlot slot = face->glyph;
+ FILE *fd = NULL;
+ unsigned char *text = dtext->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 (dtext->file) {
+ if ((fd = fopen(dtext->file, "r")) == NULL) {
+ text = dtext->text;
+ av_log(dtext, AV_LOG_INFO, "WARNING: The file could not be opened.\
+ Using text provided with -t switch: %s", strerror(errno));
+ }
+ else {
+ int l = fread(tbuff, sizeof(char), MAXSIZE_TEXT-1, fd);
+ if (l >= 0) {
+ tbuff[l] = 0;
+ text = tbuff;
+ }
+ else {
+ text = dtext->text;
+ av_log(dtext, AV_LOG_INFO, "WARNING: The file could not be
read.\
+ Using text provided with -t switch: %s",
strerror(errno));
+ }
+ fclose(fd);
+ }
+ }
+ else {
+ text = dtext->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 = dtext->x;
+ y = dtext->y;
+ for (i=0; i < size; i++) {
+ c = text[i];
+ /* kerning */
+ if ( (dtext->use_kerning) && (i > 0) && (dtext->glyphs_index[c]) ) {
+ FT_Get_Kerning(dtext->face, dtext->glyphs_index[text[i-1]],
+ dtext->glyphs_index[c], ft_kerning_default, &delta);
+ x += delta.x >> 6;
+ }
+
+ if (( (x + dtext->advance[ c ]) >= width ) || ( c == '\n' )) {
+ if (c != '\n')
+ str_w_max = width - dtext->x - 1;
+ y += dtext->text_height;
+ x = dtext->x;
+ }
+
+ /* save position */
+ pos[i].x = x + dtext->bitmap_left[c];
+ pos[i].y = y - dtext->bitmap_top[c] + dtext->baseline;
+ x += dtext->advance[c];
+ str_w +=dtext->advance[c];
+ }
+ if (y == 0)
+ y += dtext->text_height;
+ if (str_w_max == 0)
+ str_w_max = str_w;
+ if (dtext->bg) {
+ /* Check if it doesn't pass the limits */
+ if ( str_w_max + dtext->x >= width )
+ str_w_max = width - dtext->x - 1;
+ if ( y >= height )
+ y = height - 1 - 2*dtext->y;
+
+ /* Draw Background */
+ draw_box( picture, dtext->x, dtext->y, str_w_max, y - dtext->y,
dtext->bcolor );
+ }
+
+ /* Draw Glyphs */
+ for (i=0; i < size; i++) {
+ c = text[i];
+
+ /* skip '_' (consider as space) if text was specified in cmd line and
+ * skip new line char, just go to new line */
+ if (( (c == '_') && (text == dtext->text) ) || ( c == '\n' ) )
+ continue;
+
+ /* now, draw to our target surface */
+ draw_glyph( picture,
+ &(dtext->bitmaps[ c ]),
+ pos[i].x,
+ pos[i].y,
+ width,
+ height,
+ dtext->fcolor,
+ dtext->bcolor,
+ dtext->outline );
+
+ /* increment pen position */
+ x += slot->advance.x >> 6;
+ }
+}
+
+static void end_frame(AVFilterLink *link)
+{
+ DrawTextContext *context = link->dst->priv;
+ AVFilterLink *output = link->dst->outputs[0];
+ AVFilterPicRef *pic_ref = link->cur_pic;
+ AVPicture *pic = (AVPicture *)&pic_ref->data;
+
+ draw_text(context, pic, pic_ref->w, pic_ref->h);
+
+ avfilter_draw_slice(output, 0, pic_ref->h, 1);
+ avfilter_end_frame(output);
+}
+
+AVFilter avfilter_vf_drawtext = {
+ .name = "drawtext",
+ .description = "Draw text on top of video frames.",
+ .priv_size = sizeof(DrawTextContext),
+ .init = init,
+ .uninit = uninit,
+
+ .query_formats = query_formats,
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer=
avfilter_null_get_video_buffer,
+ .start_frame =
avfilter_null_start_frame,
+ .end_frame = end_frame,
+ .config_props = config_input,
+ .min_perms = AV_PERM_WRITE |
+ AV_PERM_READ,
+ .rej_perms = AV_PERM_PRESERVE },
+ { .name = NULL}},
+ .outputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO, },
+ { .name = NULL}},
+};
Index: configure
===================================================================
--- configure (revision 22749)
+++ configure (working copy)
@@ -2695,6 +2695,12 @@
check_header sys/soundcard.h
check_header soundcard.h
+drawtext_filter_deps="freetype_freetype_h"
+drawtext_filter_extralibs="-lfreetype"
+
+check_header ft2build.h
+enabled drawtext_filter && check_lib2 FT_FREETYPE_H FT_Init_FreeType -lfreetype
+
enabled_any alsa_indev alsa_outdev && check_lib2 alsa/asoundlib.h
snd_pcm_htimestamp -lasound
enabled jack_indev && check_lib2 jack/jack.h jack_client_open -ljack
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc