0

Command ffmpeg -i file-1.mp4 -vf ass=file-1a.ass burned-1.mp4

works to burn file-1a.ass subtitles on file-1.mp4 video.

But each time I have to reiterate the same command on over 40 different videos and subtitles and each time I have to wait for rendering the output.

So perhaps there is a way to automatically reiterate the same command on all the files.

Looking for a reply found the loop command for f in *; do ffmpeg $f;

But I am confused how to use it with 2 files, the .mp4 and the .ass file, and also the output file which should have the same number

I imagine should put the same name on each couple of files, such as: 1.mp4 1.ass 2.mp4 2.ass 3.mp4 3.ass etc

and then for f in *; do ffmpeg -i $f.mp4 -vf ass=$f.ass $f-output.mp4

But I have no clear idea

1 Answers1

1

You have the right idea. But it won’t work if the loop executes with f == 1.mp4, then again with f == 1.ass, and so on.

So you want to modify the loop to only iterate over .mp4 files. Then you want to strip the .mp4 extension from the value of f, that is, strip the last 4 characters from the value of f, using ${f:0: -4} (this means “get a substring of f, starting at character 0 and ending at 5 characters before the end”).

You obviously want to terminate the loop with done. I also suggest wrapping the parameters in quotes, to prevent word splitting (that is, if the filenames contain certain characters, they might be split into multiple arguments to ffmpeg).

Putting it all together:

for f in *.mp4; do f=${f%.*}; ffmpeg -i "$f.mp4" -vf ass="$f.ass" "$f-output.mp4"; done

Of course, once you have run this, you need to get rid of all the output files before you can run it again. Or you can just put the output files in a different directory to begin with.


Edit: Another user posted an answer, which seems to have been deleted. It was a good answer but lacked explanation. It was basically the same as my answer, except that it used ${f%.mp4} to strip the .mp4 extension. My answer is probably slightly more complex but slightly more efficient, so it’s basically a matter of personal preference.


Edit 2: Based on the link provided by llogan’s comment, I have made these changes:

  1. Remove the quotes in the assignment, as assignments are not subject to word splitting (this is also stated in the bash man page).
  2. Use ${f%.*} to strip the extension. This strips a dot followed by any sequence of characters from the end. It looks for the shortest possible match, so it’s really looking for a dot followed by any sequence of non-dot characters at the end.
Brian Drake
  • 346
  • 1
  • 8
  • 1
    You can make it more efficient by adding `-c:a copy` output option so the audio is copied instead of needlessly re-encoded. Too bad the other answer was deleted. It was using [bash parameter expansion](https://mywiki.wooledge.org/BashFAQ/073) to deal with the extension and is more robust in a general sense then chopping off a set number of characters. – llogan Oct 26 '20 at 19:26
  • Brian Drake answer works really very well. Many thanks. – user3428634 Oct 27 '20 at 01:24
  • llogan comment -c:a copy: how may I tell if it is working? – user3428634 Oct 27 '20 at 01:27
  • 1
    @user3428634 See console output. Look for `Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264)) Stream #0:1 -> #0:1 (copy) ` – llogan Oct 27 '20 at 02:17
  • @user3428634 Around here, we appreciate upvotes more than “thanks!”. Please hit that up button or, even better, mark this answer as accepted. – Brian Drake Oct 27 '20 at 14:41
  • Is it that what you mean by mark this answer as accepted? I clicked on button votes. But the up button? where is it? – user3428634 Oct 28 '20 at 18:10