Recently bought an ip-cam which outputs a RTSP stream. I'm using the segment option of FFmpeg to create 60 minute long recordings.
I want FFmpeg to write the files to a directory based on Year/Month/Date
, and write to a file Hour-Minute.mp4
For example:
/raid1/homes/share/public/recordings/queue/bedroom/2017/04/23/13-05.mp4
for a recording started on 23 april 2017, 13:05.
Unfortunately FFmpeg seems to not create the directory hierarchy. FFmpeg quits since the directory can not be found.
Input #0, rtsp, from 'rtsp://192.168.1.240/unicast':
Metadata:
title : LIVE555 Streaming Media v2014.07.04
comment : LIVE555 Streaming Media v2014.07.04
Duration: N/A, start: 0.000750, bitrate: N/A
Stream #0:0: Video: h264 (High), yuv420p, 1920x1080, 90k tbr, 90k tbn, 180k tbc
Stream #0:1: Audio: pcm_alaw, 8000 Hz, 1 channels, s16, 64 kb/s
[segment @ 0x2557300] Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
[segment @ 0x2557300] Failed to open segment '/raid1/homes/share/public/recordings/queue/bedroom/2017/04/23/14-19.mp4'
Output #0, segment, to '/raid1/homes/share/public/recordings/queue/bedroom/%Y/%m/%d/%H-%M.mp4':
Metadata:
title : LIVE555 Streaming Media v2014.07.04
comment : LIVE555 Streaming Media v2014.07.04
encoder : Lavf57.41.100
Stream #0:0: Video: h264, yuv420p, 1920x1080, q=2-31, 90k tbr, 90k tbn, 90k tbc
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Could not write header for output file #0 (incorrect codec parameters ?): No such file or directory
record.sh is as follows:
#!/bin/sh
ffmpeg -stimeout 600\
-rtsp_transport udp \
-i rtsp://192.168.1.240/unicast \
-c copy \
-map 0:0 \
-f segment \
-segment_time 3600 \
-segment_wrap 100 \
-segment_format mov \
-strftime 1 \
-reset_timestamps 1 \
"/raid1/homes/share/public/recordings/queue/bedroom/%Y/%m/%d/%H-%M.mp4"
I've tried not using a directory hierachy: "/raid1/homes/share/public/recordings/queue/bedroom/%Y-%m-%d_%H-%M.mp4"
. This works fine.
$ ffmpeg -version
ffmpeg version N-80901-gfebc862 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
configuration: --extra-libs=-ldl --prefix=/opt/ffmpeg --mandir=/usr/share/man --enable-avresample --disable-debug --enable-nonfree --enable-gpl --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --disable-decoder=amrnb --disable-decoder=amrwb --enable-libpulse --enable-libfreetype --enable-gnutls --enable-libx264 --enable-libx265 --enable-libfdk-aac --enable-libvorbis --enable-libmp3lame --enable-libopus --enable-libvpx --enable-libspeex --enable-libass --enable-avisynth --enable-libsoxr --enable-libxvid --enable-libvidstab
libavutil 55. 28.100 / 55. 28.100
libavcodec 57. 48.101 / 57. 48.101
libavformat 57. 41.100 / 57. 41.100
libavdevice 57. 0.102 / 57. 0.102
libavfilter 6. 47.100 / 6. 47.100
libavresample 3. 0. 0 / 3. 0. 0
libswscale 4. 1.100 / 4. 1.100
libswresample 2. 1.100 / 2. 1.100
libpostproc 54. 0.100 / 54. 0.100
Can FFmpeg create output directories on the go?
There are three output files specified, and for the first two, no -map options are set, so ffmpeg will select streams for these two files automatically. out1.mkv is a Matroska container file and accepts video, audio and subtitle streams, so ffmpeg will try to select one of each type.
First ffmpeg searches for a file named arg .ffpreset in the directories $FFMPEG_DATADIR (if set), and $HOME/.ffmpeg, and in the datadir defined at configuration time (usually PREFIX/share/ffmpeg ) or in a ffpresets folder along the executable on win32, in that order.
out1.mkv is a Matroska container file and accepts video, audio and subtitle streams, so ffmpeg will try to select one of each type. For video, it will select stream 0 from B.mp4, which has the highest resolution among all the input video streams. For audio, it will select stream 3 from B.mp4, since it has the greatest number of channels.
Options may be set by specifying - option value in the FFmpeg tools, or by setting the value explicitly in the device AVFormatContext options or using the libavutil/opt.h API for programmatic use. Input devices are configured elements in FFmpeg which enable accessing the data coming from a multimedia device attached to your system.
Nope, FFmpeg can't do that 🤬
We can add a few lines to the top of your record.sh
script to create the directory for you, though.
#!/bin/sh
BASEDIRECTORY = /raid1/homes/share/public/recordings/queue/bedroom
YEAR=$(date +"%Y");
MONTH=$(date +"%m");
DAY=$(date +"%d");
# Create a directory tree for the day
# using the current year, month, and day
mkdir -p $BASEDIRECTORY/$YEAR/$MONTH/$DAY
# Start FFmpeg hourly recordings
ffmpeg -stimeout 600\
-rtsp_transport udp \
-i rtsp://192.168.1.240/unicast \
-c copy \
-map 0:0 \
-f segment \
-segment_time 3600 \
-segment_wrap 100 \
-segment_format mov \
-strftime 1 \
-reset_timestamps 1 \
"$BASEDIRECTORY/$YEAR/$MONTH/$DAY/%H-%M.mp4"
Now we just need record.sh
to restart overnight to create a new folder for the $DAY
. That sounds like a perfect job for cron: How to write a cron that will run a script every day at midnight?
Note: this script now requires root privilege so if you're getting the error below and cron
isn't working, make sure you're typing sudo ./record.sh
while testing and install your crontab as the root user like this: sudo crotab -u root -e
, as @dashesy points out in his comment.
This is because mkdir
with the -p
or --parent
option requires root privilege and if the directory isn't there FFmpeg will throw this error:
Failed to open segment '/raid1/homes/share/public/recordings/queue/bedroom/2019/01/31/10-37.mp4'
Could not write header for output file #0 (incorrect codec parameters ?): No such file or directory
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With