omxplayer - Seamless looping of a directory - ffmpeg

I'm trying to make a script/program that will seamlessly loop through all video files in a directory using omxplayer. So far my best solution was using ffmpeg to concat the videos of the directory and loop the output using omxplayer --loop output, but I've kept running into issues with different framerates and codecs of videos and the concating itself takes way longer than I can afford. Does anyone have a clue or a snippet on how digital signage software solutions loop their videos?

Try this.
#!/bin/sh
while : ;
do for f in /videos-location/*.mp4;
do omxplayer -n -l "$f";
done;
done

Related

vim diff fffmpeg output using command substitution

Why doesn't this work:
vim -d <(ffmpeg -i vid1.mp4 2>&1) <(ffmpeg -i vid2.mp4 2>&1)
and how can I get it to work?
Currently it just clears my screen completely and causes my terminal to freeze, completely unresponsive to everything ctrl-c ctrl-d and ctrl-z. I have to quit my terminal every time.
You must use ffprobe (comes with ffmpeg) if you want an output suitable for diffing:
$ vim -d <(ffprobe -i vid1.mp4 2>&1) <(ffprobe -i vid2.mp4 2>&1)
Why?
ffmpeg is a media converter that outputs a lot of things during processing, including some information on the source file. Using it without providing an output file/stream/whatever only to get information on the source file is not how it is supposed to be used and, well… it just doesn't work correctly anyway: you get your information but the terminal may be left in a weird state and the operation returns a non-zero status.
By using ffmpeg, you are essentially relying on a side-effect of using the wrong tool incorrectly.
ffprobe, on the other hand, exists specifically for getting information on the source file.
By using ffprobe, you are relying on the expected outcome of using the right tool correctly.
That said, ffprobe probably shares a lot of code with ffmpeg because you need that 2>&1 hack to make its output Vim-friendly. Oh well…

Bash single quote in filename and ffmpeg escaping

I want to convert a list of flac files to mp3 using ffmpeg.
I have written the list of files to convert in a file.
Here is my script
#!/bin/bash
while read -r line
do
ffmpeg -i "$line" -ab 320k "${line%.flac}.mp3"
done < flac_list
It works, however when a filename contains a single quote, it does not work.
And here begins my escaping nightmare.
I have found dozens of combinations without find how to make it work.
Could someone help ?
Thanks to #chepner, the -nostdin flag appended to ffmpeg solves the issue.
I have found too that ffmpeg has surprising problems sometimes if it encounters certain characters in the filename. I stumbled over this problem when converting m4a to mp3 using a script. I didn't know that an innocent single-quote is one of them.
What you can do - aside of reporting a bug to ffmpeg - is to test, whether your filename contains an unwanted character, and either rename the file or create a symbolic link to the file, using a "good" name, and undo these changes when your conversion is done.

AppleScript + QuickTime — batch trim + create edit + export video

I'm looking for some help.
What I'm trying to do is to have AppleScript open a folder of videos, then get QuickTime to randomly trim them (as in the start frame from where it trims) and then have a variable length of the trim itself (say random between 1sec to 2sec as boundaries for the new 'clip'). After trimming and creating the new 'edit' (it would add this new random trimming to all the videos in the folder then add to timeline). QT then needs to export the edit to a new folder.
In summary, trying to make a quick auto-editing app that can just pick random selects from a folder full of videos then save an edit to a new video.
ANY help with this would be hugely appreciated!
I've been trying but to nail avail (I'm fairly new to coding to going around in circles).
Thanks!
Dylan
Like #CJK, I would recommend you use bash and ffmpeg as they are both available on macOS and both better known and more widely applicable than Applescript and QuickTime.
IMHO, as Apple does not ship a package manager, you would be well advised to use homebrew to install, update and remove packages. It is available on the homebrew website.
Once you have that, you can find any package you want with:
brew search packageXYZ
So, you can now install ffmpeg with:
brew install ffmpeg
Now you would want a bash script that:
loops through all your ".mov" files in a directory
gets their lengths
calculates a random duration
calculates a random start time
extracts that piece of video as a clip
and, finally at the end, assembles all the clips together
That will look something like this, which I would suggest you save in a bash script called $HOME/RandomClips
#!/bin/bash
# Set up globbing
shopt -s nullglob nocaseglob
# Clear list of files we are going to concatenate
> list.txt
N=1
# Loop through all ".MOV" files
for f in *.MOV ; do
# Tell user which one we are processing
echo Processing file $f
# Get length of this video in seconds
duration=$(mdls -raw -name kMDItemDurationSeconds "$f")
echo ... Duration: $duration
# Generate a random clip length less than 5 seconds
((seconds=RANDOM%5))
echo ... Clip length: $seconds
# Generate start time
((start=RANDOM%(duration-seconds)))
echo ... Start time: $start
# Extract clip into file called "Clip-1.mov", "Clip-2.mov" etc
clipname="Clip-$N.mov"
echo ... Extracting $clipname
ffmpeg -hide_banner -ss $start -i "$f" -t $seconds -pix_fmt yuv420p "$clipname"
# Add name of this clip to the list of files to concatenate at the end
echo "file $clipname" >> list.txt
# Increment clip counter
((N=N+1))
done
# Now join together all the extracted clips into a single file
ffmpeg -hide_banner -f concat -i list.txt -c copy -pix_fmt yuv420p mergedVideo.mov
Now you need to make that executable, just necessary once, with:
chmod +x $HOME/RandomClips
Then use cd to navigate to a directory of movies:
cd some/place/with/movies
and run the script with:
$HOME/RandomClips
The script is not the most robust or well-tested in the entire world but it should be 90+% good. You may have to resize videos to a fixed size so they all match formats. Likewise with codecs. Probably ask another question if that becomes an issue.
No-one said answers have to be 100% perfect, and as no-one else has suggested anything, this will hopefully get you well on your way.
If you want to debug the script, you can:
read the debug output line by line
check all the extracted clips look correct, i.e, "Clip-1.mov", "Clip-2.mov"
read the file called "list.txt" to see if it contains all the clips

Output to pipe and file at the same time even if pipe isn't accepting inputs

So, I made a script for Cygwin that uses Windows's ImageMagick and FFmpeg, but I am not sure if the results here will also apply for bash on Linux. So, what the script does is I have some cartoon video files and I'm using Waifu2x to enhance and upscale the images to 4K, and then using ImageMagick to pipe it to FFmpeg, which is also used to resize it to 3840x2160 in case the resolution is slightly different. Here's a small script I wrote for this example to simplify how it outputs to FFmpeg, as the real script is extremely lengthy and complex.
#!/bin/bash
fun(){
convert out.png JPG:-|tee "$outfile"
}
fun|ffmpeg -f image2pipe -r 60 -i - -c:v libx265 -movflags +faststart "$outputfile"
Now, what I noticed is that if FFmpeg fails to encode, the function continues but fails to output to $outfile. What I want to do is have it able to output to that file in case the encoding fails since I also write all the images to a cache folder for FFmpeg to run through in case the encoding fails, but I also want to write to both the pipe for FFmpeg and the file at the same time. What seems to be happening is that the command tee appears to be refusing to write to the file if it can't write to the pipe. I'm not sure if this behavior is intended, and/or if it also does this on Linux bash. How can I get around this and have it write to the file even if it can't write to the pipe, but write to both at the same time rather than writing to the file and attempting to read it back to the pipe?
Have you tried tee with the -p option? It makes tee continue writing even if tee can't write to its standard output, which in your case means it should cope if ffmpeg fails.
fun() {
convert out.png JPG:- | tee -p "$outfile"
}

Learning Shell - creating a script with parameters that runs two separate cli apps

I want to learn shell script, so I'm trying to download a youtube video using youtube-dl then convert it to mp3 using ffmpeg.
I do it manually running youtube-dl http://youtube.com/watch?v=...
then
ffmpeg -i downloadedFile -ab 256000 -ar 44100 audioFile.mp3.
I know that I need to pass two arguments to my script, one for the video url and another for the audio file to keep things as simple as possible, but I don't know how to start. Maybe grep the video id in the url and using it to know which file to use to convert into mp3? (since youtube-dl saves the video named by it's id)
Can someone recommend me an article or documentation that can help me?
You can use the --output parameter of youtube-dl to have an arbitrary template. Additionally, youtube-dl can already convert to mp3! Try
#!/bin/sh
youtube-dl -o '%(title)s.%(ext)s' -x --audio-format mp3 -- "$1"
-o or --output defines the output name. You can use a number of templates, including %(title)s for the title of the video, %(ext)s for the extension, and %(id)s for the video ID. You can also use static filenames such as 'audio.%(ext)s, which will result in anaudio.mp3` file.
-x or --extract-audio advises youtube-dl to convert the video to an audio file (and remove the video file afterwards unless you pass -k). However, in contrast to your solution, youtube-dl will not recode audio streams that are already in mp3 - even with a relatively high bitrate such as 256k, you'll lose quality when you decode mp3 and re-encode it afterwards.
If you want a specific bitrate, use the --audio-quality parameter, say --audio-quality 256k.
The --audio-format parameter advises youtube-dl to convert audio to the given format. You can use best to always get the original audio (and not lose any quality), in whatever format it is.
"$1" is the first parameter of your shell script. You can pass in whole URLs, video IDs, or some shortcuts (like ytsearch:python to search YouTube for "python" and pick the first video.

Resources