# drawtext¶

doc

https://ffmpeg.org/ffmpeg-filters.html#drawtext-1

## Minimal example¶

Text expansion

If the fontconfig support is disabled, or if you don’t want to care of the fontconfig (or if you aren’t familiar with it), you must specify fontfile, so the most minimalistic example for you is:

[me@host: ~]$ffplay -f lavfi "color=white:s=160x90,loop=-1:size=2" \ > -vf "drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:text=aaa'" [me@host: ~]$
[me@host: ~]$# specify fontsize [me@host: ~]$ ffplay -f lavfi "color=white:s=160x90,loop=-1:size=2" \
> -vf "drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=60:text=aaa'"


The fontfile parameter needs to be passed the full path to the font file, and if your environment is Windows it contains a colon, so the colon needs to be escaped.

ImageFont Module (Python Pillow examples)

Colons that affect the parsing of the entire filter must be escaped anyway:

[me@host: ~]$ffplay -f lavfi "color=white:s=800x450,loop=-1:size=2" -vf "drawtext=\ > 'fontfile=c\:/Windows/Fonts/courbd.ttf:\ > text=the special character \: is required to be escaped'"  Besides, because of the text expansion specification, the special character “%” associated with it is also required to be escaped (unless the parameter expansion is none): [me@host: ~]$ ffplay -f lavfi "color=white:s=800x450,loop=-1:size=2" \
> -vf "drawtext=\
> 'fontfile=c\:/Windows/Fonts/courbd.ttf:text=the special characters \\\% \
> is also required to be escaped'"
[me@host: ~]$ffplay -f lavfi "color=white:s=800x450,loop=-1:size=2" \ > -vf "drawtext=\ > 'fontfile=c\:/Windows/Fonts/courbd.ttf:text=the special characters % \ > is also required to be escaped\ > :expansion=none'"  Note Note that in the current case, you need three backslashes, as you also need an escape related to the shell (Bourne-shell). If you have trouble understanding shell expansion rules, consider using set -x for enabling trace (and set +x for disabling trace). If the escaping text is complex, consider using textfile instead of text parameter: [me@host: ~]$ cat > txt.txt
the special character :, and \% are required to be escaped
[me@host: ~]$ffplay -f lavfi "color=white:s=800x450,loop=-1:size=2" -vf "drawtext=\ > 'fontfile=c\:/Windows/Fonts/courbd.ttf:textfile=txt.txt'"  #! /bin/sh ffplay "Pexels Videos 1457810.mp4" -vf "\ drawtext=' fontfile=c\:/Windows/Fonts/comic.ttf: fontsize=120: fontcolor=white: x=100:y=100: text=%{localtime \: \%Y / \%m / \%d \%H \\\\\\: \%M \\\\\\: \%S} '"  #! /bin/sh trap 'rm -f dt.txt' 0 1 2 3 15 cat << __END__ > dt.txt %{localtime : \%Y / \%m / \%d \%H \: \%M \: \%S} __END__ # ffplay "Pexels Videos 1457810.mp4" -vf "\ drawtext=' fontfile=c\:/Windows/Fonts/comic.ttf: fontsize=120: fontcolor=white: x=100:y=100: textfile=dt.txt '"  This will reduce the need for escape a bit. ### To enable default font fallback and the font option¶ : To enable default font fallback and the font option you need to configure FFmpeg with --enable-libfontconfig. Even if ffmpeg is “Windows builds”, --enable-libfontconfig is true, but its distribution doesn’t contain fonts.conf. The most minimal fonts.conf looks like this: fonts.conf <?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> <dir>./</dir> <dir>../fonts</dir> <dir>./fonts</dir> <dir>~/.fonts</dir> <dir>WINDOWSFONTDIR</dir> <!-- for Windows --> <cachedir>WINDOWSTEMPDIR_FONTCONFIG_CACHE</cachedir> <!-- for Windows --> <cachedir>~/.fontconfig</cachedir> </fontconfig>  For the official distribution Windows version build, for example if you put ffmpeg on c:/Program Files/ffmpeg-3.3.2-win64-shared, this file seems to work if put in c:/Program Files/ffmpeg-3.3.2-win64-shared/bin/fonts/. For the Unix family, especially if you intend to rely on a package manager, it will probably install the right one in the right place. Otherwise, you can probably know by reading the fontconfig manual. If you have set up fonts.conf like this (with –enable-libfontconfig enabled), you can use font parameter like this: #! /bin/sh pref="basename$0 .sh"

ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex "
[0:v]
drawtext='font=sans-serif:fontsize=90:x=20:y=20:

text=The quick brown fox jumps over a lazy dog.
Sphinx of black quartz, judge my vow.'
" "${pref}.mp4"  Perhaps only Windows users need to write system-wide fonts.conf themselves. If you really want to write, it is better to copy from official example little by little and add to the above minimal stuff: <?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <!-- /etc/fonts/fonts.conf file to configure system font access --> <fontconfig> <!-- Font directory list --> <dir>./</dir> <dir>../fonts</dir> <dir>./fonts</dir> <dir>~/.fonts</dir> <dir>WINDOWSFONTDIR</dir> <!-- Font cache directory list --> <cachedir>WINDOWSTEMPDIR_FONTCONFIG_CACHE</cachedir> <cachedir>~/.fontconfig</cachedir> <!-- Alias well known font names to available TrueType fonts. These substitute TrueType faces for similar Type1 faces to improve screen appearance. --> <alias> <family>Times</family> <prefer><family>Times New Roman</family></prefer> <default><family>serif</family></default> </alias> <alias> <family>Helvetica</family> <prefer><family>Arial</family></prefer> <default><family>sans</family></default> </alias> <alias> <family>Courier</family> <prefer><family>Courier New</family></prefer> <default><family>monospace</family></default> </alias> </fontconfig>  This will allow you to write for example: #! /bin/sh pref="basename$0 .sh"

ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex "
[0:v]
drawtext='
font=Times:
fontsize=90:x=20:y=20:

text=The quick brown fox jumps over a lazy dog.
Sphinx of black quartz, judge my vow.'
" "${pref}.mp4"  Or you can use the family name of font (neither an alias nor a filename): #! /bin/sh pref="basename$0 .sh"

ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex "
[0:v]
drawtext='
font=MS Gothic:
fontsize=90:x=20:y=20:

text=The quick brown fox jumps over a lazy dog.
Sphinx of black quartz, judge my vow.'
" "${pref}.mp4"  For the relationship between font family names and file names, for example see ImageFont Module (Python Pillow examples). (In Windows, you may be able to see it by opening “Properties” in Explorer.) Note Note that giving a base name as shown below will not be what you expect: #! /bin/sh pref="basename$0 .sh"

ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex "
[0:v]
drawtext='
fontfile=cour.ttf:
fontsize=90:x=20:y=20:

text=The quick brown fox jumps over a lazy dog.
Sphinx of black quartz, judge my vow.'
" "${pref}.mp4"  #### Using third party fonts¶ You can use any font as long as it is a true type font. Consider using the one included with your TexLive installation. Not limited to this, non-Windows fonts are often stored in structured directories: [me@host: ~]$ find /c/texlive/2015/texmf-dist/fonts/truetype -type f
... (snip) ...
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeMono.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeMonoBold.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeMonoBoldOblique.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeMonoOblique.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSans.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSansBold.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSansBoldOblique.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSansOblique.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSerif.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSerifBold.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSerifBoldItalic.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/gnu-freefont/FreeSerifItalic.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipaexg.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipaexm.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipag.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipagp.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipam.ttf
/c/texlive/2015/texmf-dist/fonts/truetype/public/ipaex/ipamp.ttf
... (snip) ...


This is very painful if you have to write their full path each time you use them, so you should use fontconfig. You can write it like this:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- /etc/fonts/fonts.conf file to configure system font access -->
<fontconfig>

<!-- Font directory list -->
<dir>./</dir>
<dir>../fonts</dir>
<dir>./fonts</dir>
<dir>~/.fonts</dir>
<dir>WINDOWSFONTDIR</dir>

<dir>c:/texlive/2015/texmf-dist/fonts/truetype</dir>

<!-- Font cache directory list -->
<cachedir>WINDOWSTEMPDIR_FONTCONFIG_CACHE</cachedir>
<cachedir>~/.fontconfig</cachedir>

<!--
Alias well known font names to available TrueType fonts.
These substitute TrueType faces for similar Type1
faces to improve screen appearance.
-->
<alias>
<family>Times</family>
<prefer><family>Times New Roman</family></prefer>
<default><family>serif</family></default>
</alias>
<alias>
<family>Helvetica</family>
<prefer><family>Arial</family></prefer>
<default><family>sans</family></default>
</alias>
<alias>
<family>Courier</family>
<prefer><family>Courier New</family></prefer>
<default><family>monospace</family></default>
</alias>

</fontconfig>


Then, if you want to use ipaexg.ttf, you can:

#! /bin/sh
pref="basename $0 .sh" ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex " [0:v] drawtext=' font=IPAexGothic: fontsize=90:x=20:y=20: text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


BTW, on Windows, it is better to know that you can select truetype fonts in Explorer, right-click, and Install’ to deploy to c:/Windows/Fonts (in terms of fontconfig, WINDOWSFONTDIR), and then you can use them just like any other system font. (However, there seems to be no ways of batch operation, so it would be troublesome if the number of font files is large.)

## Newline, and tab¶

A line break as a value for the “text” parameter or as a character in a file specified in “textfile” behaves as you expect:

[me@host: ~]$ffmpeg -y -filter_complex \ > "color=white:s=160x90,loop=-1:size=2,drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=60:text=aaa > bbb'" -r 1/1 -t 1 newline_in_drawtext.png  [me@host: ~]$ cat > txt.txt
A line break as a value for the "text" parameter or
as a character in a file specified in "textfile"
behaves as you expect:
[me@host: ~]$ffmpeg -y -filter_complex \ > "color=white:s=960x135,loop=-1:size=2,drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=30:\ > textfile=txt.txt'" -r 1/1 -t 1 newline_in_drawtext2.png  The same is true for tab codes, but in some cases you may need to control how many spaces to replace with the “tabsize” parameter: [me@host: ~]$ cat > html_sample.txt
<html>
<body>
<div>
Indented text by tab.
</div>
</body>
</html>
[me@host: ~]$ffmpeg -filter_complex \ > "color=white:s=480x270,loop=-1:size=2,\ > drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=30:\ > textfile=html_sample.txt'" -r 1/1 -t 1 newline_in_drawtext3.png [me@host: ~]$ ffmpeg -filter_complex \
> "color=white:s=480x270,loop=-1:size=2,\
> drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=30:\
> textfile=html_sample.txt:tabsize=2'" -r 1/1 -t 1 newline_in_drawtext4.png


## Text position¶

the example of overlay

The position of the text can be specified by “x” and “y”:

#! /bin/sh
ffmpeg -y -filter_complex "
color=white:s=1280x720,loop=-1:size=2,
drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=50:text=hello:
x=100:y=100'
" -t 30 drawtext_xy.mp4


As with “overlay”, you can use expressions including timestamps for x and y of drawtext:

#! /bin/sh
ffmpeg -y -filter_complex "
color=white:s=1280x720,loop=-1:size=2,
drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf:fontsize=50:text=hello:
x=(sin(t)+1)/2*(W-tw):y=(cos(t/0.625)+1)/2*(H-th)'
" -t 30 drawtext_use_expr_in_xy.mp4


## color, box, border, and shadow¶

### fontcolor, fontcolor_expr¶

fontcolor:

The color to be used for drawing fonts. For the syntax of this option, check the (ffmpeg-utils)”Color” section in the ffmpeg-utils manual.

The default value of fontcolor is “black”.

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex " [0:v] drawtext='fontfile=c\:/Windows/Fonts/comic.ttf:fontsize=90:x=20:y=20: fontcolor=white@0.2: text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


fontcolor_expr:

String which is expanded the same way as text to obtain dynamic fontcolor value. By default this option has empty value and is not processed. When this option is set, it overrides fontcolor option.

IMO, the design of fontcolor_expr is a bit ridiculous. You might think that what should we do is color calculations as 24-bit or 32-bit values (I thought so). However, for fontcolor_expr, you must pass “a legal string as the fontcolor argument string”. In other words, “we must calculate a hexadecimal string by calculation”. Therefore, not only calculations but also “hexadecimal digitization of numerical values” is almost indispensable for this purpose:

changing the alpha value by time
#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex " [0:v] drawtext='fontfile=c\:/Windows/Fonts/comic.ttf:fontsize=90:x=20:y=20: fontcolor_expr= 0x5090FF%{eif\: mod(t * 100, 255) \: x \: 2}: text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


Although the knowledge of “we can do it in this way” is not worthless, but it is not easy to use. If you know the other ways of doing the same thing and you adopt it, it would become “easy to maintain” code, I think.

### box, boxborderw, boxcolor, line_spacing¶

box:

Used to draw a box around text using the background color. The value must be either 1 (enable) or 0 (disable). The default value of box is 0.

boxborderw:

Set the width of the border to be drawn around the box using boxcolor. The default value of boxborderw is 0.

boxcolor:

The color to be used for drawing box around text. For the syntax of this option, check the (ffmpeg-utils)”Color” section in the ffmpeg-utils manual.

The default value of boxcolor is “white”.

line_spacing:

Set the line spacing in pixels of the border to be drawn around the box using box. The default value of line_spacing is 0.

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -filter_complex " color=0xAFAFAF:s=1280x720,loop=-1:size=2, trim=0:6,setpts=PTS-STARTPTS, drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontcolor=yellow: fontsize=45: x=50:y=620: box=1: boxcolor=blue: boxborderw=5: line_spacing=32: text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


### borderw, bordercolor¶

bordercolor:

Set the color to be used for drawing border around text. For the syntax of this option, check the (ffmpeg-utils)”Color” section in the ffmpeg-utils manual.

The default value of bordercolor is “black”.

borderw:

Set the width of the border to be drawn around the text using bordercolor. The default value of borderw is 0.

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -filter_complex " color=0xAFAFAF:s=1280x720,loop=-1:size=2, trim=0:6,setpts=PTS-STARTPTS, drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontcolor=yellow: fontsize=45: x=50:y=620: bordercolor=blue: borderw=5: text=The quick brown fox jumps over a lazy dog.' " "${pref}.mp4"


The color to be used for drawing a shadow behind the drawn text. For the syntax of this option, check the (ffmpeg-utils)”Color” section in the ffmpeg-utils manual.

The default value of shadowcolor is “black”.

The x and y offsets for the text shadow position with respect to the position of the text. They can be either positive or negative values. The default value for both is “0”.

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -filter_complex " color=0xAFAFAF:s=1280x720,loop=-1:size=2, trim=0:6,setpts=PTS-STARTPTS, drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontcolor=yellow: fontsize=45: x=50:y=620: shadowcolor=blue: shadowx=5:shadowy=-5: text=The quick brown fox jumps over a lazy dog.' " "${pref}.mp4"


### alpha¶

alpha:

Draw the text applying alpha blending. The value can be a number between 0.0 and 1.0. The expression accepts the same variables x, y as well. The default value is 1. Please see fontcolor_expr.

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex " [0:v] drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontsize=70:x=50:y=50: fontcolor=white: shadowcolor=blue:shadowx=20:shadowy=20: box=1:boxcolor=0xAAAAAA:boxborderw=32: bordercolor=black:borderw=5: alpha=mod(t / 15, 1): text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


Note

Specifying alpha affects the whole text drawing (eg the color of the border). If this is not what you want, give an alpha for each color:

#! /bin/sh
pref="basename $0 .sh" # ffmpeg -y -i "Pexels Videos 1457810.mp4" -filter_complex " [0:v] drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontsize=70:x=50:y=50: fontcolor=white@0.5: shadowcolor=blue:shadowx=20:shadowy=20: text=The quick brown fox jumps over a lazy dog. Sphinx of black quartz, judge my vow.' " "${pref}.mp4"


## Text expansion¶

doc

Text expansion

Bad news. The “text expansion” provided by drawtext is extremely limited, and probably can not do most of what you want to do.

The most noticeable limitation is that ‘%{metadata : …}’ only shows frame metadata. So, even if the target video has “title” metadata at the global level, the following will not work:

[me@host: ~]$ffprobe -hide_banner yourvideo.mp4 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'yourvideo.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 title : whats going on date : 2011 ... (snip) ... [me@host: ~]$ ffplay yourvideo.mp4 -vf "
[me@host: ~]$ffplay yourvideo.mp4 -vf " > metadata=mode=print,drawtext='font=monospace:fontcolor=white:fontsize=60:text=%{metadata\: title}'"  For a few examples where “metadata” can be used, see drawtext with signalstats, drawtext, drawgraph, blackframe, freezedetect. So, “metadata” is maybe disappointing for you, but instead, only the display method of time code related (which is definitely the biggest demand) is quite satisfactory: Draw the timestamp of the current frame with the format “hms”. [me@host: ~]$ ffplay yourvideo.mp4 -vf "
> drawtext='font=monospace:fontcolor=white:fontsize=60:text=%{pts \: hms}'"

Draw the timestamp of the current frame with the format “gmtime”.
[me@host: ~]$ffplay yourvideo.mp4 -vf " > drawtext='font=monospace:fontcolor=white:fontsize=40: > text=%{pts \: gmtime}'" [me@host: ~]$ ffplay yourvideo.mp4 -vf "
> drawtext='font=monospace:fontcolor=white:fontsize=40:
> text=%{pts \: gmtime \: 0}'"
[me@host: ~]$ffplay yourvideo.mp4 -vf " > drawtext='font=monospace:fontcolor=white:fontsize=40: > text=%{pts \: gmtime \: 0 \: \%Y-\%m-\%d \%H\\\\\\:\%M\\\\\\:\%S}'"  Draw the time at which the filter is running, expressed in the local time zone. [me@host: ~]$ ffplay -f lavfi "color=s=1920x1080,loop=-1:size=2" -vf "
> drawtext='font=monospace:fontcolor=white:fontsize=200:text=%{localtime}'"
[me@host: ~]$ffplay -f lavfi "color=s=1920x1080,loop=-1:size=2" -vf " > drawtext='font=monospace:fontcolor=white:fontsize=200: > text=%{localtime \: \%Y-\%m-\%d \%H\\\\\\:\%M\\\\\\:\%S}'"  The function “expr” may be used for debugging purposes: [me@host: ~]$ ffplay -f lavfi "
> color=white:s=ntsc:d=10,
> drawtext='
>     fontsize=40:
>     text=%{expr\:(st(0, 4 - mod(t * PI, 8));(sin(ld(0)) / ld(0)) * sin(220 * 2 * PI * t))}'"


Note that constants what you can use depends on when the evaluation of the expression is performed as the official documentation mentions, furthermore, the constants that can be used here are only those that can be used with the “x” and “y” parameters of “drawtext”:

[me@host: ~]$# If you want to display the evaluated value of the following: [me@host: ~]$ ffplay video.mkv -vf "geq='lum=min(lum(X,Y) + T*7, 255):cr=cr(X,Y):cb=cb(X,Y)'"
[me@host: ~]$# But you can't do: [me@host: ~]$ ffplay -f lavfi "
> color=white:s=ntsc:d=10,drawtext='fontsize=40:text=%{expr\:(min(lum(X,Y) + T*7, 255))}'"


It’s not surprising that you can’t use “lum”, but in this example, “T” would disappoint you. If your only goal is to display the evaluation results of an expression, consider using print:

[me@host: ~]$ffplay video.mkv -vf "geq='lum=print(min(lum(X,Y) + T*7, 255)):cr=cr(X,Y):cb=cb(X,Y)'"  see also global metadata, etc. ## textfile’ and reload=1’¶ Only if you use textfile, you can use the parameter reload: If set to 1, the textfile will be reloaded before each frame. Be sure to update it atomically, or it may be read partially, or even fail. Warning For ffmpeg which is not the latest, reload=1 seems to hang up easily. At least version 3.3.2 of Windows hangs up frequently. Use the latest (4.1 at the moment). You can use this to create something like a video that follows an ever-changing text file, such as a log of something: Python script example to create a text file that changes every 5 seconds # -*- coding: utf-8 -*- from __future__ import unicode_literals import io import time import random with io.open('words', encoding='latin-1') as fi: words = fi.read().split('\n') while True: r1 = random.randint(0, len(words) - 1) r2 = random.randint(0, len(words) - 1) txt = words[r1] + '\n x\n' + words[r2] + '\n' with io.open('choice.txt', 'w') as fo: fo.write(txt) time.sleep(5)  Ffplay follows text files that the above python script keeps updating #! /bin/sh exec 2> /dev/null ffplay -f lavfi "color=white:s=960x540,loop=-1:size=2" \ -vf "drawtext='fontfile=c\:/Windows/Fonts/courbd.ttf: fontsize=60: x=30:y=30: textfile=choice.txt: reload=1"  Watch on youtube.com Let me show you a slightly more complicated example. The following Python script periodically updates random words into the file excursion.txt’ based on Google search. (However, it is for Japanese people.): excursion.py # -*- coding: utf-8 -*- from __future__ import unicode_literals try: # python 3 from urllib.request import build_opener from http.client import ResponseNotReady from html.parser import HTMLParser from urllib.parse import urlencode except ImportError: # python 2 from urllib2 import build_opener from httplib import ResponseNotReady from HTMLParser import HTMLParser from urllib import urlencode import sys import io from io import StringIO import ssl import time import re import random from subprocess import Popen, PIPE import unicodedata import httplib2 # https://pypi.python.org/pypi/httplib2 from bs4 import BeautifulSoup # https://pypi.python.org/bs4/ # class _GoogleHtmlResExtractor(HTMLParser): def __init__(self): HTMLParser.__init__(self) self._states = 0 self.data = [] def handle_starttag(self, tag, attrs): d = dict(attrs) if tag == 'p': self._states = 1 elif tag == 'a' and self._states == 1: if d['href'] != '/': self.data.append({ "href": "https://www.google.com" + d['href'] }) self._states = 2 def handle_endtag(self, tag): if tag == 'a': self._states = 0 def handle_data(self, data): if self._states == 2: self.data[-1]["data"] = data.strip() # def query(*query_keywords): user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)' url = "https://www.google.com/search" data = urlencode({ "q": " ".join(query_keywords).encode("utf-8"), }) opener = build_opener() opener.addheaders = [('User-Agent', user_agent)] res = opener.open(url + "?" + data) html = res.read().decode("utf-8") parser = _GoogleHtmlResExtractor() parser.feed(html) return parser.data # httplib2 wrapper class httplib2inst(object): def __init__(self, cache_dir=".cache"): self._inst = httplib2.Http(cache_dir) def get(self, url): retry = 20 while retry >= 0: try: return self._inst.request(url, "GET") except (ResponseNotReady, ssl.SSLEOFError): retry -= 1 time.sleep(8) except (httplib2.ServerNotFoundError, ssl.CertificateError): break return None, None # --- main --- if __name__ == '__main__': opnr = httplib2inst() qs = sys.stdin.readline().strip() if hasattr(qs, "decode"): qs = qs.decode("mbcs") srcs = set() while True: for lst in query(qs): headers, contents = opnr.get(lst["href"]) if headers: try: soup = BeautifulSoup(StringIO(contents.decode("utf-8", "replace")), "lxml") except: continue [x.extract() for x in soup.findAll('script')] [x.extract() for x in soup.findAll('iframe')] body = soup.find("body") if not body: continue p = Popen( ["c:/Program Files (x86)/MeCab/bin/mecab", "-b", "%d" % (2**24)], shell=False, stdin=PIPE, stdout=PIPE) stdoutdata, stderrdata = p.communicate( input=body.text.encode("utf-8")) for line in re.split(r"\r?\n", stdoutdata.decode("utf-8", "replace")): if "\t" not in line: continue word, _, inf = line.partition("\t") if re.match(r"[ -/:-@[-{-~]+", word): continue if re.match(r"[a-zA-Z]+", word): continue word = unicodedata.normalize('NFKC', word) if re.match(r"[a-zA-Z]+", word): continue typ = inf.split(",")[:2] if typ[0] in ("記号", "接続詞", "連体詞") or \ "助" in typ[0] or "動" in typ[0] or \ typ[1] in ("非自立", "代名詞", "数"): continue srcs.add(word) sels = list(srcs) random.shuffle(sels) for i in range(0, len(sels) // 20 * 20, 20): s = "\n".join(["{}{}{}{}"] * 5).format( *sels[i:i+20+1]).encode("utf-8") with io.open("excursion.txt", "wb") as fo: fo.write(s) time.sleep(10) time.sleep(1) qs = sels[-1]  This time, let’s draw it by changing the color little by little at random positions: play_chosen.sh #! /bin/sh exec 2> /dev/null "c:/Program Files/ffmpeg-4.1.1-win64-shared/bin/ffplay" \ -f lavfi "color=white:s=1120x630,loop=-1:size=2" \ -vf "drawtext='fontfile=c\:/Windows/Fonts/HGRSMP.TTF: fontsize=40: fontcolor_expr=0x\ %{eif \: mod(t*10, 128) \: x \: 2}\ %{eif \: mod(t*30, 255) \: x \: 2}\ %{eif \: mod(t*50, 255) \: x \: 2}: x=if(eq(mod(t\,5)\,0)\,rand(50\,(w-text_w-150))\,x): y=if(eq(mod(t\,5)\,0)\,rand(50\,(h-text_h-150))\,y): textfile=excursion.txt:reload=1"  Here’s a video showing how this works: Watch on youtube.com ## with sendcmd¶ For example, you may want to change the font over time. In such cases, you can use sendcmd (rather than drawtext itself). #! /bin/bash # # This example is for Windows. # ( exec > dtcmd.cmd t=0 for fon in (cd /c/Windows/Fonts/ ; ls *.tt[fc]) ; do echo "\${t}-$((${t} + 5)) [enter] drawtext reinit 'fontfile=c\\:/Windows/Fonts/${fon}';" t=$((\${t} + 5))
done
)
#
"ffplay" \
-f lavfi "color=white:s=960x540,loop=-1:size=2" \
-vf "sendcmd=f=dtcmd.cmd,drawtext='fontsize=40:x=50:y=50:fontcolor=blue:\
text=The quick brown fox jumps over a lazy dog.'"
`