1

I am trying to execute a find bash command to process hundreds of video files that are all named video-original.mp4 but are in subdirectories of a parent directory.

Here's an example of the directory structure:

videos
├── 01a
│   └── video-original.mp4
├── 01b
│   └── video-original.mp4
├── 02a
│   └── video-original.mp4
├── 02b
│   └── video-original.mp4
├── 03a
│   └── video-original.mp4
└── 03b
    └── video-original.mp4

I am using the following command:

find ./ -name 'video-original.mp4' -exec bash -c 'ffmpeg -i "$0" -f mp4 -vcodec libx264 -preset veryslow -profile:v high -acodec aac -movflags faststart video.mp4 -hide_banner' {} \;

The problem I am having is that it is saving the file video.mp4 in the parent videos directory, instead of in the subdirectory next to the original video-original.mp4

Afterwards, I want to delete the file video-original.mp4. Currently, my process entails waiting for all the videos to be reencoded, and then once complete, issuing a separate command to delete the file video-original.mp4:

find ./ -name 'video-original.mp4' -exec bash -c 'rm -rf "$0"' {} \;

And my final step would be to extract a screenshot of the new video.mp4 at 10 seconds and save it as thumbnail.jpg. Again, I am currently doing that as a separate step that I execute after the previous two steps are completed.

find ./ -name 'video.mp4' -exec bash -c 'ffmpeg -i "$0" -ss 00:00:10 -vframes 1 thumbnail.jpg' {} \;

What I would like to do is combine these three steps into a single command so the end result will be:

videos
├── 01a
│   ├── thumbnail.jpg
│   └── video.mp4
├── 01b
│   ├── thumbnail.jpg
│   └── video.mp4
├── 02a
│   ├── thumbnail.jpg
│   └── video.mp4
├── 02b
│   ├── thumbnail.jpg
│   └── video.mp4
├── 03a
│   ├── thumbnail.jpg
│   └── video.mp4
└── 03b
    ├── thumbnail.jpg
    └── video.mp4

Finally, it would be great to save that as a bash script and include it in my path in /usr/local/bin or ~/bin as an executable so I could just issue the command reencode and it would run. Would be even better if the input file could have any video file, for example, random_name.mp4 or random_name.mov or random_name.webm, basically any video file (but skipping video.mp4 at the encoding step).

Ali Samii
  • 1,672
  • 4
  • 28
  • 49

1 Answers1

1

I believe there might be two issues one being the path ./ — so maybe try using:

find . -name ...

Otherwise the path is translated as .//file, which doesn't seem correct.

The next issue is that since you are running the find command from the parent directory anything called with -exec is going to be output there. Instead we'll want to use -execdir since that will handle everything within the directory of the file it found. Since you want to create a command out of it we'll make it into a bash function which you can then add you to ~/.bash_profile or wherever you prefer to setup your environment.

encode () { export target=$2 ; find . -name "*$1*" \
! -name "$target" -execdir bash -c 'ffmpeg -i "$0" -f mp4 -vcodec libx264 \
-preset veryslow -profile:v high -acodec aac -movflags faststart "$target" \
-hide_banner -ss 00:00:10 -vframes 1 thumbnail.jpg' {} \; \
-execdir bash -c 'rm -f "$0"' {} \; ; }

Basically what this does is wrap the entire find command within a bash function which you can call from the command-line (once added to your profile, etc.):

$ encode mp4 video.mp4
          |      |
          |      |___ target file (encode will also skip this file)
          |
          |___ recursively encode files matching this extension

To summarize, the encode function wraps the find command, which in-turn searches recursively for any files matching the extension you select as argument one. The target (arg two) is the filename or output file to be saved. After the encoding is complete the original file that the target was encoded from is removed. If a file matches the extension you select and is within the same directory as the target then the matching file will be encoded to the target file (overwriting it); regardless of this the target file is always skipped and never encoded.

l'L'l
  • 44,951
  • 10
  • 95
  • 146