Keep FFMPEG encoding session running - bash

I am trying to encode an external HLS (m3u8) link into MPEG-TS over UDP via ffmpeg with this command:
ffmpeg -re -i http://example.com/index400.m3u8 -vcodec copy -acodec copy -f mpegts udp://127.0.0.1:10000?pkt_size=1316
Currently I am executing the command directly inside a terminal which I keep open on my Centos server. However, and after some time (volatile), I get the following error :
Failed to resolve hostname example.com: Temporary failure in name resolution
[hls,applehttp # 0x349b420] Failed to reload playlist 0
My question is, how can I run this command in a bash script or upstart or … so that whenever it unexpectedly stops, it automatically restarts.
I prefer not to use third parties like monit, and please be explicit in writing the script with annotation for newbies, I am not well experienced on this.

Turned out to be simpler than I thought. For future reference, this is what I did, in a terminal:
Create a new script:
vi test.sh
Insert the following code:
#!/bin/bash
while :
do
echo `ffmpeg -re -i http://example.com/index400.m3u8 -vcodec copy -acodec copy -f mpegts udp://127.0.0.1:10000?pkt_size=1316`
done
Press Esc W Q Enter to save and exit.
Execute the following commands:
chmod +x test.sh
./test.sh
And voilà, ffmpeg will automatically restart when an error occurs.

Related

Bash loop over files in directory outputting non existent files

I am making mp4 files from a series of images. The images should run about 1 hour but I cannot get a full video because FFMPEG looks for a file it should not have.
[image2 # 0x55fe14bef700] Could not open file : /mnt/run/image-005437.jpeg
What is confusing is that the list that I pass to ffmpeg should not include that file. If my script does not like the result it sends the file to a sub directory in the target folder called failed
the location of the file with that number
$ pwd
run/failed
]$ ls
failed-005437.jpeg
the command I use to launch ffmpeg is the following
image_folder=$1
singularity exec --bind $work_dir:/mnt $work_dir/longleaf2.sif ffmpeg -f concat -safe 0 -y -i <(for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done) -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4
I have checked processed images and it is not there so why is ffmpeg looking for it?
pastebin of the failed run
https://pastebin.com/pF5ZefLf
My check that the file is not in the folder reference by the for loop so that it should never cause an error
$ ls image-005437.*
ls: cannot access image-005437.*: No such file or directory
Problem
When you run:
for f in /mnt/processed_images/$image_folder/image-%06d.jpeg; do echo "file '$f'";done
It will output:
file '/mnt/processed_images/foo/image-%06d.jpeg'
So then ffmpeg will use the sequence pattern type for the image demuxer. This expects a contiguous sequence.
Solution 1: Glob
Use a glob:
for f in /mnt/processed_images/$image_folder/*.jpeg; do echo "file '$f'";done
Now it will output each file. In this example image-000003.jpeg does not exist so it does not get listed:
file '/mnt/processed_images/foo/image-000001.jpeg'
file '/mnt/processed_images/foo/image-000002.jpeg'
file '/mnt/processed_images/foo/image-000004.jpeg'
Solution 2: Simplify and skip concat
Even better is to simplify your command by using the glob pattern type for the image demuxer within ffmpeg itself, and then you can avoid the concat demuxer:
image_folder=$1
singularity exec --bind "$work_dir":/mnt "$work_dir"/longleaf2.sif ffmpeg -pattern_type glob -framerate 25 -i "/mnt/processed_images/$image_folder/*.jpeg" -vf "crop=trunc(iw/3)*2:trunc(ih/2)*2,format=yuv420p" -movflags +faststart /mnt/run/summary_files/${image_folder}.mp4
The image demuxer glob pattern is not available for Windows users.
Added the -framerate input option for the image demuxer.
Added the format filter to make YUV 4:2:0 chroma subsampling for compatibility.
The variables have been quoted. See shellcheck.net.
FFmpeg 4.1 release branch is old. Download or compile a modern version before doing anything else.

Passing file name in youtube-dl post-process script without file extension suffix

The documentation for youtube-dl says I can run a post-process command with the --exec option.
Using Windows, here is an example I have tried:
youtube-dl --exec "ffmpeg -i {} -ac 2 -c:a libfdk_aac -cutoff 20000 -afterburner 1 -vbr 0 {}.m4a" https://www.youtube.com/watch?v=sw9DlMNnpPM
Note that {} passes the file name to the post-process command. For example filename.webm.
The problem is that {} includes the file extension.
How can I pass the file name to the post-process command without the file extension?
For example, if I were to convert the video, I would rather avoid getting an output name like filename.webm.m4a. Needless to say, I would rather want filename.m4a.

Including Youtube-dl in FFMPEG not working in Bash (OSX)

I am trying to download 5 second samples for a list of youtube video. The traditional approach is to download the entire file with "youtube-dl" and then use "ffmpeg" to split it however you want it.
I am trying to use the following method: https://github.com/ytdl-org/youtube-dl/issues/622#issuecomment-162337869
It does work when I include the variables in the command, for example:
ffmpeg -ss 0 -i $(youtube-dl -f best --get-url https://www.youtube.com/watch?v=ySVi-0RS5vI&t=5s) -t 10 -c:v copy -c:a copy title2.mp4
However, I am having issues trying to automate the system. Specifically, I would like ffmpeg and youtube-dl to read a file and use the values. I created the file "youtube.txt" which includes the following codes:
440.8,https://www.youtube.com/watch?v=0-4wOE_DNeA,661.2,881.6,0-4wOE_DNeA
330,https://www.youtube.com/watch?v=0-AMWW6tHzw,495,660,0-AMWW6tHzw
509.2,https://www.youtube.com/watch?v=0-Rmto2rgMw,763.8,1018.4,0-Rmto2rgMw
427.6,https://www.youtube.com/watch?v=0-U53qm45cA,641.4,855.2,0-U53qm45cA
320.4,https://www.youtube.com/watch?v=0-dja9Ys4Sg,480.6,640.8,0-dja9Ys4Sg
343.6,https://www.youtube.com/watch?v=0-g_PulsqtM,515.4,687.2,0-g_PulsqtM
415.6,https://www.youtube.com/watch?v=0-nniRyn7dU,623.4,831.2,0-nniRyn7dU
431.2,https://www.youtube.com/watch?v=006BQU3BFxw,646.8,862.4,006BQU3BFxw
I am using the following command:
parallel -j 6 --colsep ',' ffmpeg -ss {1} -i $(youtube-dl -f best --get-url {2}) --t 5 -c:v copy -c:a copy {5} :::: youtube.txt
However, I get the following errors:
ERROR: '{2}' is not a valid URL. Set --default-search "ytsearch" (or run youtube-dl "ytsearch:{2}" ) to search YouTube
--t: No such file or directory
Would you mind helping me?
Thanks!
Here's a solution using python2, so this should work on the python version shipped with MacOS. My original bash script was choking on the csv line reading for some reason. Add this script to getvids.py in the same directory as your youtube.txt, then run chmod +x getvids.py and when you're ready to turn it loose ./getvids.py
#!/usr/bin/python
import csv, os
with open('youtube.txt') as csv_file:
csv_reader = csv.reader(csv_file, delimiter=',')
for row in csv_reader:
starttimes = [row[0], row[2], row[3]]
yturl = os.popen('youtube-dl -f best --get-url '+row[1]).read().strip()
for thistime in starttimes:
print(row[1] + ' #time='+thistime)
os.system('ffmpeg -hide_banner -loglevel panic -ss '
+thistime+' -i "'+yturl+'" -t 5 -c copy '+row[4]+'['+thistime+'s].mp4')

Limit cpu limit of process in a loop

I am trying to execute ffmpeg in a loop over multiple files. I only want one instance to run at a time, and to only use 50% of the cpu. I've been trying cpulimit but it isn't playing nice with the loop.
for i in {1..9}; do cpulimit -l 50 -- ffmpeg <all the options>; done
This spawns all nine jobs at once, and they are all owned by init so I have to open htop to kill them.
for i in {1..9}; do ffmpeg <all the options> & cpulimit -p $! -l 50; done
This hangs, ctrl+c continues to the next loop iteration. These instances can only be killed by SIGKILL.
Using a queue is the way to go. A simple solution that I use is Task Spooler. You can limit the number of cores ffmpeg uses with -threads also. Here's some code for you:
ts sh -c "ffmpeg -i INPUT.mp4 -threads 4 OUTPUT.mp4"
You can set the max number of simultaneous tasks to 1 with: ts -S 1
To see the current queue just run ts
You should run it in foreground. In this way the loop will work as expected.
$ cpulimit --help
...
-f --foreground launch target process in foreground and wait for it to exit
This works for me.
for file in *.mp4; do
cpulimit -f -l 100 -- ffmpeg -i "$file" <your options>
done
If you want the -threads option to have an effect on the encoder, you should put it after the -i argument, before the output filename - your current option only tells the decoding part to use a single thread. So to keep it all using a single thread, you want -threads 1 both before and after the -i option. so you can do it like:
ffmpeg -threads 1 -i INPUT.mp4 -threads 1 OUTPUT.mp4

Controlling psftp in a Windows Batch File

How do I write a batch file to control psftp, but with a dynamic filename? Overall I'm trying to convert a video file and then upload it to my Apple TV. Here's what I have, it generally works, but the commands don't control psftp, psftp just waits for user input:
echo Convert and Upload to Apple TV file Called %1.mkv
ffmpeg -i %1.mkv -vcodec mpeg4 -acodec ac3 -ab 384k -sameq -s hd720 -t 60 %1.avi
psftp frontrow#192.168.1.50 -pw aaa
cd downloads/boxee
put %1.avi
quit
I know with the -b flag psftp can call it's own batch file, but I don't know how to get the %1 argument to it. I've seen solutions where a text file is redirected to psftp, but that suffers from the same problem. Also, I'd prefer to have just one file, but having to call a second file would be alright too.
I ended up creating a new batch file from the main one that I then told psftp to use:
echo cd downloads/boxee > psftp.bat
echo put "%1.avi" >> psftp.bat
echo quit >> psftp.bat
psftp frontrow#192.168.1.50 -pw aaa -b psftp.bat
Specify a file containing batch commands
In normal operation, PSFTP is an interactive program which displays a command line and accepts commands from the keyboard.
If you need to do automated tasks with PSFTP, you would probably prefer to specify a set of commands in advance and have them executed automatically. The -b option allows you to do this. You use it with a file name containing batch commands. For example, you might create a file called myscript.scr containing lines like this:
cd /home/ftp/users/jeff
del jam-old.tar.gz
ren jam.tar.gz jam-old.tar.gz
put jam.tar.gz
chmod a+r jam.tar.gz
quit
and then you could run the script by typing
psftp user#hostname -b myscript.scr
Credit to http://the.earth.li/~sgtatham/putty/0.52/htmldoc/Chapter6.html#6.1.3
All in one file:
#echo off
echo Convert and Upload to Apple TV file Called %1.mkv
ffmpeg -i %1.mkv -vcodec mpeg4 -acodec ac3 -ab 384k -sameq -s hd720 -t 60 %1.avi
(
echo cd downloads/boxee
echo put %1.avi
echo quit
) | psftp frontrow#192.168.1.50 -pw aaa -bc
If we need the precise port number:
psftp frontrow#192.168.1.50 -P 222 -pw aaa -bc
Why not use the built in FTP command that comes with windows?
you will need to write a script that will upload the file:
open 192.168.1.50
user
frontrow
aaa
put file.avi
quit
then call ftp -s:MyScript
You will need to generate the script per each file using echo and the >> redirector.
I was struggling to run a simple batch file/script to have an end user upload a file she had just edited to a secure FTP site.
Using This Script:
cd /outgoing
put Examplefile.txt
# chmod a+r Examplefile.txt
# ren Examplefile.txt Exam.ted
# rm Examplefile.txt
quit
and running PuTTY's sftp command from a standard Windows command prompt:
psftp user#ftp.address.com -pw password -b testscript.scr
I was able to quickly and (more importantly!!) easily upload a file from the company I am doing work for to a company we needed to transact business with. You can also see I am ready to rename the file if needed (ren) or delete a file if needed (rm). The hash symbol (#) sets the lines as remark lines.
This allowed me to create a complete batch file in Windows that the end user could simply click on to upload the files as she generated them. It was MUCH simpler than using some of the other "flavors" of sftp I found on the 'Net and I have used and trusted PuTTY for decades.
If all you're doing with ftp is uploading a single file, you can use pscp.
echo Convert and Upload to Apple TV file Called %1.mkv
ffmpeg -i %1.mkv -vcodec mpeg4 -acodec ac3 -ab 384k -sameq -s hd720 -t 60 %1.avi
pscp -pw aaa -sftp %1.avi frontrow#192.168.1.50:/downloads/boxee

Resources