AudionAudion

Cut: format matrix, test methods and FFmpeg pitfalls

TRIM_MATRIX_EN.md

Cut: format matrix, test methods and FFmpeg pitfalls

Русский

About the interface in this document. The cut points are found in the mpv player,
which a button of the section opens, and are moved into the fields with buttons, or
typed as a timecode on the keyboard.

A reference for the CUT section. Everything written here is measured, not taken from documentation: each cell of the tables is a real attempt to write with -c copy and to read the result back, each sync number is a measurement by frames and samples. The numbers were taken on FFmpeg 9.0.1, and taken again on 8.0.1 they matched cell for cell. Which build goes into the distribution is decided by the installer from the version of the NVIDIA driver (on most machines this is the 8.x branch), so both are checked.

The section in detail is in TRIM_EN.md, the decisions are in DECISIONS_EN.md. Here are the facts about trimming; the full set of measurements, including frame rate conversion and the limits of FFmpeg itself, is in MEASUREMENTS_RU.md (Russian).


1. What the section does

CUT copies the streams (-c:v copy) and does not re-encode the picture. From this come four properties that define everything else:

(24000/1001 for 23.976 and 24/1 for a true 24.000), and nothing is guessed; a camera shoots both;

it is rewritten sample for sample without a generation loss.

ModeWhat staysPoints
Remove the starteverything after INone (IN)
Remove the endeverything before OUTone (OUT)
Keep the middlethe piece between IN and OUTtwo
Splitall parts, nothing is thrown away; the joins are on keyframesN points give N + 1 parts, up to 30 points

The + rows in KEEP and CUT OUT are not new modes but separate runs of the same mode on the same take, each into its own file (_keep01, _cut01): everything measured here applies to each of them as to a single cut.


2. Container × video codec

Pairs «video + a sound that the container surely accepts», written with -c copy, then read back, and the codec compared.

VideoMP4MOVMKVMXFTSM2TS
H.264yesyesyesyesyesyes
HEVCyesyesyesnoyesyes
ProResnoyesyesyesnono
DNxHD/DNxHRnoyesyesyesnono
MPEG-2yesyesyesyesyesyes
AV1yesnoyesnonono
VP9yesnoyesnonono

What follows from this in practice:

«Could not find tag for codec» and a zero-length file, so such a pair is rejected before the run.

re-encoding; that is a separate operation, not trimming.

3. Container × audio codec

SoundMP4MOVMKVMXFTSM2TS
PCM 16 LEyesyesyesyesnono
PCM 16 BE (twos, Canon)yesyesyesnonono
PCM 24 LEyesyesyesyesnono
PCM 32 floatyesyesyesnonono
AACyesyesyesnoyesyes
AC-3yesyesyesnoyesyes
E-AC-3yesyesyesnoyesyes
MP3yesyesyesnoyesyes
FLACyesnoyesnonono
ALACyesyesyesnonono
Opusyesnoyesnoyesyes

The main points:

the camera writes pcm_s16be, and on output to MXF the sound is rewritten into pcm_s16le: the same samples, in the byte order the container requires.

moved into TS; MOV takes it as it is.


3.1. A sound file

A sound file does not copy the stream: it decodes it and cuts on the sample, so the container matrix above does not apply to it. What is written where:

ButtonCodecContainerLossless
As is: PCMthe same PCMwav, w64, aif, aiff, caf, au, snd, mkayes
As is: FLAC, ALAC, WavPack, TTAthe sameits own or mkayes
As is: MP3, AAC, Opus, Vorbis, AC-3, E-AC-3the same, at the source bitrateits own or mkaone generation
WAVPCM at the source bit depth; float for a compressed sourcewav, RF64 past 4 GByes
FLAC, ALACFLAC, ALACflac, m4aup to 24 bits
M4AAACm4ano
MP3LAMEmp3no
Opuslibopus, at most 256 kbpsopusno

MP3, M4A, FLAC, ALAC and MKA keep a cover; WAV and Opus do not.

Packet copying (exact cut turned off) is offered for MP3 in mp3, AAC in m4a and m4b, Vorbis in ogg and oga, Opus in opus, ogg and oga; for the rest it is not. What the join costs for each codec is in TRIM_EN.md; the measurements are in MEASUREMENTS_RU.md (Russian), section 12.3.


4. Cut accuracy

4.1 Frames

Checked on eight synthetic sources and one camera source. In every case the number of frames matched the plan exactly.

SourceRequestFramesDifference
ProRes 25p3 → 91500
HEVC long-GOP 29.9712 → 306000 (after topping up by decodable frames)
H.264 all-intra 23.9763 → 91440
29.97 drop-frame5 → 153300
59.94 drop-frame3 → 93600
MPEG-TS (start 1.44 s)2 → 83000
4 PCM channels2 → 81500
Canon HEVC 4:2:2 10-bit3 → 101660
ARRI ProRes 4444 XQ 24.0002 → 81440
VFR (30 → 17.6)4 → 16by time+1.07 s, reported

4.2 Sound sync

The mark is in both tracks at once: a white frame at the start of each second and a click at the same moment. The deviation is counted against the source, not as an absolute value.

ContainerChange against the source
MP40…2 ms
MOV0…5 ms
MKV1…3 ms
MXF0…5 ms (after the PCM rewrite; before it, 9…18)

On the camera file the sound of the piece is found in the source word for word: the piece starts 48 samples (1 ms, a fortieth of a frame) after the cut point.

4.3 Metadata

Checked on a file with rotation, two tracks and project tags:

WhatMP4MOVMKV
Rotation (rotation=90)yesyesyes
Track language (rus, eng)yesyesyes
Project tags (title, artist)yesyesyes
Camera tags (make, model, brands)yesyespartly
Timecode as a tmcd trackyesyesno (a text tag)

Camera tags are carried by -movflags use_metadata_tags; without it the MP4 muxer writes its own isomiso2mp41 and loses make, model and a brand like mp42hvc1CAEP.


5. FFmpeg pitfalls found by measurement

Each one took a separate investigation; none is obvious from the documentation.

No.PitfallSymptomHow it is avoided
1-ss before -i resets the time-to after it counts from the new zerothe tail is passed as a duration/frames, not as an absolute point
2round(fps) on fractional rates4 minutes at 29.97 become 240.27 sthe rate lives as a Fraction from ffprobe to ffmpeg
3Rounding the end «to the nearest»a frame standing at 29.9966 is lost when 30.0 is requestedthe end is rounded up
4-t when copyingan overshoot of 1–3 frames on a stream with B-framesthe tail is set with -frames:v
5-frames:v is exact only with an exact -sswith -ss off the keyframe the piece is shorter by the gapthe seek always goes to the computed keyframe
6HEVC with a B-pyramidthe muxer writes 2–4 frames fewer than requestedthe shortfall is measured and the cut is repeated once with a correction
7-avoid_negative_ts make_zerothe video drifts 0.1 s from the soundnot used
8start_time ≠ 0 (MPEG-TS 1.44 s)all points shift by this amountthe offset is removed from the keyframes and added back on seek
9avg_frame_rate on VFRthe frame count covers the wrong span (12 s → 16 s)VFR is detected and cut by time, with a warning
10-n on an existing file«already exists», exit code 0the target is checked before the run
11PCM in MXF with -c copy384 extra samples at the start (8 ms)PCM is rewritten sample for sample (LE)
12-map_metadata 0 in MP4camera tags and brands are lost-movflags use_metadata_tags
13`pan=monoc0=c1` on monowrites silence, exit code 0the number of channels is checked before the run
14MXF + compressed sound«Could not write header», code 4294967274rejected before the run with an explanation
15Packet ≠ framethe muxer writes 600 packets, the decoder gives 597: the trailing B-frames refer past the cut boundarythe shortfall is caught by the stream duration and topped up by decodable frames
16Camera RAW in MXFcodec_name is empty, the sizes are zero, «dimensions not set», a zero-length filerejected before the run: FFmpeg has no X-OCN or ARRIRAW decoder
17A warning breaks the JSON parsingstderr is mixed into stdout, and json.loads fails on the line «could not resolve file descriptor strong ref»probes are read with separate streams

6. How all this is measured

The commands that produced the numbers above. Use the same ones for the next check; otherwise the results cannot be compared.

Frames. Count packets instead of decoding: the result is the same, the time is forty times shorter (0.14 s against 5.7 s on four minutes of 59.94).

ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 FILE

Keyframes around a point, without scanning the whole file:

ffprobe -v error -select_streams v:0 -skip_frame nokey -read_intervals "START%+WINDOW" -show_entries frame=pts_time -of csv=p=0 FILE

Sync. You need a source with a mark in both tracks: a white frame and a click at one moment. Read the video through signalstats with -fps_mode passthrough; otherwise the filter duplicates frames to fit its own clock and shifts the times:

ffmpeg -v info -i FILE -map 0:v:0 -vf "signalstats,metadata=print:key=lavfi.signalstats.YAVG" -fps_mode passthrough -f null -

The sound is read by samples, not through silencedetect: the detector works in 20 ms windows, and the values to measure are a few milliseconds.

ffmpeg -v error -i FILE -map 0:a:0 -ac 1 -ar 48000 -f s16le -

Bit-exact check of copying. Find the sound of the piece inside the sound of the source: if it is there word for word, the sound was copied, and the position gives the exact offset of the cut.

Compatibility. Write one second with -c copy into the container and read it back. Choose the partner stream to suit the container: MXF does not take AAC, TS does not take PCM, and without this the cell shows the refusal of the partner, not of the codec under test.

Traps of the measurements themselves

Three mistakes that were already made once; they are worth not repeating:

  1. Comparing «the first flash found» with «the first click found». If

one stream opens with a mark and the other does not, the detectors describe different events, and the result is a «107 ms desync» that does not exist.

  1. Measuring sync with FFmpeg detectors. blackdetect works in whole frames,

silencedetect in windows; together they give an error of 40 ms, that is, more than the value being measured.

  1. Checking compatibility by the exit code. A file can be written and not

read back; TS «accepts» ProRes exactly this way.


6.1. Camera RAW: what the tool cannot do

Two formats that FFmpeg does not open in any version; checked on both 8.0.1 and 9.0.1:

FileWhat is insideWhat ffprobe sees
Sony BURANO X-OCN LTX-OCN in MXF OP1aa stream without a codec name, width=0; the sound pcm_s24le is read
ARRI Alexa Mini .mxfARRIRAW in MXFthe same

An attempt at a plain copy gives «dimensions not set» and a zero-length file, so such sources are rejected before the run with a direct explanation. They can be cut in the vendor's own software (Sony Catalyst, ARRI Reference Tool) or after a transcode.

The same material in MOV is cut fully: ARRI ProRes 4444 XQ (2944×2160, 12-bit, 5 PCM tracks) went through frame for frame, together with the timecode 02:00:11:11 → 02:00:13:11.


7. What was not checked

The list is open, so that nobody (the author included) decides that the matrix is closed:

telemetry, AVCHD straight from the card;

58th minute and in the last seconds; see MEASUREMENTS_RU.md (Russian));

moves forward by 0.1 s and this is reported, but it was not checked by ear;

AC-3, E-AC-3, DTS and AAC outside M4A.

Alle Projekte