github kajisho5/ffmpeg-skill v3.1.6

3 hours ago

Automated release: version and notes generated from pull requests merged since 3.1.5.

Fixed

  • On FFmpeg 7.0+, freeze.py --at lost its hold (--at 1 --hold 1 on a 2 s clip came out 1.97 s, and
    the sound ran a second past the picture) and reverse.py did not hold the last frame of a picture
    shorter than its sound (408 ms off): from 7.0 setpts leaves the frame rate unknown and the frame
    durations 0, so a tpad clone after it adds nothing. Both now clone before the shift; the graph
    is the same on every version, and both end on an fps at the source's rate, which gives back the
    frame durations setpts clears (the last frame was written with none: 3.967 s for 4 s) (#409, #411).
  • color.py --lut shifted every colour even with an identity LUT (2FAE4E came out 249A4B): libavfilter's
    own conversion into lut3d's RGB read the frame's BT.709 tag and the one back used BT.601. Both legs
    are now explicit BT.709 conversions through float RGB, and a --lut-strength blend is made in that
    RGB too; an identity LUT returns what --lut-strength 0 does (#410).
  • join.py, multicam.py, grid.py, broll.py and overlay.py --video mixed a full-range clip in a
    plain pixel format (VP9 and AV1 full range, any 10-bit full range, which decode as yuv420p tagged
    pc) with limited-range ones without converting the range, so one of them was shown in the other's
    range (C03028 came out C9251B). Every SDR picture these tools mix is now taken to limited range
    first. The limited-range layers graphics.py (boxes and bars with a colour), emoji PNGs and
    overlay.py --image composite were put on a full-range main the same way (30B050 came out 37A757);
    that main is now taken to limited range under them (#410).
  • On FFmpeg before 7.1, a colour drawn on such a full-range picture landed in limited range: a pad's
    black read 101010 and white EBEBEB (pad.py, fit.py, overlay.py --text ...), and a colour with
    chroma on a 10-bit full-range picture came out oversaturated. The picture is now taken to limited
    range before the drawing on those versions; FFmpeg 7.1+ commands are unchanged (#410).
  • look.py (frames, --compare, contact sheet), scenes.py --sheet and export.py --preset gif
    decoded an untagged source as BT.601 (C03028 came out B31F28), while every encode takes it as
    BT.709. Its frames are now labelled BT.709 (tags only) before the conversion to RGB (#410).
  • color.py --correct with every option at its default tinted grey (808080 came out 7E7E7B):
    colortemperature=temperature=6500 was always in the chain and is not an identity. The term is
    left out at 6500 K (#410).
  • grid.py --cols 1 --rows 1 reached ffmpeg and failed there with exit 222 (xstack takes two inputs
    or more). It is now refused up front as an input error (#410).
  • silence.py drifted picture and sound apart at every cut, even on a clean source: each kept range
    was rounded twice, the picture to whole frames and the sound to whole AAC frames, and the errors
    added up (about 150 ms over 21 ranges of a 61 s talk; 5, 40 and 75 ms over three ranges), and
    --timemap was off by as much. A sound that starts after its picture was also moved early by its
    whole offset (+280 ms). The kept ranges are now re-cut the way cut.py --segments --accurate
    cuts them: both streams on the same frame-grid bounds, shifted by one constant, a late sound padded
    with silence. Each kept bound is moved to the nearest frame time first, and --timemap is built from
    those bounds, so its output times are the output's. The old render kept both boundary frames of
    every range, one frame more per range than was kept (#409).
  • sync.py and multicam.py measured a sound track that starts after its file's start from its
    first sample: a track 0.3 s late measured +2.279 s for +2.000 s, --replace-audio placed it about
    270 ms late, and multicam.py cut the camera's picture that far off and rebased its sound too. The
    audio decode now pads a late sound so its samples are on the file's clock (this also corrects
    scenes.py's audio envelopes and cut.py's beat grid on such files), and both tools place the
    sound on its own file's clock before delaying it (#409).
  • freeze.py, speedramp.py, join.py (since #338), broll.py --audio b|mix and reverse.py moved
    one stream against the other on a source whose sound or picture starts late, or whose sound runs
    past its picture: freeze +279 ms (late sound) and -100 ms (late picture), speedramp +570 ms at
    0.5x, join and broll +279 ms, reverse +396 ms for a sound 0.6 s past the picture (a
    stream-copied cut went from -17 to +61 ms). Each now cuts both streams on the same frame times and
    shifts them by one constant, as cut.py's re-cut does; reverse.py turns both about one end (#409).
  • loop.py lost a frame and slid the sound on every repeat of a clip whose sound starts late (795 of
    810 frames, 43-51 ms): -stream_loop took each repeat's length from the streams' spans without the
    last frame. The repeats now come from the concat demuxer, one entry per repeat, each the file's
    whole length, with the late sound's gap filled with silence (#409).
  • Footage that stores non-square pixels (DV, HDV/XDCAM 1440x1080, DVD) came out squashed from
    every tool that scales (fit, export, grid, join, broll, multicam, look, ...), crop.py read its
    rectangle in the stored frame, and caption, overlay.py --text and graphics drew text the
    player stretched 1.78x. probe.py now reports sample_aspect_ratio, and every tool that sizes,
    crops, places or draws on the picture first scales it to square pixels at its display aspect
    (its height kept) and says so in notes; rectangles, margins and sizes are in that displayed
    frame. A tool that only re-encodes keeps the stored size and its SAR (#411).
  • graphics.py's title, lower-third, chapter and bug never wrapped, so a long title ran
    off the frame (also through render.py --template). They now wrap with the same wrapped()
    helper sticker, hook and meme use, and the lower-third bar widens to the widest line.
    overlay.py --text wraps a line wider than the frame between the margins and says so in notes
    (#411).
  • look.py's contact sheet stamped an MPEG-TS's tiles one seek late (about +0.5 s); it now reads
    the stamps off the file's own timestamps. scenes.py --sheet picked the wrong frames on a
    variable-frame-rate source (a frame number from start x average fps); it now picks each scene's
    first frame by time. look.py --compare stretched the first picture to the second's aspect; both
    are now letterboxed into boxes as tall as the taller one (#411).
  • grid.py drew a Japanese, Chinese or Thai filename label as empty boxes while reporting
    substituted: false, and a label wider than its cell kept only its tail. Each label now gets a
    font that covers its script, and a long one is shortened from the end with an ellipsis (#411).
  • freeze.py --at T held the frame before T (at a cut, the last frame of the previous shot); it
    now holds the frame shown at T (#411).
  • An hh:mm:ss:ff time typed off a source's start timecode (01:00:01:00 on a camera file starting at
    01:00:00:00) was refused as past the end with no word on why. The refusal's hint now says the
    time counts from the file's first frame and names the frame meant; the time grammar is unchanged
    (#411).
  • broll.py with an odd-sized A-roll failed unclassified (kind: ffmpeg); the A-roll is scaled to
    even up front and recorded as odd_dimensions_scaled_even (#411).
  • A JPEG with an EXIF Orientation tag (a phone's portrait photo) was sized as landscape by
    insert.py and sequence.py, which cropped a sideways window out of the upright picture
    ffmpeg decodes. probe() now reads a still's rotation off its decoded frame (#411).
  • Review of #416: freeze.py without --at (the clip's end) held nothing in --mode insert (the
    picture kept its length, the sound gained the hold); it now holds the last frame as --mode extend
    does. On a variable frame rate a hold whose one-frame window held no frame (frames at 0.033 and
    0.100, --at 0.06) was lost too; the hold is now the first frame at or after the cut (#409, #411).
  • silence.py with more than 32 kept ranges replaced its input under -o <input> --overwrite: the
    chunked join's last command never names the source, so the same-file check did not see it. It is
    now refused up front. Its keep, kept_duration, removed_seconds and --edl described the
    unsnapped bounds while the render and --timemap held frame times (0.385-2.115 for 0.4-2.1), and
    an EDL bound rounded past its frame re-cut one frame late; all now describe the rendered ranges,
    frame times written down to the millisecond (#409).
  • insert.py noted the square-pixel scale of a non-square-pixel still but never ran it, so the still
    lost a band top and bottom; cropdetect.py, sequence.py and waveform.py --image squared the
    picture without the notes line. The EXIF-rotation probe read a still named photo%02d.jpg as an
    image sequence and found no rotation (#411).
  • straighten.py --fit crop pre-scaled by a square's factor (|cos|+|sin|) and left two corners black
    on a 16:9 frame; it now scales by |cos| + max(W/H, H/W)|sin| of the displayed frame (#411).
  • speedramp.py accepted a segment whose two ends fall on one frame (1.01-1.02 at 30 fps) and
    applied its factor to no frame; it is now refused as an input error (#409).
  • graphics.py placed a PNG emoji on a wrapped line as if the label were one line (first line's y,
    the earlier lines' width added to x); a title wrapped taller than the frame, and overlay.py --text
    wrapped taller than the frame or placed too near the edge to wrap, lost text without a word (now a
    notes line); the lower-third bar's 62 % floor ran past the right margin at a large --scale; a
    grid label in a cell with room for one em was not shortened; broll.py scaled a 1-pixel-wide
    A-roll to width 0 (kept as 1) and failed; and the SMPTE hint named the first timecoded input's
    start timecode for a time in another input (a B-roll's --from) (#411).
  • Colour, A/V sync and geometry: the round-1 audit fixes (#410, #409, #411) (#416)

What's Changed

Full Changelog: v3.1.5...v3.1.6

Don't miss a new ffmpeg-skill release

NewReleases is sending notifications on new releases.