如何实现流中断后10秒自动重启?含现有脚本优化需求
问题与解决方案
问题背景
现有Bash脚本通过监控FFmpeg日志中的特定错误来重启HLS推流,但仍存在流中断无法自动恢复的情况,需要实现包括TS文件中断场景在内的流中断后10秒自动重启。
原监控脚本与FFmpeg推流命令如下:
原监控脚本
#!/bin/bash while true;do grep -c "Non-monotonous DTS in output stream" file.txt >nonmonotonus.txt grep -c "Timestamps are unset in a packet for stream" file.txt >timestamp.txt grep -c "PES packet size mismatch" file.txt >pespacket.txt grep -c "Error while decoding stream" file.txt >errordecoding.txt grep -c "Circular buffer overrun" file.txt >circularbuffer.txt grep -c "Header missing" file.txt >header.txt grep -c "Conversion failed" file.txt >conversion.txt file=nonmonotonus.txt file1=timestamp.txt file2=pespacket.txt file3=errordecoding.txt file4=circularbuffer.txt file5=header.txt file6=conversion.txt if (($(<"$file">=3000)) || (($(<"$file1">=500)) || (($(<"$file2">=100)) || (($(<"$file3">=1000)) || (($(<"$file4">=500)) || (($(<"$file5">=6)) || (($(<"$file6">=1)); then stream1 restart > restart.txt sleep 1 fi done
原FFmpeg推流命令
FFmpeg -re -threads 3 -c:s webvtt -i "$INPUT_URL?source=null&overrun_nonfatal=1&fifo_size=1000000" \ -c:v copy \ -map 0:0 -map 0:1 \ -c:a aac -b:a 128k -ar 48000 \ -threads 4 -f hls -hls_time 2 -hls_wrap 15 \ "manifest.m3u8" \ </dev/null > /dev/null 2>&1 2>file.txt & echo $! > $STREAM_PID_PATH
优化方案
针对原有脚本的不足,从进程存活监控、TS文件更新检测、错误日志优化、延迟重启逻辑四个维度改进:
1. 核心改进点
- 进程存活检测:直接检查FFmpeg的PID是否存在,避免进程崩溃后日志监控失效的情况。
- TS文件更新监控:HLS流正常时会持续生成新的.ts文件,若最近10秒无新TS文件生成,判定为流中断。
- 优化错误日志检测:改为实时跟踪日志新增错误,避免重复统计历史错误,同时保留原有错误阈值触发逻辑。
- 10秒延迟重启:触发重启条件后等待10秒,确认问题未自行恢复再执行重启,减少不必要的重启操作。
2. 优化后的完整脚本
#!/bin/bash # 配置参数 LOG_FILE="file.txt" STREAM_PID_PATH="/path/to/stream.pid" HLS_OUTPUT_DIR="./" # 替换为你的m3u8和ts文件所在目录 RESTART_DELAY=10 # 中断后延迟重启时间(秒) # 重启FFmpeg流的函数 restart_stream() { echo "$(date): 检测到流中断,${RESTART_DELAY}秒后重启..." sleep ${RESTART_DELAY} # 停止原有进程(如果存在) if [ -f ${STREAM_PID_PATH} ]; then OLD_PID=$(cat ${STREAM_PID_PATH}) kill ${OLD_PID} 2>/dev/null sleep 2 # 确保进程被杀死 kill -9 ${OLD_PID} 2>/dev/null rm -f ${STREAM_PID_PATH} fi # 启动新的FFmpeg推流 ffmpeg -re -threads 3 -c:s webvtt -i "$INPUT_URL?source=null&overrun_nonfatal=1&fifo_size=1000000" \ -c:v copy \ -map 0:0 -map 0:1 \ -c:a aac -b:a 128k -ar 48000 \ -threads 4 -f hls -hls_time 2 -hls_wrap 15 \ "${HLS_OUTPUT_DIR}/manifest.m3u8" \ </dev/null > /dev/null 2>&1 2>${LOG_FILE} & echo $! > ${STREAM_PID_PATH} echo "$(date): 流已重启,新PID为$(cat ${STREAM_PID_PATH})" } # 初始化错误计数器 declare -A error_counts=( ["Non-monotonous DTS in output stream"]=0 ["Timestamps are unset in a packet for stream"]=0 ["PES packet size mismatch"]=0 ["Error while decoding stream"]=0 ["Circular buffer overrun"]=0 ["Header missing"]=0 ["Conversion failed"]=0 ) # 错误阈值配置 declare -A error_thresholds=( ["Non-monotonous DTS in output stream"]=3000 ["Timestamps are unset in a packet for stream"]=500 ["PES packet size mismatch"]=100 ["Error while decoding stream"]=1000 ["Circular buffer overrun"]=500 ["Header missing"]=6 ["Conversion failed"]=1 ) # 实时监控逻辑 while true; do restart_triggered=0 # 1. 检查FFmpeg进程是否存活 if [ -f ${STREAM_PID_PATH} ]; then PID=$(cat ${STREAM_PID_PATH}) if ! kill -0 ${PID} 2>/dev/null; then restart_triggered=1 fi else restart_triggered=1 fi # 2. 检查TS文件是否在最近10秒更新 if [ ${restart_triggered} -eq 0 ]; then latest_ts=$(ls -t ${HLS_OUTPUT_DIR}/*.ts 2>/dev/null | head -n1) if [ -z "${latest_ts}" ]; then # 无TS文件,判定中断 restart_triggered=1 else ts_modified=$(stat -c %Y "${latest_ts}") current_time=$(date +%s) if [ $((current_time - ts_modified)) -gt ${RESTART_DELAY} ]; then restart_triggered=1 fi fi fi # 3. 检查日志错误是否超过阈值 if [ ${restart_triggered} -eq 0 ]; then # 实时读取新增的日志行 tail -n 0 -F ${LOG_FILE} | while read line; do for err_msg in "${!error_counts[@]}"; do if echo "${line}" | grep -q "${err_msg}"; then error_counts["${err_msg}"]=$((error_counts["${err_msg}"] + 1)) # 检查是否超过阈值 if [ ${error_counts["${err_msg}"]} -ge ${error_thresholds["${err_msg}"]} ]; then restart_triggered=1 break 2 # 跳出内层和外层循环 fi fi done done & TAIL_PID=$! sleep 5 # 每5秒检查一次错误计数 kill ${TAIL_PID} 2>/dev/null fi # 如果触发重启条件,执行重启 if [ ${restart_triggered} -eq 1 ]; then restart_stream # 重置错误计数器 for err_msg in "${!error_counts[@]}"; do error_counts["${err_msg}"]=0 done fi sleep 2 # 主循环间隔 done
3. 脚本说明
- 配置参数:根据实际环境修改
STREAM_PID_PATH、HLS_OUTPUT_DIR等路径参数。 - 进程管理:重启前会先终止原有FFmpeg进程,避免僵尸进程。
- TS文件检测:通过检查最新TS文件的修改时间,判断流是否正常生成片段。
- 错误日志跟踪:采用
tail -F实时读取新增日志行,仅统计新产生的错误,避免历史错误干扰。
内容的提问来源于stack exchange,提问作者Mr_Milky
相关产品推荐
相关产品推荐

