Home / Alt manpages / ffmpeg-bitstream-filters(1)

  • ffmpeg-bitstream-filters(1)
  • User command
  • linux

Remux and Repair Streams with FFmpeg Bitstream Filters

You will finish with a safe workflow for applying an FFmpeg bitstream filter without decoding the media, including a tested H.264 MP4 to MPEG-TS remux and a small audio packetisation check. Bitstream filters change encoded packets. They are not the same as audio or video filters, which operate on decoded frames.

Allow about fifteen minutes. You need the ffmpeg and ffprobe commands, a readable media file, and enough free space for a new output. The examples use the ffmpeg-bitstream-filters(1) manual installed with Debian package version 6.1.1-3ubuntu5+esm13. This shell resolves ffmpeg to FFmpeg 8.0.1 from Linuxbrew, so your filter list and diagnostic wording may differ. Check your own executable before relying on a build-specific filter.

1. Check the executable and available filters

Start with read-only checks. These commands do not need sudo and do not alter media:

$ command -v ffmpeg
/home/linuxbrew/.linuxbrew/bin/ffmpeg
$ ffmpeg -version | sed -n '1,3p'
ffmpeg version 8.0.1 ...
$ ffmpeg -hide_banner -bsfs

The last command prints the bitstream filters compiled into the executable. The manual's list is a description of the installed documentation, not a guarantee that another build has the same set. For a filter you intend to use, ask FFmpeg for its accepted options and supported codecs:

$ ffmpeg -hide_banner -h bsf=pcm_rechunk
Bit stream filter pcm_rechunk
...

Checkpoint: the exact filter name must appear in -bsfs. If it does not, stop there. Installing a different package or changing your PATH is a system administration decision, not a parameter to add to the command.

2. Understand where the filter is applied

Use -bsf:v for video, -bsf:a for audio, and the unqualified -bsf only when applying the filter to the relevant streams is unambiguous. The value is a comma-separated list; each filter's options follow its name after =:

ffmpeg -i INPUT -c:v copy -bsf:v FILTER[=OPTION=VALUE][,FILTER2] OUTPUT

A bitstream filter generally works with copied encoded packets, which is why the examples use -c copy or -c:v copy. That does not make every combination valid. A filter supports particular codecs and packet layouts, and the output container may impose its own requirements. Omitting stream copy can make FFmpeg decode and re-encode, changing the task and possibly reducing quality.

Read the input before choosing a stream:

$ ffprobe -hide_banner -v error -show_entries stream=index,codec_type,codec_name -of compact INPUT.mp4
stream|index=0|codec_type=video|codec_name=h264
stream|index=1|codec_type=audio|codec_name=aac

Your indexes and codecs will differ. Treat this output as the authority for the file you are about to process.

3. Remux H.264 MP4 into MPEG-TS

h264_mp4toannexb converts H.264 from length-prefixed packets to start-code-prefixed Annex B packets. MPEG-TS commonly needs that form. Write a new destination so the source remains your recovery copy:

$ ffmpeg -hide_banner -i INPUT.mp4 -map 0 -c copy \
    -bsf:v h264_mp4toannexb OUTPUT.ts

On success, FFmpeg ends with a summary containing the output filename and a zero exit status. The installed manual also says this filter is auto-inserted for the MPEG-TS muxer, so an explicit filter is often unnecessary for this particular remux. Keeping it visible documents the packet conversion you expect and makes the command easier to audit.

Checkpoint: verify the output without decoding it:

$ ffprobe -hide_banner -v error \
    -show_entries format=format_name:stream=index,codec_type,codec_name \
    -of compact OUTPUT.ts
stream|index=0|codec_type=video|codec_name=h264
format|format_name=mpegts

The exact stream order and format-name detail can vary, but the output should identify an MPEG-TS container and retain H.264 as the video codec. If the command fails, keep INPUT.mp4 and inspect the first diagnostic before trying another filter.

4. Repacketise PCM audio as a controlled test

pcm_rechunk changes audio packets rather than audio samples. By default it aims for 1024 samples per packet and pads the final packet. With frame_rate, it instead aims for a fixed number of packets per second. This is useful when a downstream container or device expects predictable packet boundaries.

The following command generates one second of a synthetic sine wave, applies the filter, and writes a frame checksum to standard output. It is a non-destructive test and needs no input file:

$ ffmpeg -hide_banner -loglevel error \
    -f lavfi -i sine=r=48000:d=1 \
    -c pcm_s16le -bsf:a pcm_rechunk=r=30000/1001 \
    -f framecrc -
#software: Lavf62.3.100
#tb 0: 1/48000
#media_type 0: audio
#codec_id 0: pcm_s16le

The header confirms that FFmpeg produced PCM audio and the frame checksum muxer accepted the filtered packets. The detailed checksum lines are input-dependent. This example does not prove that a particular playback device wants this packet rate; it only proves that the installed build accepts the filter and option for this codec.

5. Handle filters with options carefully

Options belong to the filter after its equals sign. For example, dump_extra accepts keyframe or all; if omitted, the manual documents key packets as the default. filter_units accepts a pipe-separated unit list. Quote that value so the shell does not interpret the pipe as a pipeline:

$ ffmpeg -i INPUT.h264 -c:v copy \
    -bsf:v 'filter_units=pass_types=1-5' OUTPUT.h264

That H.264 example removes non-VCL NAL units from the packet stream. The manual warns that removing inline parameter sets can leave the result unusable. Do not use a packet-removal filter on an irreplaceable source or in a production batch until you have tested the exact decoder and container that will consume the result.

6. Diagnose failures without escalating privileges

A missing filter, unsupported codec, invalid option, or incompatible input is normally fixed by changing the filter choice or input mapping. sudo does not repair any of those errors. Run ordinary media conversion as your normal user, and use elevated privileges only when the input or destination directory explicitly requires access. Prefer copying the file into a working directory where you have normal permissions.

Common traps are easy to separate:

  • If FFmpeg says the filter is unknown, compare its spelling with ffmpeg -bsfs and check which executable command -v selected.
  • If it reports an unsupported codec, inspect ffprobe output and use a filter documented for that codec and stream type.
  • If a command unexpectedly re-encodes, check every relevant stream option. -c copy is the concise form; -c:v copy controls video only.
  • If output already exists, FFmpeg may refuse to overwrite it unless -y is supplied. Do not add -y blindly: it makes an existing destination easier to destroy.

There is no state to undo in the examples until you deliberately replace a file. The source is preserved and each destination is new. If an output is wrong, stop using it, return to the source, and choose a different destination name. Delete an unwanted output only after checking its path; deletion is irreversible.

Done means

  • You confirmed the executable, version, and build-specific filter list.
  • You inspected the input streams before selecting -bsf:v or -bsf:a.
  • You kept encoded data copied when the task was a packet-level change.
  • You remuxed to a new file and used ffprobe to verify its container and codec.
  • You treated filter options, packet removal, overwrite flags, and elevated access as deliberate choices.