ffmpeg/streamsaver [ Files ]
NAME
streamsaver - обработчик аудиопотоков с нарезкой их в файлы и
ретрансляцией на icecast
VERSION
1.0
DESCRIPTION
Сценарий принимает аудиопоток с оборудования, по UDP или TCP, фрагментирует его на отрезки заданной длины для последующего хранения и анализа, а также ретранслирует поток на сервер радиовещания icecast для прослушивания аудио конечным пользователем.
USAGE
streamsaver <файл настроек>
ARGUMENTS
- <файл настроек> - xml-файл с описанием входящего и выходящего потоков и правилами фрагментирования записей.
streamsaver/readOption [ Functions ]
[ Top ] [ streamsaver ] [ Functions ]
NAME
readOption - получение значения опции из файла настроек
USAGE
readOption <опция> <файл>
ARGUMENTS
- опция - имя опции
- файл - xml-файл с настройками
RESULT
Значение параметра при наличии искомой опции в xml-файле или значение по
умолчанию, которое задаётся при инициализации переменной config.
SOURCE
45 readOption() { 46 cfg=$(\grep -oPm1 "(?<=<$1>)[^<]+" "$2") 47 48 if [ ! -z "$cfg" ]; then 49 config[$1]=$cfg 50 fi 51 }
streamsaver/enableOption [ Functions ]
[ Top ] [ streamsaver ] [ Functions ]
NAME
enableOption - добавление опции к команде ffmpeg
DESCRIPTION
Процедура включает опцию, если в конфигурационном файле имеется соответствующая настройка.
USAGE
enableOption <опция>
ARGUMENTS
- опция - имя опции из массива настроек config.
SOURCE
71 enableOption () { 72 if [ ! -z "${config[$1]}" ]; then 73 CMD+=" $(echo $* | cut -d ' ' -f 2- | sed "s|%%|\"${config[$1]}\"|g")" 74 fi 75 }
streamsaver/readXML [ Functions ]
[ Top ] [ streamsaver ] [ Functions ]
NAME
readXML - чтение файла настроек
DESCRIPTION
Получение настроек из xml-файла.
USAGE
readXML <xml>
ARGUMENTS
- xml - файл настроек.
SOURCE
94 readXML() { 95 #Чтение настроек из файла 96 for option in ${!config[*]}; { 97 readOption "$option" "$1" 98 } 99 }
streamsaver/makeCMD [ Functions ]
[ Top ] [ streamsaver ] [ Functions ]
NAME
makeCMD - создание команды для оцифровки сигнала
DESCRIPTION
Процедура составляет команду ffmpeg, включая опции, если они заданы в конфигурационном файле или указаны значения по умолчанию в массиве настроек config.
Эталонные настройки ffmpeg
ffmpeg -reconnect 1 \
\
-i "${config[stream]}" \
-legacy_icecast 1 \
-content_type audio/mpeg \
-ice_name "Имя канала" \
-ice_description "Описание канала" \
icecast://source:${config[password]}@${config[icecast]}/${config[mountpoint]} \
\
-segment_list "./files_archive.csv" \
-segment_list_entry_prefix "$ARCHIVE_DIR" \
-segment_list_type "csv" \
-segment_list_flags "live" \
-segment_atclocktime 1 \
-acodec "$FORMAT" -f segment \
-segment_time "$ARCHIVE_TIME" \
-segment_format "$FORMAT" \
-strftime 1 "$ARCHIVE_DIR/$FILE_NAME"
\
-segment_list "./files_slices.csv" \
-segment_list_entry_prefix "$ARCHIVE_DIR" \
-segment_list_type "csv" \
-segment_list_flags "live" \
-segment_atclocktime 1 \
-acodec "$FORMAT" -f segment \
-segment_time "$SLICES_TIME" \
-segment_format "$FORMAT" \
-strftime 1 "$SLICES_DIR/$FILE_NAME"
Пример иерархии файлового хранилища:
FILES
├── archive
│ ├── TK04
│ │ └── CH4098
│ │ └── 2016-07-12_13:41:47-TK#4-4098.mp2
│ ├── TK05
│ │ └── CH4098
│ │ └── 2016-07-12_13:41:45-TK#5-4098.mp2
│ └── TK06
│ └── CH53
│ └── 2016-07-12_13:41:49-TK#6-53.mp2
└── fragments
├── TK04
│ └── CH4098
│ ├── 2016-07-12_13:41:47-TK#4-4098.mp2
│ └── 2016-07-12_13:41:50-TK#4-4098.mp2
├── TK05
│ └── CH4098
│ ├── 2016-07-12_13:41:45-TK#5-4098.mp2
│ └── 2016-07-12_13:41:50-TK#5-4098.mp2
└── TK06
└── CH53
└── 2016-07-12_13:41:49-TK#6-53.mp2
RESULT
Команда ffmpeg, которую можно передать на выполнение.
SOURCE
173 makeCMD() { 174 #Правило именования файлов 175 FILE_NAME="${config[filename_prefix]}-${config[channel_name]}-CH${config[channel_number]}.${config[filename_suffix]}" 176 177 #Минимальная команда 178 CMD="${config[cmd]} -f ${config[input_format]} -i ${config[stream]} -f ${config[output_format]}" 179 180 #КОДИРОВАНИЕ 181 # enableOption output_format -c %% 182 183 #ICECAST 184 if [ ! -z ${config[icecast]} ]; then 185 enableOption input_channel -map %% 186 enableOption audio_bitrate -ab %% 187 enableOption channel_name \ 188 -legacy_icecast 1 \ 189 -content_type audio/mpeg \ 190 -ice_name %% 191 192 enableOption channel_descr \ 193 -ice_description %% 194 195 enableOption icecast \ 196 icecast://source:${config[password]}@${config[icecast]}/${config[mountpoint]} 197 fi 198 199 # АРХИВ 200 enableOption input_channel -map %% 201 enableOption archive_log \ 202 -segment_list %% \ 203 -segment_list_entry_prefix "$(eval echo ${config[archive_dir]})" \ 204 -segment_list_type csv \ 205 -segment_list_flags live 206 207 # +СЕГМЕНТИРОВАНИЕ 208 enableOption archive_dir \ 209 -segment_atclocktime 1 \ 210 -acodec "${config[output_format]}" \ 211 -fi segment \ 212 -segment_time "${config[archive_time]}" \ 213 -segment_format "${config[output_format]}" \ 214 -strftime 1 "$(eval echo ${config[archive_dir]})/$FILE_NAME" 215 216 # АНАЛИЗ 217 enableOption input_channel -map %% 218 enableOption slices_log \ 219 -segment_list %% \ 220 -segment_list_entry_prefix "$(eval echo ${config[slices_dir]})" \ 221 -segment_list_type csv \ 222 -segment_list_flags live 223 224 # +СЕГМЕНТИРОВАНИЕ 225 enableOption slices_dir \ 226 -segment_atclocktime 1 \ 227 -acodec "${config[output_format]}" \ 228 -fi segment \ 229 -segment_time "${config[slices_time]}" \ 230 -segment_format "${config[output_format]}" \ 231 -strftime 1 "$(eval echo ${config[slices_dir]})/$FILE_NAME" 232 233 echo "$CMD" 234 }
streamsaver/config [ Variables ]
[ Top ] [ streamsaver ] [ Variables ]
VARIABLE
config - массив настроек, содержащий значения по-умолчанию.
Настройки описаны в секции SETTINGS.
USED BY
enableOption, readOption, readXML, makeCMD
SOURCE
250 typeset -A config 251 252 config=( 253 [proxy]="0" 254 [stream]="" 255 [icecast]="" 256 [password]="" 257 [channel_name]="" 258 [channel_number]="" 259 [channel_descr]="" 260 [mountpoint]="" 261 [cmd]="ffmpeg" 262 [input_format]="" 263 [input_channel]="" 264 [archive_dir]="" 265 [archive_time]="" 266 [archive_log]="" 267 [slices_dir]="" 268 [slices_time]="" 269 [slices_log]="" 270 [filename_prefix]="%Y-%m-%d_%H:%M:%S" 271 [filename_suffix]="mp3" 272 [output_format]="mp3" 273 [audio_bitrate]="256k" 274 )
streamsaver/SETTINGS [ Variables ]
[ Top ] [ streamsaver ] [ Variables ]
VARIABLE
SETTINGS - файл настроек
DESCRIPTION
Переменная хранит имя файла настроек, который содержит параметры, перечисленные в массиве опций config, в формате XML. При отсутствии параметра или пустом значении соответствующие флаги а аргументы не добавляются в итоговую команду ffmpeg. Таким образом, например, можно включать или отключать ведение журнала сохранения аудиозаписей, просто указывая или удаляя параметр archive_log.
Формат файла настроек следующий:
<xml>
<!-- Название канала -->
<channel_name></channel_name>
<!-- Описание канала -->
<channel_descr>Тестовый_канал</channel_descr>
<!-- Входящий поток -->
<stream>http://localhost:8000/tuc01
<!-- Icecast для вывода -->
<icecast>localhost:8000</icecast>
<!-- Пароль для доступа к Icecast -->
<password>hackme</password>
<!-- Точка подключения канала -->
<mountpoint>tuc02</mountpoint>
<!-- Программа/канал из потока -->
<input_channel>0:p:4098</input_channel>
<!-- Команда получения сигнала -->
<cmd>ffmpeg</cmd>
<!-- Формат входного потока -->
<input_format>mp2 -map 0:0</input_format>
<!-- Директория для сохранения архивных файлов -->
<!-- Может содержать переменную $DATA (текущую дату) -->
<archive_dir>FILES/archive/</archive_dir>
<!-- Длительность архивных файлов в секундах -->
<archive_time>3600</archive_time>
<!-- Файл журнала обработки архивных записей -->
<archive_log>FILES/archive.log</archive_log>
<!-- Директория для сохранения фрагментов на анализ -->
<slices_dir>FILES/fragments/</slices_dir>
<!-- Длительность фрагментов для анализа в секундах -->
<slices_time>10</slices_time>
<!-- Файл журнала обработки фрагментов на анализ -->
<slices_log>FILES/fragments.log</slices_log>
<!-- Префикс имени файла -->
<filename_prefix>%Y-%m-%d_%H:%M:%S</filename_prefix>
<!-- Расширение имени файла -->
<filename_suffix>mp2</filename_suffix>
<!-- Формат аудиофайлов -->
<output_format>mp2</output_format>
<!-- Битрейт аудиофайлов -->
<audio_bitrate>256k</audio_bitrate>
<!-- Использование streamproxy -->
<proxy>1</proxy>
</xml>
SOURCE
343 SETTINGS="$1"
streamsaver/main [ Toplevel ]
[ Top ] [ streamsaver ] [ Toplevel ]
NAME
streamsaver
SOURCE
354 #Проверка на наличие файла настроек 355 if [ -z "$SETTINGS" ]; then 356 echo "USAGE: $(basename $0) <settings.xml>" >&2 357 exit 1 358 elif [ ! -r "$SETTINGS" ]; then 359 echo "Unable open file $1." >&2 360 echo "USAGE: $(basename $0) <settings.xml>" >&2 361 exit 1 362 fi 363 364 #Чтение настроек 365 readXML "$SETTINGS" 366 367 #Текущая дата 368 DATE="$(\date +%F)" 369 370 #Создание директорий хранения файлов за текущую дату, если требуется 371 [ ! -z ${config[archive_dir]} ] && mkdir -p "$(eval echo ${config[archive_dir]})" 372 [ ! -z ${config[slices_dir]} ] && mkdir -p "$(eval echo ${config[slices_dir]})" 373 374 #Дата следующего дня 375 DATE="$(\date --date='tomorrow' +%F)" 376 377 #Создание директорий хранения файлов на следующий день 378 [ ! -z ${config[archive_dir]} ] && mkdir -p "$(eval echo ${config[archive_dir]})" 379 [ ! -z ${config[slices_dir]} ] && mkdir -p "$(eval echo ${config[slices_dir]})" 380 381 #Если используется прокси, то сигнал будет приниматься с соответствующего Icecast 382 if [ ${config[proxy]} == 1 ]; then 383 config[stream]="http://${config[icecast]}/${config[mountpoint]}" 384 config[input_format]="${config[output_format]}" 385 config[output_format]="copy" 386 config[input_channel]="" 387 config[icecast]="" 388 fi 389 390 #Создание команды оцифровки сигнала 391 makeCMD