sh script to encode IP camera frames


  • Impossible Mission Players - A

    So, I have a dumb IP camera that can upload frames on movement detection. This results in a folder of (thousands of) files like so:

    0_1513829546622_c565d83a-e788-4e35-9c2e-9acd54acba4b-image.png

    I'd like to craft a script that can take groups of them and smush them into video, and then delete them.

    For this, I know I have available to use ffmpeg, bash and cron, but tying them all together is leaving me scratching my head.

    Any hints on how to start? I think I need to:

    • Generate groups of files, probably based on hour and minute
    • Splat the list into ffmpeg (somehow) and provide an output file
    • Delete the files
    • Run this hourly by cron

    Any good pointers?



  • ffmpeg -pattern_type glob -i '000DC5D6F204()_1_20171222*_*.jpg' 20171222.mp4 && rm 000DC5D6F204\(\)_1_20171222*_*.jpg
    

  • Impossible Mission Players - A

    @ben_lubar Nifty. I think adding -r 3 at the beginning will let it slow the framerate down so the entire day doesn't go by in a minute, yes?

    How do I group it by hour?

    And can I overlay the filename for each frame?



  • @tsaukpaetra said in sh script to encode IP camera frames:

    @ben_lubar Nifty. I think adding -r 3 at the beginning will let it slow the framerate down so the entire day doesn't go by in a minute, yes?

    -r 3 will make it run at 3 FPS, assuming the container format and video codec support it.

    How do I group it by hour?

    Add another two digits to the filename prefix. You can generate those names with date '+[some percent signs and letters I guess]'

    And can I overlay the filename for each frame?


  • Impossible Mission Players - A

    Ok, I've come up with:

    #!/bin/sh
    cd /mnt/Security/video/MouseCam/grabs
    export target=000DC5D6F204\(\)_1_`date -v-1H +%Y%m%d%H`
    export dest=`date -v-1H +%Y%m%d-%H`.mp4
    
    echo "Targeting $target"
    echo "Destination file: $dest"
    
    ffmpeg -r 3 -pattern_type glob -i "${target}*_*.jpg" ${dest} && rm ${target}*_*.jpg
    
    echo Done.
    

    Here's to hoping nothing messes up, because I'm sticking it in the crontab and coming back in the morning...



  • @tsaukpaetra I'm not sure whether the unquoted ${target} will cause a syntax error due to the parentheses.



  • @tsaukpaetra Better quote all variable substitutions you don't want to expand special characters from, just in case:

    target="000DC5D6F204()_1_`date -v-1H +%Y%m%d%H`"
    dest="`date -v-1H +%Y%m%d-%H`.mp4"
    ffmpeg -r 3 -pattern_type glob -i "${target}*_*.jpg" "${dest}" && rm "${target}"*_*.jpg
    

    Also, this command is for BSD date(1), right?


  • area_can


  • area_can


  • Impossible Mission Players - A

    @aitap said in sh script to encode IP camera frames:

    @tsaukpaetra Better quote all variable substitutions you don't want to expand special characters from, just in case:

    target="000DC5D6F204()_1_`date -v-1H +%Y%m%d%H`"
    dest="`date -v-1H +%Y%m%d-%H`.mp4"
    ffmpeg -r 3 -pattern_type glob -i "${target}*_*.jpg" "${dest}" && rm "${target}"*_*.jpg
    

    Also, this command is for BSD date(1), right?

    Yes.


  • Impossible Mission Players - A

    @tsaukpaetra said in sh script to encode IP camera frames:

    nothing messes up

    Nothing messed up, because the damn thing didn't run.

    Apparently, my crontab entry was wrong:

    #Encode the mouse cam on the hour
    0	*	*	*	*	root /bin/sh /mnt/Security/video/MouseCam/grabs/splice.sh
    

    I'll figure that out later, for now Imma add a pre-process ffmpeg command to spudge the filename on the pictures.

    Revised script:

    #!/bin/sh
    
    cd /mnt/Security/video/MouseCam/grabs
    export target=000DC5D6F204\(\)_1_`date -v-1H +%Y%m%d%H`
    export dest=`date -v-1H +%Y%m%d-%H`.mp4
    
    echo "Targeting $target"
    echo "Destination file: $dest"
    
    echo "Stamping files..."
    
    for i in `ls ${target}*_*.jpg`; do 
        export time=$(echo $i | cut -d . -f 1)
        ffmpeg -loglevel panic -hide_banner -nostats -i $i -vf "drawtext=text='$time': fontcolor=white: box=1: boxcolor=black@0.7: boxborderw=2" -y $i
    done
    
    echo "Splicing..."
    
    ffmpeg -loglevel panic -hide_banner -nostats -r 3 -pattern_type glob -i "${target}*_*.jpg" ${dest} && rm ${target}*_*.jpg
    
    echo Done.
    


  • @tsaukpaetra said in sh script to encode IP camera frames:

    0 * * * * root /bin/sh /mnt/Security/video/MouseCam/grabs/splice.sh

    ITYM

    0 * * * * /mnt/Security/video/MouseCam/grabs/splice.sh
    

  • Impossible Mission Players - A

    @ben_lubar said in sh script to encode IP camera frames:

    ITYM

    Modeled after all the other entries that seem to work:

    0_1513922849257_70d00594-4dfc-4b85-ad8c-a87797f17ade-image.png

    The logfile claims it ran:

    Dec 21 21:30:00 namp /usr/sbin/cron[81622]: (root) CMD (/bin/sh /usr/local/etc/rc.d/dansguardian start)
    Dec 21 22:00:00 namp /usr/sbin/cron[91195]: (root) CMD (/bin/sh /mnt/Security/video/MouseCam/grabs/splice.sh)
    Dec 21 22:00:00 namp /usr/sbin/cron[91197]: (root) CMD (/root/transmission_remove_finished2.sh >> /var/log/Sickrage_Remove.log)
    Dec 21 22:00:00 namp /usr/sbin/cron[91198]: (root) CMD (/usr/local/bin/webalizer)
    Dec 21 22:00:00 namp /usr/sbin/cron[91199]: (root) CMD (/usr/local/bin/sarg >> /tmp/cron.sarg.log )
    Dec 21 22:00:00 namp /usr/sbin/cron[91200]: (root) CMD (/usr/local/bin/squid-analyzer --debug >> /tmp/cron.squida.log)
    Dec 21 22:00:00 namp /usr/sbin/cron[91201]: (root) CMD (/bin/sh /usr/local/etc/rc.d/dansguardian start)
    Dec 21 22:00:00 namp /usr/sbin/cron[91202]: (root) CMD (newsyslog)
    Dec 21 22:30:00 namp /usr/sbin/cron[94593]: (root) CMD (/bin/sh /usr/local/etc/rc.d/dansguardian start)
    Dec 21 23:00:00 namp /usr/sbin/cron[95977]: (root) CMD (/bin/sh /mnt/Security/video/MouseCam/grabs/splice.sh)
    Dec 21 23:00:00 namp /usr/sbin/cron[95979]: (root) CMD (/root/transmission_remove_finished2.sh >> /var/log/Sickrage_Remove.log)
    Dec 21 23:00:00 namp /usr/sbin/cron[95980]: (root) CMD (/usr/local/bin/webalizer)
    Dec 21 23:00:00 namp /usr/sbin/cron[95981]: (root) CMD (/usr/local/bin/sarg >> /tmp/cron.sarg.log )
    Dec 21 23:00:00 namp /usr/sbin/cron[95982]: (root) CMD (/usr/local/bin/squid-analyzer --debug >> /tmp/cron.squida.log)
    Dec 21 23:00:00 namp /usr/sbin/cron[95983]: (root) CMD (/bin/sh /usr/local/etc/rc.d/dansguardian start)
    Dec 21 23:00:00 namp /usr/sbin/cron[95984]: (root) CMD (newsyslog)
    

    Perhaps I'll add some redirection like others to see if there's an error or something.


  • Impossible Mission Players - A

    @tsaukpaetra said in sh script to encode IP camera frames:

    Perhaps I'll add some redirection like others to see if there's an error or something.

    Dec 22 00:01:00 namp /usr/sbin/cron[4480]: (root) CMD (/bin/sh /mnt/Security/video/MouseCam/grabs/splice.sh >> /mnt/Security/video/MouseCam/grabs/splice.log)
    Targeting 000DC5D6F204()_1_2017122123
    Destination file: 20171221-23.mp4
    Stamping files...
    Splicing...
    Done.
    

    It seems to believe it's working, but it's obviously not using the right directory, since nothing is... done?

    I'm at a loss. Only thing I can think of is to include the full path for everything?



  • @tsaukpaetra is the file saved anywhere on the disk? If so, maybe try printing current directory.



  • @tsaukpaetra maybe redirect stderr, too (>>logfile 2>&1)? Do a set -x in the beginning so that sh would print all commands that it actually tries to run?



  • @tsaukpaetra The only gotcha I remember about cron is that it does not use your environment (obviously, since it's not run in your session), so if e.g. one of the commands you call is not in its PATH, or something like that, it will fail.



  • @aitap said in sh script to encode IP camera frames:

    @tsaukpaetra maybe redirect stderr, too (>>logfile 2>&1)? Do a set -x in the beginning so that sh would print all commands that it actually tries to run?

    As long as we're using set, how about adding e in there as well, so that if the cd or ffmpeg or rm commands fail, the whole script stops?

    Also, @Tsaukpaetra, doing this is very dangerous:

    for i in `ls ${target}*_*.jpg`; do 
    

    You should always quote variables unless you want them to expand, especially if the place the variable was defined required quoting or backslashes, and `ls [something]` is very rarely if ever something you want to use, because it will throw away the hard work you did quoting your stuff. Just change it to this:

    for i in "$target"*_*.jpg; do
    

    That also saves you a subshell and one call to ls that contains all the names of jpeg files as arguments. In cases where ls would act differently than echo such as a directory matching the glob, this will break, but it will break anyway in the ls version, and it actually breaks less this way.

    Quote the $i in the next two lines while you're at it, for the same reason.

    Also, just in case you didn't know, quoting things in shell scripts is not the same as quoting things in most other programming languages - you can put multiple quoted and unquoted strings together as long as there's no whitespace. My favorite example of this is '"'"' in the middle of a single quoted string to insert a single quote. ('\'' also works but it's not as fun.) Double quotes around a variable will prevent it from being expanded into multiple arguments except in the case of "$@" and "$*", where it expands the way you would expect (instead of making everything messy).

    And as long as I'm giving you shell tips you didn't ask for, you can quote subshells like "`foo`" and you can skip the set command by changing the shebang (#!/bin/sh) to #!/bin/sh -ex. That makes errors in commands terminate the script and sets it to display every command it executes. The shebang (named for # followed by !, "hash bang") can actually contain any command - if you put #!/bin/echo there, your shell will print the path to the command instead of running it, for example.

    It's also worth pointing out that $foo*.txt should never be used, "$foo"*.txt is replaced with a list of files whose names start with the value of $foo and end with .txt, and "$foo*.txt" is replaced with the value of $foo followed by literal *.txt as one argument.



  • @gąska said in sh script to encode IP camera frames:

    @tsaukpaetra is the file saved anywhere on the disk? If so, maybe try printing current directory.

    On Linux, if a cron command has output, it gets mailed to the user owning the cron entry by default (usually sudo mail will show you). I'm not sure how it works for BSD.



  • I thought that systemd stuff replaced cron? Hopefully with something not nearly as ass-tastic.



Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.