On 04/11/2010 03:51 AM, Stefano Sabatini wrote:
On date Saturday 2010-04-10 18:59:37 -0700, S.N. Hemanth Meenakshisundaram 
encoded:
      REGISTER_FILTER (VFLIP,       vflip,       vf);
+    REGISTER_FILTER (DRAWTEXT,    drawtext,    vf);
Alphabetical order.
Fixed.
Please add a table with the meaning of all the parameters. Check the
pad filter documentation to see how.
Added table to libavfilter.texi
[...]
Index: Makefile
===================================================================
  OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
+OBJS-$(CONFIG_DRAWTEXT_FILTER)               += vf_drawtext.o
Alphabetical order.
Fixed.
+ * vf_drawtext.c: print text over the screen
No need for this, just put the copyright, description may stay in the
@file doxy (also please mention libfreetype in this description).
Done
+#include<stdio.h>
+#include<stdlib.h>
These should be unnecessary.
Removed
+#undef time
Why undef time? (I know they were in the vhook filter, but there is
some reason for it?).
Without undef time, ffmpeg makefile rules throw a "time is forbidden for security reasons" error when building.
+#define ONE_HALF  (1<<  (SCALEBITS - 1))
+#define FIX(x)    ((int) ((x) * (1<<SCALEBITS) + 0.5))
These and scalebits are already defined in colorspace.h.
Removed redundant definitions already present in colorspace.h
+#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] ]; \
+}
These macros only work with YUV420P. Also please define them near to
where they're used.
Moved near place of use. Modified to work for other planar formats as well with hsub, vsub.
+typedef struct {
+    const AVClass *class;             /* To help parseutils to fill in 
structure */
Nit: use ///<  style for inline doxygen comments.

Nit: I prefer to lowcase the first letter if the text describing the
field is not a complete sentence (missing the verb like here), check
how it is done in main SVN filters.
Fixed.

Nit: "color"

fgcolor description should explicitely mention the term "ForeGround"
or you'll have a confused reader, also maybe these fields are not
necessary at all.
Having two variables names bcolor and bgcolor is horribly confusuing,
I suggest:
bgcolor_string
bgcolor
unexplicative name
All of these are fixed. Removed the input parameters to a separate structure (InParams) so that shorthand parameter names f, t, T etc can be used there as Michael suggested. The context only has values it requires throughout filter operation now and all its variables are descriptive.

+    int yMax, yMin;
y_max, y_min
Changed.
+    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;
av_opt_set_defaults2()
Using set_defaults2 now.
+    dtext->fcolor[0]=255;
+    dtext->fcolor[1]=128;
+    dtext->fcolor[2]=128;
+    dtext->bcolor[0]=0;
+    dtext->fcolor[1]=128;
+    dtext->fcolor[2]=128;
you can avoid to explicitely initialize these, use:
dtext->fgcolor_string = strdup("white");
dtext->bgcolor_string = strdup("black");
Done.
+    dtext->bg = 0;
+    dtext->outline = 0;
+    dtext->text_height = 0;
+
+    arg_cpy = av_strdup(args);
why this?
Removed. Initially thought set_options string would modify args.
+        av_log(dtext, AV_LOG_ERROR, "No font file provided! (-f filename)\n");
"-f filename" is misleading as we don't support that syntax anymore,
same below.
Fixed error messages.
+        if ((fp=fopen(dtext->file, "r")) == NULL) {
please use "fp = fopen" for increased readability, also !FOO is
preferred over FOO == NULL
Fixed.
+        }
+        else {
nit: "} else {" on the same line, here and below.
Changed.
+        av_log(dtext, AV_LOG_ERROR, "Could not load FreeType (error# %d).\n", 
err);
+        return AVERROR(EINVAL);
+    }
Try to use libfreetype error messages, they have a weird system for
setting errors,[...]
Done. Using a function for converting error messages. Is that a problem?
+    for (j = 0; (j<  height); j++)
+    for (i = 0; (i<  width); i++) {
+        SET_PIXEL(picture, yuv_color, (i+x), (y+j));
+    }
weird indent.

Also this can be done much faster with a memcpy, see how it is done in
vf_pad.c:draw_rectangle.
Using memset instead of memcpy. Works as required.
+    AVPicture *pic = (AVPicture *)&pic_ref->data;
This cast is not needed, you can just work on the AVFilterPicRef, and
avoid a dependancy on libavcodec.
Fixed. Using only PicRef now.
+    .description = "Draw text on top of video frames.",
please mention libfreetype in the description
Done.
Regards
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc

Also fixed alignment and style wherever non standard. Please review and let me know if there's anything else to be fixed. I will now work on fixing the corruption in vf_yadif. The complete diff for drawtext, documentation, Makefile/allfilters changes is attached below.
Index: allfilters.c
===================================================================
--- allfilters.c        (revision 5734)
+++ allfilters.c        (working copy)
@@ -37,6 +37,7 @@
     REGISTER_FILTER (ASPECT,      aspect,      vf);
     REGISTER_FILTER (CROP,        crop,        vf);
     REGISTER_FILTER (DRAWBOX,     drawbox,     vf);
+    REGISTER_FILTER (DRAWTEXT,    drawtext,    vf);
     REGISTER_FILTER (FIFO,        fifo,        vf);
     REGISTER_FILTER (FORMAT,      format,      vf);
     REGISTER_FILTER (FPS,         fps,         vf);
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,101 @@
  
  The default value of ``width'' and ``height'' is 0.
  
@@ -14,6 +14,87 @@
 +
 +Draw a box with x:y:width:height dimensions in a chosen color.
 +
+...@section drawtext
++
++Draws text string or text from specified file on top of video.
++
++It accepts the following parameters:
++f=<font file>:t=<text>:T=<text file>:x=<x offset>:y=<y offset>:
++c=<foreground color>:C=<background color>:s=<font size>:b=<draw box>:
++o=<draw outline>
++
++f and t are mandatory parameters.
++
++The description of the accepted parameters follows.
++
+...@table @option
+...@item f
++
++Specifies the font file to be used for drawing text. Path must be included.
++This parameter is mandatory.
++
+...@item t
++
++Specifies the text string to be drawn.
++This parameter is mandatory and will be used if no file with text is
++specified or if the file fails to open.
++
+...@item T
++
++Specifies a text file containing text to be drawn. Max size of 1024
++characters.
++
+...@item x, y
++
++Specify the offsets where text will be drawn within the video
++frame. Relative to the top/left border of the output image.
++
++The default value of ``x'' and ``y'' is 0.
++
+...@item s
++
++Specifies the font size to be used for drawing text.
++
++The default value of ``s'' is 16.
++
+...@item c
++
++Specifies the foreground color to be used for drawing text.
++Specify either as a string (e.g. black or as a hex value e.g. FF0000)
++
++The default value of ``c'' is black.
++
+...@item C
++
++Specifies the background color to be used for drawing box around text
++or drawing text outline based on option selected.
++Specify either as a string (e.g. black or as a 0xRRGGBB e.g. 0xFF0000)
++
++The default value of ``C'' is white.
++
+...@item b
++
++Specifies whether to draw a box around text using background color.
++Value should be either 1(enable) or 0(disable).
++
++The default value of ``b'' is 0.
++
+...@item o
++
++Specifies whether to draw an outline around text using background color.
++Value should be either 1(enable) or 0(disable).
++
++The default value of ``o'' is 0.
++
+...@end table
+...@example
++./ffmpeg -i in.avi -vfilters drawtext=f=FreeSerif.ttf:t=TestText
++            :x=100:y=50:s=24:c=Yellow:C=Red:b=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 +104,7 @@
  @section format
  
  Convert the input video to one of the specified pixel formats.
-@@ -156,6 +170,30 @@
+@@ -156,6 +251,30 @@
  
  will convert the input video to the format ``yuv420p''.
  
@@ -54,7 +135,7 @@
  @section noformat
  
  Force libavfilter not to use any of the specified pixel formats for the
-@@ -177,6 +215,98 @@
+@@ -177,6 +296,98 @@
  
  Pass the source unchanged to the output.
  
@@ -153,7 +234,7 @@
  @section scale
  
  Scale the input video to width:height and/or convert the image format.
-@@ -202,6 +332,24 @@
+@@ -202,6 +413,24 @@
  
  The default value of ``width'' and ``height'' is 0.
  
@@ -178,7 +259,7 @@
  @section slicify
  
  Pass the images of input video on to next video filter as multiple
-@@ -217,6 +365,19 @@
+@@ -217,6 +446,19 @@
  Adding this in the beginning of filter chains should make filtering
  faster due to better use of the memory cache.
  
@@ -198,7 +279,7 @@
  @section vflip
  
  Flip the input video vertically.
-@@ -229,6 +390,32 @@
+@@ -229,6 +471,32 @@
  
  Below is a description of the currently available video sources.
  
Index: Makefile
===================================================================
--- Makefile    (revision 5734)
+++ Makefile    (working copy)
@@ -18,6 +18,7 @@
 OBJS-$(CONFIG_ASPECT_FILTER)                 += vf_aspect.o
 OBJS-$(CONFIG_CROP_FILTER)                   += vf_crop.o
 OBJS-$(CONFIG_DRAWBOX_FILTER)                += vf_drawbox.o
+OBJS-$(CONFIG_DRAWTEXT_FILTER)               += vf_drawtext.o
 OBJS-$(CONFIG_FIFO_FILTER)                   += vf_fifo.o
 OBJS-$(CONFIG_FORMAT_FILTER)                 += vf_format.o
 OBJS-$(CONFIG_FPS_FILTER)                    += vf_fps.o
Index: vf_drawtext.c
===================================================================
--- vf_drawtext.c       (revision 0)
+++ vf_drawtext.c       (revision 0)
@@ -0,0 +1,510 @@
+/*
+ * copyright (c) 2010 S.N. Hemanth Meenakshisundaram
+ * Original vhook author: Gustavo Sverzut Barbieri <[email protected]>
+ * Libavfilter version  : S.N. Hemanth Meenakshisundaram <[email protected]>
+ *
+ * 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 "libavcodec/colorspace.h"
+#include "libavutil/pixdesc.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
+
+typedef struct {
+    unsigned char *text;            ///< text to be drawn
+    char *file;                     ///< file with text to be drawn
+    unsigned int x;                 ///< x position to start drawing text
+    unsigned int y;                 ///< y position to start drawing text
+    unsigned char bgcolor[3];       ///< foreground color in YUV
+    unsigned char fgcolor[3];       ///< background/Box color in YUV
+    short int draw_box;             ///< 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
+    int advance[256];
+    int bitmap_left[256];
+    int bitmap_top[256];
+    unsigned int glyphs_index[256];
+    int hsub, vsub;                 ///< chroma subsampling values
+} DrawTextContext;
+
+typedef struct {
+    const AVClass *class;
+    unsigned char *f;
+    unsigned char *t;
+    char *T;
+    char *c;
+    char *C;
+    unsigned int x;
+    unsigned int y;
+    unsigned int s;
+    short int b;
+    short int o;
+} InParams;
+
+#define OFFSET(x) offsetof(InParams, x)
+
+static const AVOption inparams_options[]= {
+{"f", "set f", OFFSET(f), FF_OPT_TYPE_STRING, 0,  CHAR_MIN, CHAR_MAX },
+{"t", "set t", OFFSET(t), FF_OPT_TYPE_STRING, 0,  CHAR_MIN, CHAR_MAX },
+{"T", "set T", OFFSET(T), FF_OPT_TYPE_STRING, 0,  CHAR_MIN, CHAR_MAX },
+{"c", "set c", OFFSET(c), FF_OPT_TYPE_STRING, 0,  CHAR_MIN, CHAR_MAX },
+{"C", "set C", OFFSET(C), FF_OPT_TYPE_STRING, 0,  CHAR_MIN, CHAR_MAX },
+{"b", "set b", OFFSET(b), FF_OPT_TYPE_INT,    0,         0,        1 },
+{"o", "set o", OFFSET(o), FF_OPT_TYPE_INT,    0,         0,        1 },
+{"s", "set s", OFFSET(s), 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 *inparams_get_name(void *ctx)
+{
+    return "inparams";
+}
+
+static const AVClass inparams_class = {
+    "InParams",
+    inparams_get_name,
+    inparams_options
+};
+
+static int query_formats(AVFilterContext *ctx)
+{
+    /* FIXME : Supports only YUV420P now. Add support for other formats */
+    enum PixelFormat pix_fmts[] = {
+        PIX_FMT_YUV420P, PIX_FMT_YUV444P, PIX_FMT_YUV422P,
+        PIX_FMT_YUV411P, PIX_FMT_YUV410P,
+        PIX_FMT_YUV440P, PIX_FMT_NONE
+    };
+
+    avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
+    return 0;
+}
+
+#undef __FTERRORS_H__
+#define FT_ERROR_START_LIST {
+#define FT_ERRORDEF(e, v, s) { (e), (s) },
+#define FT_ERROR_END_LIST { 0, NULL } };
+
+struct ft_error
+{
+    int err;
+    char *err_msg;
+} ft_errors[] =
+#include FT_ERRORS_H
+
+static const char *ft_err_msg(int err)
+{
+    const struct ft_error *fterr;
+
+    for (fterr = ft_errors; fterr->err_msg != NULL; fterr++)
+        if (fterr->err == err)
+            return fterr->err_msg;
+
+    return "Unknown Freetype Error";
+}
+
+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 y_max, y_min;
+    FT_BBox bbox;
+    DrawTextContext *dtext = ctx->priv;
+    InParams *in = av_malloc(sizeof(InParams));
+
+    in->class = &inparams_class;
+    av_opt_set_defaults2(in, 0, 0);
+    in->c = av_strdup("black");
+    in->C = av_strdup("white");
+
+    if (av_set_options_string(in, args, "=", ":") < 0) {
+        av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", 
args);
+        goto fail;
+    }
+    dtext->text = in->t;
+    dtext->file = in->T;
+    dtext->draw_box = in->b;
+    dtext->outline = in->o;
+    dtext->x = in->x;
+    dtext->y = in->y;
+
+    if (!in->f || *(in->f) == 0) {
+        av_log(ctx, AV_LOG_ERROR, "No font file provided! (=f:filename)\n");
+        goto fail;
+    }
+
+    if (!in->t || *(in->t) == 0) {
+        av_log(ctx, AV_LOG_ERROR, "No text provided (=t:text)\n");
+        goto fail;
+    }
+
+    if (in->T && *(in->T) != 0) {
+        FILE *fp;
+        if (!(fp = fopen(in->T, "r"))) {
+            av_log(ctx, AV_LOG_INFO, "WARNING: The file could not be opened.\
+                   Using text provided with =t switch: %s", in->T);
+        } else {
+            fclose(fp);
+            file_valid = 1;
+        }
+    }
+
+    if ((in->c) && (av_parse_color(rgba, in->c, ctx) != 0)) {
+        av_log(ctx, AV_LOG_ERROR, "Invalid foreground color: '%s'.\n", in->c);
+        goto fail;
+    }
+    dtext->fgcolor[0] = RGB_TO_Y(rgba[0], rgba[1], rgba[2]);
+    dtext->fgcolor[1] = RGB_TO_U(rgba[0], rgba[1], rgba[2], 0);
+    dtext->fgcolor[2] = RGB_TO_V(rgba[0], rgba[1], rgba[2], 0);
+
+    if ((in->C) && (av_parse_color(rgba, in->C, ctx) != 0)) {
+        av_log(ctx, AV_LOG_ERROR, "Invalid background color: '%s'.\n", in->C);
+        goto fail;
+    }
+
+    dtext->bgcolor[0] = RGB_TO_Y(rgba[0], rgba[1], rgba[2]);
+    dtext->bgcolor[1] = RGB_TO_U(rgba[0], rgba[1], rgba[2], 0);
+    dtext->bgcolor[2] = RGB_TO_V(rgba[0], rgba[1], rgba[2], 0);
+
+    if ((err = FT_Init_FreeType(&(dtext->library))) != 0) {
+        av_log(ctx, AV_LOG_ERROR, "Could not load FreeType (%s).\n", 
ft_err_msg(err));
+        goto fail;
+    }
+
+    if ((err = FT_New_Face( dtext->library, in->f, 0, &(dtext->face) )) != 0) {
+        av_log(ctx, AV_LOG_ERROR, "Could not load face: %s  (%s).\n", in->f, 
ft_err_msg(err));
+        goto fail;
+    }
+    if ((err = FT_Set_Pixel_Sizes( dtext->face, 0, in->s)) != 0) {
+        av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels 
(%s).\n", in->s, ft_err_msg(err));
+        goto fail;
+    }
+
+    dtext->use_kerning = FT_HAS_KERNING(dtext->face);
+
+    /* load and cache glyphs */
+    y_max = -32000;
+    y_min =  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 */
+
+        dtext->bitmaps[c]     = dtext->face->glyph->bitmap;
+        dtext->bitmap_left[c] = dtext->face->glyph->bitmap_left;
+        dtext->bitmap_top[c]  = dtext->face->glyph->bitmap_top;
+        dtext->advance[c]     = dtext->face->glyph->advance.x >> 6;
+
+        err = FT_Get_Glyph( dtext->face->glyph, &(dtext->glyphs[c]) );
+        if (err) continue;  /* ignore errors */
+        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 > y_max)
+          y_max = bbox.yMax;
+        if (bbox.yMin < y_min)
+          y_min = bbox.yMin;
+    }
+
+    dtext->text_height = y_max - y_min;
+    dtext->baseline = y_max;
+
+    return 0;
+
+fail:
+    av_free(in->f);
+    av_free(in->c);
+    av_free(in->C);
+    return AVERROR(EINVAL);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    DrawTextContext *dtext = ctx->priv;
+    av_freep(&dtext->text);
+    av_freep(&dtext->file);
+    FT_Done_Face(dtext->face);
+    FT_Done_FreeType(dtext->library);
+}
+
+static int config_input(AVFilterLink *link)
+{
+    DrawTextContext *dtext = link->dst->priv;
+    const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[link->format];
+    dtext->hsub = pix_desc->log2_chroma_w;
+    dtext->vsub = pix_desc->log2_chroma_h;
+    return 0;
+}
+
+#define SET_PIXEL(pic_ref, yuv_color, x, y, hsub, vsub) { \
+    pic_ref->data[0][ (x) + (y)*pic_ref->linesize[0] ] = yuv_color[0]; \
+    pic_ref->data[1][ ((x >> hsub) + (y >> vsub)*pic_ref->linesize[1]) ] = 
yuv_color[1]; \
+    pic_ref->data[2][ ((x >> hsub) + (y >> vsub)*pic_ref->linesize[2]) ] = 
yuv_color[2]; \
+}
+
+#define GET_PIXEL(pic_ref, yuv_color, x, y, hsub, vsub) { \
+    yuv_color[0] = pic_ref->data[0][ (x) + (y)*pic_ref->linesize[0] ]; \
+    yuv_color[1] = pic_ref->data[1][ (x >> hsub) + (y >> 
vsub)*pic_ref->linesize[1] ]; \
+    yuv_color[2] = pic_ref->data[2][ (x >> hsub) + (y >> 
vsub)*pic_ref->linesize[2] ]; \
+}
+
+static inline void draw_glyph(AVFilterPicRef *pic_ref, FT_Bitmap *bitmap, 
unsigned int x,
+                              unsigned int y, unsigned int width, unsigned int 
height,
+                              unsigned char yuv_fgcolor[3], unsigned char 
yuv_color[3],
+                              short int outline, int hsub, int vsub)
+{
+    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 pic_ref (destination) */
+                GET_PIXEL(pic_ref, dpixel, (c+x), (y+r), hsub, vsub);
+  
+                /* pixel in the glyph bitmap (source) */
+                spixel = bitmap->buffer[r*bitmap->pitch +c/8] & (0x80>>(c%8));
+
+                if (spixel)
+                    memcpy(dpixel, yuv_fgcolor, 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(pic_ref, yuv_color, (c+x-1), (y+r), 
hsub, vsub);
+                    } else if ( in_glyph && !spixel ) {
+                    /* right border detected */
+                        in_glyph = 0;
+                        /* 'draw' right pixel border */
+                        memcpy(dpixel, yuv_color, 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(pic_ref, yuv_color, (c+x), (y+r-1), 
hsub, vsub);
+
+                        /* bottom border detection */
+                        if ((r+1 < height) && (! 
bitmap->buffer[(r+1)*bitmap->pitch +c/8] & (0x80>>(c%8))))
+                            /* draw bottom border */
+                            SET_PIXEL(pic_ref, yuv_color, (c+x), (y+r+1), 
hsub, vsub);
+                    }
+                }
+                SET_PIXEL(pic_ref, dpixel, (c+x), (y+r), hsub, vsub);
+            }
+        }
+    }
+}
+
+static inline void drawbox(AVFilterPicRef *pic_ref, unsigned int x, unsigned 
int y,
+            unsigned int width, unsigned int height, unsigned char 
yuv_color[3], int hsub, int vsub)
+{
+    int i, plane;
+    uint8_t *p;
+
+    for (plane = 0; plane < 3 && pic_ref->data[plane]; plane++) {
+        int hsub1 = plane == 1 || plane == 2 ? hsub : 0;
+        int vsub1 = plane == 1 || plane == 2 ? vsub : 0;
+
+        p = pic_ref->data[plane] + (y >> vsub1) * pic_ref->linesize[plane] + 
(x >> hsub1);
+        for (i = 0; i < (height >> vsub1); i++) {
+            memset(p, yuv_color[plane], (width >> hsub1));
+            p += pic_ref->linesize[plane];
+        }
+    }
+}
+
+static void draw_text(AVFilterContext *ctx, AVFilterPicRef *pic_ref, int 
width, int height)
+{
+    DrawTextContext *dtext = ctx->priv;
+    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"))) {
+            text = dtext->text;
+            av_log(ctx, AV_LOG_INFO, "WARNING: The file could not be opened.\
+                   Using text provided with -t switch");
+        } 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(ctx, AV_LOG_INFO, "WARNING: The file could not be read.\
+                       Using text provided with -t switch");
+            }
+            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];
+    }
+    y += dtext->text_height;
+    if (str_w_max == 0)
+        str_w_max = str_w;
+    if (dtext->draw_box) {
+        /* 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;
+
+        av_log(ctx, AV_LOG_ERROR, "Entry : %d, %d \n", y, dtext->text_height);
+        /* Draw Background */
+        drawbox( pic_ref, dtext->x, dtext->y, str_w_max, y-dtext->y,
+                 dtext->bgcolor, dtext->hsub, dtext->vsub );
+    }
+
+    /* 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( pic_ref,
+                    &(dtext->bitmaps[ c ]),
+                    pos[i].x,
+                    pos[i].y,
+                    width,
+                    height,
+                    dtext->fgcolor,
+                    dtext->bgcolor,
+                    dtext->outline,
+                    dtext->hsub,
+                    dtext->vsub );
+
+        /* increment pen position */
+        x += slot->advance.x >> 6;
+    }
+}
+
+static void end_frame(AVFilterLink *link)
+{
+    AVFilterLink *output = link->dst->outputs[0];
+    AVFilterPicRef *pic_ref = link->cur_pic;
+
+    draw_text(link->dst, pic_ref, 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, requires libfreetype 
library.",
+    .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}},
+};
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc

Reply via email to