Skip to content
streamneo.
Setup Guides12 min read

How to Keep Frame Rate Constant When Looping Videos to YouTube with FFmpeg

Learn how FFmpeg input looping differs from constant-frame-rate output, how to choose a cadence and check the result before YouTube.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

To repeat a video with FFmpeg and keep a predictable frame rate, treat looping and output cadence as separate settings. -stream_loop repeats the input; when you re-encode, an output rate or CFR sync mode controls whether frames are duplicated or dropped to make the encoded output constant-rate.

Start by identifying the rate the source was intended to have, then preserve it unless your project has a reason to convert it. YouTube recommends encoding and uploading at the frame rate at which the content was recorded; it does not require every upload to use one universal rate.

Looping and frame-rate conversion are separate jobs

A video file contains frames, timestamps and usually one or more audio streams. Repeating the input tells FFmpeg to read that material again after it reaches the end. It does not, by itself, decide how frequently frames should appear in the output or make irregular input timing constant.

That distinction matters because “loop the video” and “make constant-frame-rate video” solve different problems. The former is about duration and repetition. The latter is about the relationship between frames and timestamps in the encoded output. One command can do both, but each part of the command has its own job.

FFmpeg’s -stream_loop is an input option. Put it before the -i it applies to. The -1 value means repeat indefinitely. For a finite repeat count, use the count you need; zero means no repetition. Consult the FFmpeg command-line documentation for the option’s placement and behaviour, since options are not interchangeable just because they appear in one command.

For whole-video repetition, -stream_loop is the direct choice. FFmpeg also has a video loop filter, which repeats selected frames in a filter chain. That can suit a short frame-level effect, such as holding or repeating a small section, but it is not the same operation as reading the entire input again. If you want a complete music visualiser or ambience video to start over at the end, use input looping rather than treating the filter as a general substitute.

The output may still need a cadence decision. A source that has regular timestamps at its intended rate may already be suitable. A variable-frame-rate source, a file with unusual timestamps, or an output you have chosen to convert may need a deliberate encoding and sync configuration. Do not infer that the loop option handles any of those cases.

Choose the source’s intended frame rate

First inspect the source rather than selecting a familiar-looking number by habit. FFmpeg tools can report stream details; look at the video stream’s reported frame rate and, where available, the average frame rate and timestamps. Those values can differ for variable-frame-rate material, so use context as well as a single displayed field: how the footage was recorded, how it plays, and whether the editor or camera project specifies a target rate.

YouTube’s recommended upload encoding settings say content should be encoded and uploaded at the same frame rate it was recorded. The page lists 24, 25, 30, 48, 50 and 60 fps as common rates, while noting other rates are acceptable. These are examples, not a requirement to convert a 25 fps recording to 30 fps or a 24 fps animation to 60 fps.

If the actual intended rate is 29.97 frames per second, represent it as a rational value such as 30000/1001, rather than rounding it to 30 without a reason. Similar fractional rates arise in video workflows. An inaccurate target can create unnecessary repeated or dropped frames, which may change motion or make timing less straightforward to troubleshoot.

For a devotional song recorded and edited at 25 fps, preserving 25 fps is normally the clearest starting point. For a 30 fps lofi visual loop, use 30 only if that is the source’s intended rate. If the source is variable-rate phone footage, do not assume its nominal label fully describes its timing; inspect a test encode and playback before committing to a long-running workflow.

Changing cadence is not a way to create genuinely new motion detail. When FFmpeg converts to a different target rate, it can duplicate frames or drop them. A faster target does not restore details that were never captured, and a lower target may omit source frames. Only make that trade when your editing, delivery or playback requirements call for it.

Use stream_loop to repeat the input

For infinite input repetition, place -stream_loop -1 before -i input.mp4. That placement is important: it tells FFmpeg to loop the input file, not to apply an output setting to the resulting file. If the input has video and audio and you want both, map both streams explicitly or let FFmpeg select streams after checking what the file contains.

The command below illustrates a one-hour MP4 output from a 30 fps source with audio. It loops the input indefinitely, then stops the output at the chosen duration:

ffmpeg -stream_loop -1 -i input.mp4 -map 0:v:0 -map '0:a?' -t 3600 \
  -c:v libx264 -r 30 -pix_fmt yuv420p \
  -c:a aac -movflags +faststart output.mp4

This is an illustrative starting point, not a command tested against every file or FFmpeg build. Replace 30 with the source’s intended rate; use a rational rate such as 30000/1001 when that is the actual target. Replace 3600 with your desired duration in seconds. The optional audio map 0:a? allows the command to proceed when the input has no audio stream.

The duration option ends the output after the requested time, even if that point falls partway through a repeated input. That is useful for a fixed-length file, but check the ending if you need a clean musical or visual phrase. A duration limit does not guarantee the final frame or audio sample will land on a natural seam.

For a finite number of repetitions, replace -1 with the desired loop count. Read the FFmpeg documentation for the precise count semantics in the version you are using, particularly if you are counting total plays rather than additional repeats. Avoid relying on a guessed count for an unattended overnight render: make a short test and verify where the input restarts and where the output ends.

Set a CFR output when re-encoding

In the example, -c:v libx264 re-encodes the video, and -r 30 requests an output rate during encoding. FFmpeg documents that output -r duplicates or drops frames before encoding to achieve the requested constant output frame rate. This is materially different from simply changing a rate label while copying the original compressed video stream.

You can express constant-frame-rate synchronisation with -fps_mode cfr as well, alongside an appropriate output rate such as -r 30. FFmpeg defines cfr as duplicating or dropping frames to attain the requested constant rate. Treat the rate as a creative and technical choice grounded in the source, not as a magic upload value. Check the FFmpeg documentation for -r and frame-rate modes against your installed version before building a production command.

Do not add both options mechanically without understanding your build and intended sync behaviour. A starting pattern may include -r 30 -fps_mode cfr, but the correct target and options depend on input timestamps and FFmpeg version. If you choose to use -fps_mode cfr, set an output rate that reflects the intended cadence and inspect the resulting file for dropped or duplicated motion.

Stream copy is a different trade-off. With -c:v copy, FFmpeg does not decode, duplicate or drop frames to convert cadence. An output -r in a stream-copy command may only signal a rate to the muxer; if it conflicts with packet timestamps, the result can be invalid. Use stream copy when preserving the existing encoded stream is the objective and its cadence and timestamps are already appropriate. Re-encode when you need to change cadence or other video encoding properties.

Re-encoding costs processing time and can affect image quality, depending on the chosen codec settings. Stream copy avoids a generational encode but cannot perform the frame conversion described here. Make that choice from the actual need: do not re-encode solely because a tutorial uses an encoder, and do not expect copying to fix variable or mismatched timing.

Adapt the command to your input

Before running the example, check whether the file has audio, which video stream you want, and whether it contains multiple tracks. -map 0:v:0 selects the first video stream. -map '0:a?' selects an audio stream if one exists, but if there are several audio tracks and you need a particular language or mix, inspect the streams and map the right one. A command that selects the wrong track can produce a technically valid file that is still wrong for your channel.

The example uses H.264 video in an MP4 container, AAC audio and yuv420p pixel format. YouTube’s upload guidance also discusses progressive scan, H.264, MP4, chroma subsampling and other encoding settings. Those recommendations are separate from loop behaviour and are not a guarantee that any one command fits every source. Preserve or set colour, resolution, audio and codec options according to your file and workflow rather than pasting settings blindly.

If you already have an edit prepared for a 24/7 fireplace stream, the important checks are whether the source’s motion cadence is intentional and whether its audio and picture meet cleanly at the repeat point. A fire image may hide a visual cut better than a speaking face, but a repeated crackle or abrupt music restart can still make the seam obvious. Listen across the end and beginning, not just to a frame near the middle.

A locally rendered loop file and a live broadcast are also distinct stages. If you intend to feed FFmpeg output into a live workflow, first verify the file on disk; then separately confirm that the broadcasting setup accepts its codec, resolution, frame rate and audio. For a channel built around looping pre-recorded video through OBS, OBS adds its own output and scheduling settings, so do not assume that a correct file alone determines the live cadence.

For a long-running channel, repeating a finished file is only one operational approach. StreamNeo removes the need to leave a computer running just to keep an uploaded loop on air: you upload the file, provide your YouTube stream key, and the broadcast continues from the cloud with monitoring and automatic restarts if it drops. That addresses the computer-running burden, not the need to prepare and check the source file or follow YouTube’s current guidance.

Verify output cadence before streaming

Do a short render first. Use FFmpeg’s information output or a media inspection tool to check the encoded video stream’s reported rate, duration, codec and pixel format. A displayed nominal rate is useful, but it is not proof that every timestamp is evenly spaced; inspect timestamps or use a tool that reports frame timing when the source is unusual or the result behaves unexpectedly.

Watch and listen to the beginning, a point well after a loop boundary, and the end. Confirm that the input restarts where expected, that the audio does not click or drift at the seam, and that motion looks natural. If there are multiple tracks, verify that the intended audio is present. This catches practical failures that a successful command exit cannot tell you about.

For a variable-frame-rate source, unusual timestamps, or a source with separate audio and video timing, do not assume a single rate field will explain the whole file. Run a representative test through at least one repeat boundary. If the converted output judders, loses motion or drifts out of sync, revisit the chosen target and sync mode rather than raising the rate arbitrarily.

Keep the source file until the output has passed review. A compact record of the input’s reported streams, the command used and the output’s properties helps you reproduce a known-good render later. If FFmpeg reports timestamp warnings, investigate rather than suppressing them by reflex; a loop that crosses a damaged or irregular timestamp region can behave differently from a short preview.

Once the file is ready, treat YouTube Live as a separate check. Start a private or unlisted test where appropriate, inspect the incoming stream and playback in YouTube Studio, and confirm that the channel receives the expected image, audio and cadence. YouTube’s streaming and upload guidance can change, so consult the current official page rather than treating an old command as a compliance guarantee.

Keep cadence problems distinct from stream health

A file that plays correctly on your computer can still encounter a live-stream issue later, but diagnose the layer that is failing. If the rendered file itself stutters at every repeated boundary, examine input timing, frame conversion and the loop seam. If the file plays smoothly but the live preview shows trouble, check the live encoder and network path instead of changing the source frame rate without evidence.

This distinction is useful when reading a YouTube Studio stream-health warning. A bitrate or connection warning is not automatically a frame-rate defect. Likewise, forcing a new cadence is unlikely to solve a weak connection. Keep a tested local file and note whether the problem appears before or only after broadcast begins.

YouTube publishes recommended upload settings, including bitrate guidance by resolution and frame-rate group. Those recommendations concern delivery and encoding choices; they do not mean a particular bitrate or frame rate guarantees a smooth 24/7 broadcast. For a looped channel, test the combination you will actually use and distinguish a transcode or file issue from a live ingestion issue.

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

Does -stream_loop -1 make my output constant-frame-rate?

No. It repeats the input indefinitely, and it belongs before -i. To request CFR while re-encoding, choose an intended output rate with output -r or use -fps_mode cfr with an appropriate rate; then inspect the resulting file.

Can I set -r while copying the video stream?

That does not perform frame duplication or dropping when the video is stream-copied. FFmpeg may use the rate as muxer information, and a mismatch with packet timestamps can produce an invalid file. Re-encode if you need a cadence conversion.

Should I convert every loop to 30 fps for YouTube?

No. YouTube recommends matching the frame rate at which the content was recorded, and it accepts other rates too. Preserve the intended source rate unless a real project requirement calls for conversion.

Why does the command use -map '0:a?'?

It selects audio if the input has an audio stream, while the question mark makes that mapping optional. If your file has several audio tracks, inspect them and map the one you intend to publish rather than assuming the first track is correct.

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 Setup Guides guides ↗ · All topics ↗