Skip to content
streamneo.
Tools15 min read

How to Add a Logo and Scrolling Text to an FFmpeg YouTube Stream

Add a logo and scrolling text to an FFmpeg YouTube stream with overlay, drawtext, local checks and a careful YouTube preflight.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

A logo is added to an FFmpeg video with the overlay filter, while text is rendered with drawtext. Scrolling text is a timed position expression inside the filter graph, not a YouTube setting.

Before broadcasting, test the exact FFmpeg build, font, file paths, filter graph and encoder settings on the machine that will run the stream. A command copied from an example may need changes for your shell, input files, resolution, frame rate and YouTube ingest settings.

Prepare a transparent logo asset

Start with a logo file that has transparency, usually a PNG. Transparency matters because overlay places the logo image over the video; the transparent parts allow the programme underneath to remain visible. A JPEG normally has no transparent background, so it will appear as a rectangular image unless you prepare it differently.

Check the image before opening FFmpeg. Place it over a dark and a light background in an image editor or preview tool. This reveals white edges, an unwanted background colour or faint marks that may be hard to see on your desktop but obvious over moving video.

Give the file a simple path, such as:

/home/channel/assets/logo.png

On Windows, a path might look like:

C:/channel/assets/logo.png

Paths with spaces and punctuation can work, but they add another layer of quoting. For a first test, a short path containing ordinary letters, numbers and underscores is easier to troubleshoot. Keep the logo, font and text file in a directory you can back up with the rest of the channel assets.

The logo’s pixel dimensions should suit the output video. An image prepared for a large design canvas can cover a substantial part of a 720p stream even if it looks modest when viewed separately. If the logo is too large, scale it inside the filter graph rather than editing the original asset each time. Keeping the original file untouched lets you make a second version later.

For example, this adds a scale step before the logo reaches overlay:

[1:v]scale=240:-1[logo];[0:v][logo]overlay=10:H-h-10

The width becomes 240 pixels and the height is calculated to preserve the logo’s aspect ratio. That is only a starting value. Test the result at the actual output resolution and look at the logo while the video is moving. A logo that is clear on a still frame may compete with faces, subtitles or devotional artwork during playback.

The position 10:H-h-10 puts the logo ten pixels from the left and bottom edges. FFmpeg also supports expressions based on the main video and overlay dimensions, such as W-w-10 for the right edge. In a production stream, leave enough space for any captions or channel graphics that YouTube viewers may see around the video.

If you are building a long devotional, ambience or shop-information loop, decide whether the mark should stay in one corner for the entire programme. Moving it between scenes can make the channel look inconsistent and does not solve a logo that is simply too large. Make the asset readable first, then choose a quiet position.

Check that your FFmpeg build has the filters

Do not assume that every FFmpeg binary contains the same optional libraries. The overlay filter is needed for the image, and drawtext is needed for text. FFmpeg’s filter documentation says that drawtext requires a build configured with FreeType. Font fallback and the font option involve Fontconfig, while text shaping involves FriBidi; the current filter reference also lists HarfBuzz among the drawtext requirements.

Check the installed binary before constructing a long command:

ffmpeg -filters | grep -E 'overlay|drawtext'

On a Windows installation, use the equivalent filter listing command or inspect the output in the terminal. You can also ask FFmpeg for its version and configuration:

ffmpeg -version

Look for the filters in the listing and for the relevant configuration details in the version output. The exact presentation differs between builds. If drawtext is missing, installing a different build may be necessary. If the filter appears but fails when used, read the error carefully rather than changing several parts of the command at once.

The FFmpeg filters documentation is the primary reference for the options and expressions. Match the documentation to the FFmpeg version you are actually running. Examples found elsewhere may use options or syntax that your local build handles differently.

Test the font independently. A fontfile path must point to a real font file that the process can read. For example:

ls -l /home/channel/fonts/DejaVuSans.ttf

The command is only an example for a Unix-like system. On Windows, check the file in Explorer or use a PowerShell command. Do not copy /path/to/font.ttf into a live command and expect FFmpeg to find it. A missing font can stop the filter graph before any video reaches YouTube.

Keep a one-line message in a plain text file while testing:

LIVE FROM OUR CHANNEL

Using a file avoids much of the shell escaping needed for punctuation in an inline text= value. It also makes it easier to change the message without rewriting the filter graph. Store the file in a known location and confirm that its encoding is suitable for the characters you intend to display.

Place and size the logo with overlay

FFmpeg’s overlay filter combines a second video input with a main video input. The first input is normally your programme video and the second is the transparent logo. A minimal example is:

ffmpeg -i video.mp4 -i logo.png \
  -filter_complex "[0:v][1:v]overlay=10:H-h-10" \
  output.mp4

The expression keeps the logo ten pixels from the left and bottom edges. Here, H is the main video height and h is the overlay height. For the lower-right corner, use:

overlay=W-w-10:H-h-10

W and H refer to the main video dimensions, while w and h refer to the logo dimensions. This is more useful than hard-coding a position when the same filter graph may be used with more than one output size.

To scale the logo first, label the logo stream and pass the scaled result to the overlay:

ffmpeg -i video.mp4 -i logo.png \
  -filter_complex "[1:v]scale=240:-1[logo];[0:v][logo]overlay=W-w-16:H-h-16" \
  output.mp4

This example uses a 240-pixel width and a sixteen-pixel margin. Neither value is a universal recommendation. The correct size depends on the logo’s detail, the output resolution, the channel’s visual style and whether viewers watch on a phone.

If the logo has a transparent background but appears with a black box, inspect the asset and the pixel format first. If it looks soft, start with a larger source image and scale it down once. Enlarging a small logo often makes edges look poor. If the logo is cropped, check its dimensions and the position expression before changing the video itself.

The logo operation changes the video pixels. It does not select YouTube’s codec, bitrate, keyframe interval or audio format. Keep those concerns separate: first make a correct composited video frame, then encode it for the intended live destination.

Add fixed text with drawtext

drawtext renders text over the video. A simple filter looks like this:

drawtext=fontfile=/home/channel/fonts/DejaVuSans.ttf:textfile=/home/channel/assets/message.txt:fontcolor=white:fontsize=32:y=H-th-24:x=24

fontfile selects the font, textfile supplies the words, fontcolor sets the colour, fontsize sets the text size, and the x and y expressions position the text. In this example, H-th-24 places the text near the bottom with a margin based on its rendered height.

For a darker background behind the letters, add a box:

drawtext=fontfile=/home/channel/fonts/DejaVuSans.ttf:textfile=/home/channel/assets/message.txt:fontcolor=white:fontsize=32:box=1:[email protected]:boxborderw=10:y=H-th-24:x=24

A semi-transparent box can improve readability over clouds, water, video detail or bright temple artwork. It can also cover more of the programme than expected, so inspect it over several scenes. A thin outline or shadow may be preferable when a solid box feels too prominent.

The text file is particularly helpful when the message contains colons, commas, apostrophes or other characters that interact with filter and shell syntax. FFmpeg parses a filter graph through several layers: the filter’s options, the filtergraph itself and the shell that passes the command. A character that is harmless in a text file may need escaping when embedded directly in text=.

If you do use inline text, test a very short message first. Keep the command in a script once it works, and note which shell runs it. A command copied from a Bash example will not necessarily have the same quoting behaviour in PowerShell or Command Prompt.

The order of filters matters. This chain puts the logo on first and text on top:

[0:v][1:v]overlay=W-w-16:H-h-16,
drawtext=fontfile=/home/channel/fonts/DejaVuSans.ttf:textfile=/home/channel/assets/message.txt:fontcolor=white:fontsize=32:y=H-th-24:x=24

If you want the logo to cover the text instead, put drawtext before overlay. Usually, text intended as a channel-wide notice should remain visible, so placing it after the logo is the clearer choice.

Create a scrolling text expression

A scrolling message is just text whose horizontal position changes with time. FFmpeg’s documentation shows a right-to-left example using an expression based on t, the elapsed time:

drawtext="fontsize=15:fontfile=FreeSerif.ttf:textfile=LONG_LINE:y=h-line_h:x=-50*t"

The negative x value moves the text towards the left as time advances. The coefficient controls the speed. The documented font size is an example, not a suitable setting for every resolution. Test the message at the size and frame rate you will actually broadcast.

For a message that begins off the right edge, crosses the frame and then returns, use a wrapping expression. An illustrative form is:

drawtext=fontfile=/home/channel/fonts/DejaVuSans.ttf:textfile=/home/channel/assets/message.txt:fontcolor=white:fontsize=32:y=H-th-24:x=W-mod(80*t,W+tw)

Here, tw is the rendered text width. The expression changes the horizontal position over time and brings the message back into the cycle after it has travelled across the available distance. The 80 controls movement speed in this example. Change it after watching the result, rather than treating it as a standard value.

Expressions can become difficult to read once you add boxes, shadows, scaling and several text elements. Build the effect in stages. First display fixed text. Then make it move slowly. Then add the logo and any background box. If the final command fails, you can remove the newest stage and identify the part that introduced the problem.

A scrolling message should be short enough to understand while it passes. A devotional channel might use a brief programme label, while a local shop could display opening hours or a contact instruction. Long notices can become a moving wall that distracts from the stream. If the information is important, consider displaying it as fixed text or editing it into the source video instead.

The vertical expression also deserves a test. H-th-24 places the text near the bottom of the frame, but a lower-third graphic or YouTube player controls may compete visually with that area. Move it higher if the source content already uses the bottom edge. Check both the first appearance and the point where the message wraps, since an expression can look correct in the middle of the cycle but clip at the edges.

Choose built-in text or a prepared asset

drawtext is the practical choice when the wording, timing or position needs to change without opening an editor. A text file can be updated between runs, and a time expression can create a basic marquee without producing a separate animation. It also keeps the text tied to the filter graph, so you can change the font, colour and position alongside the rest of the stream setup.

A prepared text asset is better when the design needs exact typography, several languages, a logo lock-up or more elaborate animation. You might create a transparent video or image sequence containing a finished lower third, then feed it to overlay as another input. This moves typography out of FFmpeg, which can make a complicated design easier to preview.

The trade-off is maintenance. A prepared asset must match the video dimensions, frame rate and duration behaviour you expect. If the message changes every day, editing and replacing the asset may be slower than changing a text file. If the message must be translated into several scripts, check that the design tool and the playback pipeline preserve the characters correctly.

For simple channel identity, start with one logo and one text element. Add separate assets only when you can explain what each one contributes. More inputs and labels make the filter graph harder to inspect, and a long-running stream benefits from a command you can understand at a glance.

The same distinction applies to an entire always-on workflow. If you are using recorded videos rather than a camera, the guide on making a YouTube live stream from recorded videos on a low budget in India covers the wider setup decisions. If the machine running FFmpeg is not meant to stay on overnight, a cloud workflow can remove the need to keep your own computer powered on; StreamNeo turns an uploaded video into a YouTube stream and handles restarting when the broadcast drops.

Combine the filters without mixing up the settings

Once each part works independently, combine the logo and text. This is an illustrative starting point, not a command that has been run for every operating system or FFmpeg build:

ffmpeg -i video.mp4 -i logo.png \
  -filter_complex "[1:v]scale=240:-1[logo];[0:v][logo]overlay=16:H-h-16,drawtext=fontfile=/home/channel/fonts/DejaVuSans.ttf:textfile=/home/channel/assets/message.txt:fontcolor=white:fontsize=32:y=H-th-24:x=W-mod(80*t\\,W+tw)" \
  -c:v libx264 -preset veryfast -tune zerolatency -b:v 6000k -maxrate 6000k -bufsize 12000k \
  -g 60 -keyint_min 60 -sc_threshold 0 -pix_fmt yuv420p \
  -c:a aac -b:a 128k -ar 44100 \
  -f flv "rtmps://SERVER/STREAM_KEY"

The graph scales the logo, overlays it and then draws the scrolling text. The paths, server address and stream key are placeholders. The escaping shown may need adjustment for the shell you use. In particular, commas, colons, quotes and backslashes can be interpreted by more than one parser.

The encoder options after the filter graph are a separate concern. YouTube’s live encoder settings guidance currently lists H.264, H.265/HEVC and AV1 as supported video codec choices, along with CBR guidance, supported audio choices and keyframe recommendations. It also publishes bitrate guidance by codec, resolution and frame rate. Use the current table for the exact format you choose instead of copying values from a different stream.

For example, YouTube’s current guidance lists 5 Mbps as a recommended H.264 bitrate for 1080p30, and 17 Mbps as a recommended H.264 bitrate for 1080p60. These are YouTube recommendations for those entries, not measurements of your upload connection and not requirements created by the overlay or drawtext filters. A different resolution, frame rate or codec changes the relevant setting.

Do not let the logo’s size decide the bitrate. Overlay and drawtext alter the frames before encoding, while the chosen encoder settings control how those frames are compressed and sent. If you change from 720p to 1080p, or from one frame rate to another, revisit the complete YouTube encoder configuration.

Treat the stream key as a password. YouTube’s live stream settings guidance explains the stream URL and key used by an encoder. Keep both out of public scripts, screenshots and articles. If a key is exposed, replace it in YouTube Studio rather than assuming that obscurity will protect it.

Validate locally, then run the YouTube preflight

First produce a short local output with the same filter graph. You do not need to begin with a live broadcast. Use a short input or stop the test after enough time to see the logo enter, the text scroll and the message wrap. Watch for a missing font, a cropped logo, a frozen overlay, unreadable text, unexpected audio behaviour or an FFmpeg process that exits.

Run the test using the exact paths and shell that will be used for the overnight stream. A command can work in an interactive terminal and fail in a scheduled task because the working directory, permissions or environment differ. Use absolute paths where practical, and record the FFmpeg version that passed the test.

Check the output dimensions and frame rate independently of how the video looks in a player. A player may scale the picture or hide a mismatch. Confirm that the audio is present, that the output opens correctly and that the text remains visible across bright and dark sections of the source.

Then test the connection to YouTube without publishing a finished event prematurely. YouTube’s encoder setup guide describes entering the stream URL and key from YouTube Studio into the encoder. YouTube also recommends testing with movement and audio similar to the planned broadcast, then watching stream health and messages during the event.

Use an upload connection with enough headroom for the chosen bitrate rather than relying only on a brief speed result. Watch for dropped frames, buffering messages, audio drift and a filter process that stops after the input reaches its end. A local file that finishes will not automatically become an always-on channel. You need a loop, playlist, scheduled restart or another method appropriate to your source material.

Keep a simple preflight note for each channel:

Check What to confirm
Logo Transparent file, readable size, correct corner and no unwanted box
Filters overlay and drawtext appear in the local FFmpeg build
Font The exact font path is readable by the running process
Message Text file contains the intended wording and characters
Filter graph Logo, fixed text or scrolling text appear in the correct order
Output Resolution, frame rate, audio and pixel format match the plan
YouTube Current codec, bitrate, keyframe and ingest guidance has been checked
Connection Stream health and dropped-frame messages remain acceptable during a test

If a command fails, simplify it. Remove the scrolling expression and display fixed text. Remove the text and test the logo. Remove the logo and test the input and encoder. This isolates filter syntax from path problems and from YouTube connection problems.

For longer-running channels, document the working command and keep a copy of every asset it references. If you later replace a font or logo, repeat the local test. Small changes to a font path or image dimension can stop an otherwise reliable command.

If your wider problem is keeping a recorded programme connected after the source ends, the advice on keeping an OBS YouTube stream connected after a video playlist ends covers that failure mode. For an FFmpeg-based setup on a remote machine, running a YouTube livestream with FFmpeg on an Ubuntu VPS in India is the more relevant operational guide.

Before committing, compare the operating options on the pricing page. When the file and channel are ready, start free — 24-hour trial, no card.

FAQ

Can I add a logo without re-encoding the video?

No, not when you want the logo burned into the outgoing picture with overlay. FFmpeg must create new video frames containing both the source and the logo, so the video is encoded again. Audio may be copied or encoded separately depending on the command, but that does not remove the video processing.

Why does drawtext say that the filter or font is missing?

Your FFmpeg build may not include the libraries required by drawtext, or the font path may be wrong or unreadable. Check ffmpeg -filters, inspect the local build configuration and test the exact font path before changing the whole command.

Does the logo affect YouTube’s bitrate settings?

The logo and text change the video content before encoding, but they do not choose YouTube’s bitrate, codec, resolution or keyframe interval. Select those encoder settings from YouTube’s current guidance for the intended output and test the result on your connection.

Why does my scrolling text command work in one terminal but not another?

Shell quoting is part of the command. Colons, commas, quotes and backslashes can be interpreted by the shell, the filtergraph parser and drawtext in different ways. Use textfile, keep paths simple while testing and validate the command in the same shell and environment that will run the live stream.

YOU’VE REACHED THE END

Keep the ideas coming.

More guides, useful tools and a little help for your next broadcast.

Back to the journal ↗
YOUR NEXT READ

A little more to explore.

More Tools guides ↗ · All topics ↗