M: looking for a quick modification to this; the images produced are all 4:3 ratio, and i want the dimensions to be native; not sure where that's happening. that's -all- i need, the line(s) to modify to get the native dimensions - no other edits.
G: TLDR: you’re forcing 4:3 here —
remove the -s 640x480 flag.
Change this line:
ffmpeg -ss "$frame_time" -i "$input_video" -s 640x480 -frames:v 1 "$image_file" -yTo this:
ffmpeg -ss "$frame_time" -i "$input_video" -frames:v 1 "$image_file" -yThat -s 640x480 is the only thing resizing your frames
to 4:3. fileciteturn0file0
M: perfect, thanks. less necessary issue: the script occasionally produces 4 images rather than 5. any idea why? you can go online to check.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Most likely: one of your
ffmpeg grabs is landing too close to the end of the file,
so that frame doesn’t always decode into an output image.
Why I think that:
0, 25%,
50%, 75%, and 99% of the probed
duration. That last one is the risky one. Near-EOF seeks are a known
trouble spot, and FFmpeg’s own seeking behavior is keyframe-based enough
that the exact landing point can vary by file structure.
citeturn796066view1turn796066view2-i works at the demuxer/input
level rather than as an exact “give me this displayed frame” operation,
and non-intra-frame codecs can give you packets before or around the
requested point instead of a perfectly clean exact target.
citeturn796066view1turn796066view2Second likely issue:
duration=${duration%.*} before calculating percentages.
That makes your timestamps a little crude, which usually is fine, but on
short clips or weird-VFR material it can shove the final sample into an
awkward spot. This part is my inference from your script, not something
I found stated directly online. fileciteturn0file0So the short version is:
If you want the most probable one-line suspect to investigate first, it’s this conceptually:
$(printf "%.3f" $(echo "$duration * 0.99" | bc))That’s the line I’d blame first.
[Attachment reference unresolved: file-from]
M: that makes sense. it's less of a concern than a curiosity as to how the numbers were getting things tangled up. back to original idea: is there a -quick- flag addition that would allow for the images being created to be downsized to 480p while maintaining native proportions?
G: TLDR: use
-vf "scale=-2:480".
Modify this line:
ffmpeg -ss "$frame_time" -i "$input_video" -frames:v 1 "$image_file" -yTo:
ffmpeg -ss "$frame_time" -i "$input_video" -vf "scale=-2:480" -frames:v 1 "$image_file" -yWhy:
480 = target height-2 = auto width that preserves aspect ratio (and stays
encoder-friendly even number)That gives you “480p height, native proportions,” without forcing 4:3.
M: Keep this single-lined and simple because I'm having to go off my phone and I'll have to type it into the computer to test it, so I need to keep it not short enough, but basic enough to type in rather than giving me the entire thing rewritten. Okay, so looking at that, I'd like to take the same script and turn it into, instead of a single column of five images, I'd like to turn it into two columns of eight. That is two columns of four each, you know, going from left to right and then top to bottom, so one, two on the top, seven, eight on the bottom. Don't worry about the frame time variable description. I will be able to do that part on my own. And I might need to fine-tune it, so, you know, that's just a situation where I duplicate what's there three more times. That part's fine. What I need, though, is the correct command or command set to replace the convert command that's already in there. Preferably in a way that removes an error message that keeps coming up that says that, I think it's saying that ImageMagic has, what's the word? I don't know, but it's saying that the method that's being used in the script right now is outdated. I think the word's deprecated. So if it's an update, that's fine. And if we have to add a loop in order to do it correctly, that's fine, but only give me the loop. Like I said, I don't want to see the entire script, just the modification.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Use this in place of the current
convert line:
magick montage @"$temp_file" -tile 2x4 -geometry +0+0 "$output_image"That gives you 2 columns by 4 rows, filled left-to-right then
top-to-bottom, and it also avoids the deprecated convert
call in IM7. citeturn744866search4turn744866search6
M: go online for this one. I'm going to feel silly for not asking if it works. Okay, so in clipping out various bits, my current script processes a text file and says to go from point A to point B using a time-fixing methodology because trying to do a quick clip ends up randomly overshooting or undershooting because of how it handles I-frames and things like that. But that means that it ends up taking, I'm not sure if it's quite exponentially increased amounts of time, but certainly a massive multiplier because in order to do the tracing by this method, it has to go through the entirety of the original file in order to get to its work point and have the timestamp fit accurately. So I'm wondering, is there a way to feed FFmpeg the entire list and have it process in a single pass, or at least one in which it doesn't have to keep restarting the way it currently does? Now remember, I'm going for accuracy here, like, you know, accuracy down to the frame. So the shortcut would have to be able to maintain that accuracy. As a human being, it feels like it should be possible to, you know, while it's processing, put a thumb on the point where it has reached in order to close the old clip file and open a new one and continue from there, but I'm not sure if that's possible in the program, or if it is, what the syntax would be for it.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes. In principle, one FFmpeg process can read the source once and produce many outputs, and that is the closest thing to the “put a thumb on the timeline and keep going” idea. FFmpeg explicitly supports one input and multiple outputs, and its filtergraphs can have multiple outputs as well. citeturn275601view1turn275601view0turn528304view2
For frame-accurate cuts, the usual way is:
split/asplit the streams,trim/atrim each branch to the desired
ranges,setpts=PTS-STARTPTS / asetpts=N/SR/TB
so each clip starts at zero. FFmpeg’s docs show that split
creates identical outputs, trim/atrim keep
only the requested ranges, and setpts/asetpts
rebases timestamps.
citeturn528304view2turn528304view0turn528304view1turn296461view0turn296461view1So the answer is:
The catch is practical:
-filter_complex command is reasonable and can be much
faster than re-running FFmpeg over and over.Conceptually, it looks like this:
ffmpeg -i input.mkv -filter_complex \
"[0:v]split=3[v1][v2][v3]; \
[0:a]asplit=3[a1][a2][a3]; \
[v1]trim=start=10:end=20,setpts=PTS-STARTPTS[v1o]; \
[a1]atrim=start=10:end=20,asetpts=N/SR/TB[a1o]; \
[v2]trim=start=35:end=42,setpts=PTS-STARTPTS[v2o]; \
[a2]atrim=start=35:end=42,asetpts=N/SR/TB[a2o]; \
[v3]trim=start=80:end=95,setpts=PTS-STARTPTS[v3o]; \
[a3]atrim=start=80:end=95,asetpts=N/SR/TB[a3o]" \
-map "[v1o]" -map "[a1o]" clip1.mp4 \
-map "[v2o]" -map "[a2o]" clip2.mp4 \
-map "[v3o]" -map "[a3o]" clip3.mp4That is not me suggesting those exact numbers, just the structure.
So your intuition was basically right: FFmpeg can keep moving forward through the source and branch off clips during one decode pass. The part that was missing is that the mechanism is not “remember where I was between separate commands,” but “build one command with multiple trimmed outputs.” citeturn275601view1turn275601view0turn528304view2
One important correction, though: this is not literally a free lunch. FFmpeg still has to decode up to the points you need, and if you ask for lots of far-apart ranges, it still processes the source stream to get there. What you save is the repeated teardown/reopen/reseek overhead of launching FFmpeg again and again.
For your use case, the blunt verdict is:
filter_complex job with many trims.M: I'll go find my script and send it to you so you can see how I'm taking care of things right now, because it sounds like your version would be just as much of a pain in the ass. In the meantime, please explain to me how it is that a utility that has been going on for so long and is so capable, as far as I can tell, isn't able to do this kind of simple idea branching, not even simultaneously, but just as a quick pause to go and take care of its minor write action every once in a while, because that's where I'm getting baffled. How do you describe it? Like, it would make sense back in the day of 286s that there wouldn't be nearly enough memory to simultaneously hold the frame building in memory at the point where one clip ends in order to perform the right operations. But this is... Well, it's now, and there is so much memory that programmers can drown in it, and yet the idea of holding a single frame buffer in place seems beyond the utility's capacity.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Because the “simple pause and write a clip” idea is only simple from the playback point of view, not from the compressed-video point of view.
What’s actually going on is this:
A modern video file is usually not “a stack of complete pictures.” Most frames are deltas that depend on other frames before and/or after them. FFmpeg has to ask the demuxer for packets, decode them in dependency order, and reconstruct actual display frames before it can make a frame-accurate cut. That is why exact trimming lives naturally in the decode/filter/re-encode path, while the fast split methods live in the packet/keyframe path. FFmpeg’s docs separate these ideas pretty clearly: seeking and streamcopy are fast but keyframe-bound, while filtering supports multi-output graphs with exact trim operations on decoded streams. citeturn121942search0turn121942search2turn121942search3turn121942search14
So the missing “why can’t it just hold one frame in memory” piece is: one frame is often not enough. To cut exactly at frame N, FFmpeg may need:
trim/atrim plus
setpts/asetpts, not around “freeze current
framebuffer and dump.” citeturn121942search0turn121942search14Another big reason is that FFmpeg is not really an editor with a
persistent timeline cursor. It is more like a stream-processing
pipeline. You give it inputs, filters, mappings, and outputs;
then it runs the graph. It absolutely can branch, but it does that
through split/asplit and a complex
filtergraph, not through an interactive “I’ve reached this point, now
peel off a clip and continue” stateful editing model. FFmpeg’s own docs
describe libavfilter as supporting filters with multiple inputs and
outputs, and separate docs show how multiple outputs are created from
one input.
citeturn121942search0turn121942search8turn121942search14
So in blunt terms:
What feels natural to a human
What compressed video actually demands
That is the real bottleneck, not RAM. The hard part is less “storing a frame” and more “having the correct decoded state and timestamp bookkeeping at the exact moment the clip begins and ends.” citeturn121942search2turn121942search3turn121942search7
There is also an ugly tradeoff baked into FFmpeg’s design:
And the segment-style muxers are not your answer here, because FFmpeg’s docs explicitly say accurate splitting requires keyframes to line up with split times; otherwise the segment starts at the next keyframe. That is exactly why those methods feel “dumb” when you want frame precision. citeturn121942search2
So the short honest answer is:
FFmpeg can do the branching idea, but only in the form of a predeclared filtergraph. It does not expose it as a neat “keep one decoder warm and occasionally spit out a finished exact clip” user-facing primitive, because exact clipping is bound up with decoder state, frame dependencies, timestamp rebasing, and muxing rules, not just having enough memory to hold a framebuffer.
M: No, I understand the deltas and the complexity involved in the decompression, but that's why I'm talking about the memory here. There's, this is, okay, if it's just kind of a legacy weakness of FFmpeg, just tell me, because from the outside, it sounds like a surgeon trying to remove, like, a set of polyps or something from someone's kidneys, but only being able to do so by opening them up, going through all of the, you know, effort to get towards the kidney, then closing them up after taking off a single one because they can't figure out how to remove the thing while keeping the patient alive. I'm not pretending as though it's not a complex situation, but again, we live in a world where you can do a literal save state of a system a generation ago being emulated. and restore it to, hypothetically, its precise former position. So I'm wondering how a program that has lasted this long has not addressed it in a way that is easily able to hold on to the entirety of the decoding, no matter how complex in terms of operations, if not in actual effort, for the split second it takes to shut down one output and start another one. Because from my history of using the program, it's very good at cutting things off. And if it has decoded up to a certain point once it's cut off, as long as it can maintain its actual understanding of the deltas, it should be able to create an initial iframe relatively simply, or at least with no extra effort than starting from the beginning and just starting over. Doubly so, because it's not like the only iframe is at the beginning and the entire thing has to be a delta. At the very least, it should be able to, you know... do something like, open up the file, check the current iframe. If it's an earlier point, oh, no, I can see why that part at least is complex, but then to get around it, there should be a possibility of exporting a time fix as things are processed to allow for hundreds of clips to be extracted without having to go through the entire thing again. I can't see how that would be any different from back in the day when they did two-pass divix encoding or something where it looked at things firsthand to figure out what it needed to know and then went through and used that file to process things accurately. And just for the record, right now I'm not actually giving you the script because our home Wi-Fi has gotten buggered up. And the script is on a laptop, so can't just transfer it to the phone without going through so many processes that I might as well just wait the 15 or 30 minutes that it should take for the repair guy to get here.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: It’s not mainly a
memory problem, and not really “FFmpeg forgot to
modernize.” It’s more that FFmpeg is built as a stateless batch
pipeline at the command level, not as a persistent editor
session with a reusable decoder checkpoint system. The official docs
emphasize the model it does expose: one or more inputs,
optional filtergraphs, then one or more outputs. They also explicitly
support multiple outputs and multi-output filters like
split, which is why the sanctioned way to do your “branch
while moving forward” idea is a predeclared filtergraph, not a warm
decoder that keeps getting reused across separate CLI invocations.
citeturn865234search3turn865234search1turn865234search7
The part you’re zeroing in on — “why not just preserve the decode
state and keep going?” — is technically plausible in the abstract, but
it is not equivalent to saving one framebuffer. For
frame-accurate output, the relevant state includes decoder internals,
packet position, timestamp state, reordering state, audio/video sync
state, and container/muxing state. FFmpeg can preserve all that
within one running process through filtering, trimming,
and timestamp rebasing; that is exactly what
trim/atrim plus
setpts/asetpts are for. What it does
not give you as a normal user-facing primitive is
“serialize the current decoder/muxer state, then resume later for the
next exact clip” across many separate output jobs. That absence is much
more about architecture and interface than RAM scarcity.
citeturn865234search1turn865234search13
Your save-state analogy is fair, but there’s an important difference: emulators are built around preserving a single machine state as a core feature. FFmpeg is built around stream transformation, and its stable abstraction boundary is packets/frames/filters/outputs, not “checkpoint and resume this exact decode/mux session later.” The project has instead invested in two other solutions: fast but keyframe-bound seeking/stream copy, and accurate but decode-based trimming/filtering. FFmpeg’s own docs and wiki keep drawing that same line: accurate trimming is in the transcoding/filtering path, while fast splitting is constrained by keyframes. citeturn865234search0turn865234search5turn865234search1
So the blunt answer is: no, this is not just some dumb 1990s memory limitation that survived by accident. It’s more that FFmpeg never chose to make “incremental exact clip extraction with reusable decoder checkpoints” a first-class CLI workflow. Instead, it chose a model where, if you want one-pass exact branching, you describe all branches up front in a single graph. That is powerful, but ugly. The ugliness is real, and your complaint is valid. citeturn865234search1turn865234search3turn865234search7
Your idea of a “time-fix export” is actually pretty sensible conceptually, but it is not the same thing as two-pass encoding. Two-pass encoding stores rate-control statistics for the encoder so the second pass can allocate bitrate better; it is not a general serialized decode-state or seek-accuracy cache for future clip extraction. FFmpeg’s two-pass mode is documented in exactly that encoder-statistics sense. So you’re not wrong that a cached analysis pass is imaginable — you’re just describing a different feature than classic two-pass. citeturn865234search18
So my direct verdict is:
And yes: from a user-design perspective, there probably should be a cleaner “read once, emit many exact clips” front end than the current filtergraph pain. Your instinct there is solid.
M: Is there another, you know, well-known utility that I've just ignored because up until now, FFmpeg has been sufficient that does what I'm asking you to try and force FFmpeg to use or do? That seems like a more productive way to go in terms of research than continuing to try and hit my head against this communication wall. Because I understand what you're saying, and I understand what I'm saying, but the words to reconcile the two are beyond me. They involve a degree of jargon I just don't have access to at the moment. And if I let myself keep going down this road, I will get frustrated, simply because I know I'm not wrong, and I understand what you're saying about the direction FFmpeg has decided to go. But it feels like there should be a way to reconcile things with a tertiary file that I just don't have enough familiarity with the program or the decoding notion to be able to say whether it's a rational impulse or simply inaccessible without excessive effort. or some kind of piggyback utility which could begin or monitor FFmpeg as it decodes in this stream-merging slow version and ask it to pause and implement and export parallel process of Ffmpeg to write the clip without disrupting the original decode process
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
[Attachment reference unresolved: file_into]
G: [Non-text content: thoughts; content_type=thoughts]
[Attachment reference unresolved: file_into]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
[Attachment reference unresolved: file_into]
G: Yes, but not as a clean silver bullet.
The closest well-known alternatives break into three buckets:
1. LosslessCut — best if you mostly want fast, lossless, keyframe-bound extraction with a better front end than raw FFmpeg. It is explicitly built around fast lossless trimming/cutting and supports segment lists plus export/import of cut segments, but it is still FFmpeg-based under the hood, so it does not magically solve the exact-frame re-encode problem you’re talking about. citeturn532095search12turn148330search10turn532095search8
2. Avidemux — better if you want a GUI that can queue jobs and batch them more sanely. Avidemux has a queue/job workflow, so it can at least spare you the manual export-clicking, but it is still basically a batch-processing/editor approach, not a “persistent decoder checkpoint” system. citeturn532095search1turn532095search13turn148330search19
3. VapourSynth / AviSynth — best if what you really
want is scripted, frame-accurate trimming described
once in a cleaner language. Both expose trim operations directly;
VapourSynth’s Trim is frame-based, and AviSynth’s
Trim trims video while keeping audio synchronized.
VapourSynth can then pipe the result to FFmpeg or x264. This is probably
the nearest thing to the “tertiary file” idea you were circling around.
But it is not a magical pause/resume clip extractor either — it is a
cleaner frameserving/script layer on top of the same
general decode/encode reality.
citeturn148330search0turn148330search20turn148330search17turn148330search12turn148330search21
So the blunt ranking is:
What you are asking for — “read once, keep state, peel off many exact clips without repeatedly starting over” — is closest in spirit to a frameserver/editor pipeline, not to a lossless cutter. So the most productive research direction is probably VapourSynth, not yet another attempt to bully FFmpeg’s CLI into behaving like an editor. citeturn148330search8turn148330search12turn532095search7
My direct answer: yes, there are other tools, but no famous mainstream utility cleanly does exactly your dream workflow as a one-click batch extractor. The nearest serious alternative is VapourSynth as the control layer, with FFmpeg or x264 as the encoder/output stage. citeturn148330search12turn532095search7
[Attachment reference unresolved: file_into]
[Attachment reference unresolved: file-vs]
M: I want something Linux and command-line based for a script, if possible. Like I said, I'll send you the script so you can see what I want once we actually have access to it in a way I can use to get you the commands involved.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes: for Linux + command-line + scriptable + frame-accurate, the best thing to look at is VapourSynth.
Why:
Trim
is explicitly frame-based and inclusive. citeturn705417search7ffmpeg or an encoder, so it
works as a control layer instead of forcing all the
logic into one monstrous FFmpeg command.
citeturn705417search7turn705417search2What is not the answer for exactness:
If you mean “is there a shell utility that already does read-once, emit-many, exact clips from a list file, with sane syntax,” then the honest answer is: not a famous standard one. The nearest serious route is:
If you want a second thing to keep in mind:
splitmuxsink are built around splitting muxed
output, not your exact batch-trim use case.
citeturn705417search9turn705417search20So the short verdict is:
M: Well, keep those in mind, because once you've got the script, you'll have a better idea of the method I'm using right now, and you'll be able to say whether or not it can get what I need. One of the reasons this is frustrating is because for the clips, I actually don't need the audio. I would rather strip out every other stream except for the visual one, but that's the one that is giving me the most grief. My workflow has involved opening things up in the program, what is it? Avidemux, using its methods to navigate and find out where the scenes actually cut, and then the workaround I've got because it does not easily lend itself to that kind of arbitrary export is to have OCR capture an appropriate box and write that to a text file. And that's why I have to keep going through the FFmpeg trim version of things, because otherwise the timecodes don't exactly sync up with what Avidemux is able to find. And the current version of it necessarily works through a strictly numerical timestamp using decimal points rather than a frame count.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: That tracks.
Your bottleneck is not really “clip extraction” in the abstract, it’s this specific chain:
Avidemux finds the visual cut
→ OCR pulls the timestamp
→ text file stores decimal times
→ FFmpeg re-encodes from those times for accuracy
So the weak point is obvious: you’re using a frame-oriented discovery tool, then converting its result into time-based coordinates before handing it to FFmpeg. That translation layer is exactly where drift, mismatch, and repeated reprocessing pain get introduced.
The big things I’ll be looking for when you send the script are:
And yes, stripping everything except video should help simplify the pipeline logic, even if it doesn’t magically solve the decode-state issue by itself.
So at this point the real question is not “can FFmpeg clip video,” because obviously it can. The real question is whether your coordinate system is wrong for the job. Right now it sounds like it is.
M: There is not, as far as I or you have been able to discover, a utility that has a similar and rapid capacity to scan by frame while in a Linux environment. I used VirtualDub years ago, but that seems to be strictly a Windows build. And even if there is a Linux one, I'm currently trying to transition computers, so until that comes together, it's not something I want to muck about with using the current laptop. You realize you're allowed to go online to answer pretty much everything here, right? You weren't limited to the occasions where I gave you a specific task.
G: Yes—and you’re right to push on that, because there are a few relevant tools, but none line up perfectly with your exact combo of fast frame scanning + Linux CLI + scriptable output.
TLDR:
. and ,)
and fast seeking.But:
Still, this is the closest Linux-native equivalent to your Avidemux usage for finding cuts.
You can scan for scene changes with:
ffmpeg -i input.mp4 -vf "select='gt(scene,0.4)',showinfo" -f null -This outputs timestamps where scene changes are detected.
Or:
ffprobe -show_frames -select_streams v -show_entries frame=pkt_pts_time,pict_type input.mp4But:
Trim(start, end) by frame numberBut:
You’re not missing something obvious.
What you’re trying to do is essentially:
“Use a fast interactive viewer to identify exact frames, then export many exact clips efficiently in batch.”
And Linux tools split that into:
But nothing cleanly bridges them.
This part matters:
OCR → text file → FFmpeg
That’s not a hack because you’re sloppy—that’s a hack because the ecosystem does not provide a clean handoff mechanism between:
You basically built your own bridge.
When I see your workflow, the biggest improvement opportunity isn’t “find a better cutter,” it’s:
Move to frame numbers as the canonical unit
Why:
Based on everything so far, the direction is probably:
“Is there a Linux CLI tool like VirtualDub that does this cleanly?”
No.
Closest pieces:
But the glue between them is still DIY—which is exactly what you’ve been building.
Once you send the script, I’ll stop talking in abstractions and give you a concrete “replace X with Y” path instead of this ecosystem autopsy.
M: Okay, you're looking at things a little bit askew. The command line is for the processing, for the actual identification that requires a manual scanning of things and a graphic user interface that Avidemux provides in a really, really quick fashion, even though, well, sufficiently smooth in terms of both quick forward and backward scanning that it overrides a desire to go searching for something else, which might be a little bit more complete simply because, well, when I asked you about this problem in another silo, one of the things you suggested was VLC, and that simply does not have the degree of accuracy that I'm looking for intrinsically, and does not easily rewind in the way that I'm able to do with Avidemux, at least not without changing its interface sufficiently that it could start interfering with its usability as an actual media player.
G: Got it. That clarifies the separation cleanly:
So we don’t touch the front half. The fix lives entirely in how you transfer coordinates and how FFmpeg consumes them.
You’re not fighting FFmpeg.
You’re fighting:
Avidemux (frame-based reality) → OCR → decimal timestamps (lossy abstraction)
That’s where the friction and reprocessing cost comes from.
You don’t need a new utility.
You need to stop feeding FFmpeg time and instead feed it frame-accurate positions derived correctly.
There are two viable directions:
Right now you’re doing:
Instead:
This reduces drift but does not eliminate the structural issue.
Avidemux is showing you frames.
So instead of:
start_time → end_time
You want:
start_frame → end_frame
Then convert once:
time = frame / fpsAnd feed FFmpeg exact values.
Or go one step further and let FFmpeg do frame-based selection:
-vf "select='between(n,start,end)',setpts=PTS-STARTPTS"That bypasses timestamp ambiguity entirely.
You said:
“It should be able to just continue once it’s decoded”
It can—but only if the cut points are expressed in the same coordinate system as the decoder.
So FFmpeg has to:
every time
That’s the mismatch—not memory, not capability.
You said:
“I don’t need audio”
Good. Then you should always include:
-an -sn -dn -map 0:v:0That:
You’re not wrong choosing it.
Blunt comparison:
So: keep Avidemux
The fix is downstream.
I’m going to look for:
-ss / -toAnd then give you:
You’re not wrong about the intuition.
You just picked the wrong coordinate system to bridge GUI → CLI.
Fix that, and most of the “why is FFmpeg doing this over and over” frustration drops sharply.
M: Keep that in mind too. I'm not even going to look at that until you've seen the script that I'm using and recognize the accuracy that I'm having to deal with. Because if it was a simple question of frame repetition, then the numbers would repeat as well, etc., etc. But this has turned into a slog through decimal points that I do not see a rapid way to convert back into some kind of frame count. And even if it does exist, there's no good reason for me to figure it out right now because I'll have to reconstruct my awareness once I actually can start working on any improvements. That's a nice way of saying I'm walking away now without being completely rude about it.
G: Understood. We’ll leave it there until the script is in hand.
M: okay, this is the script that i'm using. it functions perfectly in my workflow in terms of giving the right output; our aim is to get equivalent output without it taking... what would it be for X clips of an mp4 of length T, something like X instantiations averaging .5T minutes to process, divided by the processing speed multiplier? point is, for a 24-minute anime episode, there are about 300 scenes - meaning that even though the scan-through time isn't real-time, it still takes that 3600 minutes of real-time effort...
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: TLDR: now that I’ve seen the script, the reason it’s slow is exactly what it looked like from the outside: you are doing 300 separate accurate transcodes from the original source. There is no hidden one-flag fix that keeps your current loop structure and suddenly makes it fast. fileciteturn1file0
Your hot spot is this line in practice:
ffmpeg -i "$inputFile" -nostdin -ss "$start" -to "$end" ... -vcodec libx264 ...Because -ss is after -i,
FFmpeg treats it as an output option, and the docs say
that in that mode it “decodes but discards input until the
timestamps reach position.” Also, FFmpeg options are applied to
the next input/output, so the order matters. That is why each clip
effectively re-reads and re-decodes from the start up to the cut point.
citeturn900173view2turn959183view0
So your choices are basically:
1. Keep this exact script shape
Accurate, but slow. No magic fix.
2. Generate one giant FFmpeg filtergraph from the edit
list
This is the true single-pass version. FFmpeg filters support multiple
outputs, and the trim filter can cut by time or by frame,
with setpts resetting timestamps after trim. So yes, FFmpeg
can do the whole episode in one decode pass. But for ~300 scenes, the
generated graph becomes monstrous.
citeturn959183view1turn945007view3
3. The practical route: make one intermediate file
first
This is the one I’d actually bet on.
The idea:
Why this helps:
So the honest verdict is:
Best exact-but-ugly: one generated
filter_complex pass.
Best practical improvement without reinventing your
workflow: one-time intra-only intermediate, then split
that.
Best “just keep the current shell loop with one small
tweak”: not really a thing. The current shape is intrinsically
expensive. citeturn900173view2turn945007view3turn959183view2
And one small side note: since you only care about video, add
-dn too when you clean streams, not just
-an -sn. That won’t solve the big problem, but it is at
least consistent with your stated goal. fileciteturn1file0
M: i already downmix everything to a lighter version using this; it makes the scanning easier too, because it is designed to optimize iframe creation (as opposed to modern situations which have enough bandwidth that iframes are more of a nice idea than a scene-change requirement)
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes — and this is the key distinction:
your current downmix is lighter, but it is not intra-only. It is still a normal long-GOP H.264 encode with scene-cut-friendly keyframes, not “every frame is self-contained.” fileciteturn2file0
This part is why:
keyint=250 means GOPs can still run up to 250
frames.scenecut=40 encourages extra keyframes at scene
changes, but does not make every frame independently
seekable.bframes=3 adds more inter-frame dependency, not less.
fileciteturn2file0So your current file is good for:
But it is not the kind of intermediate that eliminates the repeated decode penalty when you later do 300 exact cuts.
That lines up with FFmpeg’s behavior: with -ss used as
an output-side seek, FFmpeg decodes and discards until it reaches the
target position, and FFmpeg’s filtering docs are where the exact
multi-output trim path lives.
citeturn665783search0turn665783search1turn665783search4
So the blunt answer is:
Your current preprocessing helps the viewer and helps keyframe odds. It does not solve the extraction architecture problem.
If you want the “make the second stage much faster” version, the preprocessing file would need to be something closer to:
-g 1 /
keyint=1) orThat would be larger, but much friendlier for repeated accurate clipping. x264’s FFmpeg docs explicitly point users to x264’s own options, and intra-only output is the general concept you’d want here. citeturn665783search2turn665783search17
So the practical takeaway is:
That is the part worth keeping in mind before we touch the main script again.
M: i can always make two versions in the pre-processing. what cli command would you suggest for a similar speed increase for the actual clip extraction? as a separate question: i just gave you the third script from my general workflow, the one that creates a thumbnail from all the clips that the previous ones end up producing. would it be possible to eliminate the clip extraction step, and JUST get the appropriate frames from each defined scene, using the calculation in this script but expanded to target the frames from inside the original mp4? because the purpose of this effort isn't to have the entire catalog of scenes available - it's to have a catalog of thumbnails which would allow for selective scene extraction for amv creation without having to maintain a full scene catalog.
G: [Non-text content: thoughts; content_type=thoughts]
G: [Non-text content: reasoning_recap; content_type=reasoning_recap]
G: Yes.
For a second preprocessing version meant to speed up
later exact cuts, I’d make an all-intra video-only
proxy. The FFmpeg wiki’s VFX/encode guidance says intra-only
behavior is achieved with -g 1 and -bf 0, and
FFmpeg’s libx264 docs expose GOP control through x264 options.
citeturn267554search4turn267554search0
A practical command is:
ffmpeg -i "$1" -an -sn -dn -map 0:v:0 -c:v libx264 -preset veryfast -crf 20 -g 1 -bf 0 "$2-intra.mp4"That should make the clip extraction stage much faster than your current long-GOP downmix, at the cost of a much larger proxy file. Your current proxy still allows GOPs up to 250 frames and keeps B-frames enabled, so it helps scanning but not repeated exact extraction nearly as much. fileciteturn2file0
For the separate question: yes, you can probably
skip clip extraction entirely and generate the
thumbnail sheets straight from the original MP4 or, better, from the
proxy. That is the cleaner route for your stated goal. Your current
thumbnail script computes per-clip percentages, then seeks each clip
nine times and builds a montage. The same math can be applied directly
to each scene’s start,end pair from the edit list, so each
target time becomes:
scene_start + (scene_duration * fraction)
and then FFmpeg can grab those frames directly. That means:
The catch is performance: if you do it in the most literal way, that becomes 9 seeks per scene, so about 2700 frame grabs for a 300-scene episode. That is still likely better than fully encoding 300 scene clips, because you are only decoding enough to emit single frames instead of writing whole clip files, but it is not magically one-pass unless you generate a large filtergraph. FFmpeg’s filter system does support multi-output graphs, so a one-process solution is possible in theory, just ugly at this scale. citeturn267554search1turn267554search3
So the blunt verdict is:
And yes, once we’re focused on the thumbnail-only path, your current clip-extraction script becomes mostly unnecessary overhead.
M: if the rescanning is going to happen anyway, i might as well stick with the clipping; it means that i can hypothetically review errors easier, without having to completely dissect the original effort. i'll try making the second mp4 and see what happens in terms of speed.
G: That’s reasonable.
For your test, use:
ffmpeg -i "$1" -an -sn -dn -map 0:v:0 -c:v libx264 -preset veryfast -crf 20 -g 1 -bf 0 "$2-intra.mp4"What I’d expect:
One caution: if file size gets stupid, the first knob I’d touch is
CRF, not -g 1. Keep all-intra, just raise
CRF a bit.