编写Bash脚本实现MPEG-DASH直播流的视频编码与拼接自动化
MPEG-DASH直播流视频编码与拼接Bash脚本实现
我帮你编写了一个完全适配MPEG-DASH直播场景的Bash脚本,它能处理输入文件夹内的所有视频文件,完成编码、拼接及你提到的所有辅助功能。下面是完整实现和细节说明:
核心功能清单
- 批量读取输入文件夹内的视频文件
- 将所有视频编码为1080p、720p、480p三种分辨率格式,生成对应MPEG-DASH适配集
- 自动检查所有输入视频的帧率一致性,不一致时抛出提示并终止(避免拼接后播放异常)
- 强制将非1920×1080的输入视频缩放至1080p基准分辨率
- 为所有视频添加频道Logo图片(支持自定义位置和透明度)
- 自动裁剪视频结尾部分,确保所有视频以closed GOP结束,消除播放异常
- 最终将同分辨率的编码视频拼接为完整的适配集流
完整脚本实现
#!/bin/bash # 配置参数 INPUT_DIR="./input_videos" OUTPUT_DIR="./dash_output" LOGO_PATH="./channel_logo.png" LOGO_POS="10:10" # 左上角坐标,格式为x:y LOGO_OPACITY=0.8 # Logo透明度(0-1) TARGET_RES=("1920x1080" "1280x720" "854x480") TARGET_FPS=25 # 目标帧率,可根据需求修改 GOP_SIZE=50 # GOP大小,通常为2倍帧率 # 创建输出目录 mkdir -p "${OUTPUT_DIR}/temp" "${OUTPUT_DIR}/adaption_sets" # 检查依赖 if ! command -v ffmpeg &> /dev/null; then echo "错误:未找到ffmpeg,请先安装ffmpeg" exit 1 fi if [ ! -f "${LOGO_PATH}" ]; then echo "警告:未找到Logo文件 ${LOGO_PATH},将跳过Logo添加步骤" SKIP_LOGO=true fi # 第一步:检查所有输入视频的帧率一致性 echo "正在检查输入视频帧率..." REFERENCE_FPS=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 "${INPUT_DIR}"/* | head -n1) REFERENCE_FPS_NUM=$(echo "${REFERENCE_FPS}" | cut -d'/' -f1) REFERENCE_FPS_DEN=$(echo "${REFERENCE_FPS}" | cut -d'/' -f2) REFERENCE_FPS_DEC=$(echo "scale=2; ${REFERENCE_FPS_NUM}/${REFERENCE_FPS_DEN}" | bc) for VIDEO in "${INPUT_DIR}"/*; do CURRENT_FPS=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 "${VIDEO}") CURRENT_FPS_NUM=$(echo "${CURRENT_FPS}" | cut -d'/' -f1) CURRENT_FPS_DEN=$(echo "${CURRENT_FPS}" | cut -d'/' -f2) CURRENT_FPS_DEC=$(echo "scale=2; ${CURRENT_FPS_NUM}/${CURRENT_FPS_DEN}" | bc) if [ "${CURRENT_FPS_DEC}" != "${REFERENCE_FPS_DEC}" ]; then echo "错误:视频 ${VIDEO} 帧率(${CURRENT_FPS_DEC})与基准帧率(${REFERENCE_FPS_DEC})不一致" exit 1 fi done echo "所有输入视频帧率一致,继续执行..." # 第二步:处理每个视频(缩放、添加Logo、裁剪至closed GOP) echo "正在处理输入视频..." for VIDEO in "${INPUT_DIR}"/*; do VIDEO_NAME=$(basename "${VIDEO}" | cut -d'.' -f1) # 获取视频总帧数和时长 TOTAL_FRAMES=$(ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames -of default=noprint_wrappers=1:nokey=1 "${VIDEO}") # 计算需要裁剪的帧数,确保最后一个GOP是closed FRAMES_TO_KEEP=$(( (TOTAL_FRAMES / GOP_SIZE) * GOP_SIZE )) for RES in "${TARGET_RES[@]}"; do # 构建ffmpeg命令参数 FFMPEG_CMD="ffmpeg -i \"${VIDEO}\" -vf " # 添加缩放滤镜 FFMPEG_CMD+="scale=${RES}:force_original_aspect_ratio=decrease,pad=${RES}:(ow-iw)/2:(oh-ih)/2," # 添加Logo(如果存在) if [ -z "${SKIP_LOGO}" ]; then FFMPEG_CMD+="movie=${LOGO_PATH},format=rgba,colorchannelmixer=aa=${LOGO_OPACITY} [logo]; [in][logo] overlay=${LOGO_POS} [out]," fi # 裁剪至closed GOP FFMPEG_CMD+="trim=end_frame=${FRAMES_TO_KEEP} " # 编码参数(适配MPEG-DASH) FFMPEG_CMD+="-c:v libx264 -preset fast -crf 23 -g ${GOP_SIZE} -keyint_min ${GOP_SIZE} -sc_threshold 0 " FFMPEG_CMD+="-c:a aac -b:a 128k " FFMPEG_CMD+="-r ${TARGET_FPS} " FFMPEG_CMD+="-y \"${OUTPUT_DIR}/temp/${VIDEO_NAME}_${RES}.mp4\"" # 执行命令 echo "正在处理 ${VIDEO_NAME} -> ${RES}" eval "${FFMPEG_CMD}" done done # 第三步:拼接同分辨率的视频,生成适配集 echo "正在拼接视频生成适配集..." for RES in "${TARGET_RES[@]}"; do # 生成拼接列表文件 echo "file '${OUTPUT_DIR}/temp/'\$(basename %f)" > "${OUTPUT_DIR}/temp/concat_list_${RES}.txt" ls "${OUTPUT_DIR}/temp/"*"${RES}.mp4" | sort >> "${OUTPUT_DIR}/temp/concat_list_${RES}.txt" # 执行拼接 ffmpeg -f concat -safe 0 -i "${OUTPUT_DIR}/temp/concat_list_${RES}.txt" -c copy -y "${OUTPUT_DIR}/adaption_sets/adaption_set_${RES}.mp4" done # 清理临时文件 echo "清理临时文件..." rm -rf "${OUTPUT_DIR}/temp" echo "处理完成!适配集已保存至 ${OUTPUT_DIR}/adaption_sets/"
关键模块详解
1. 帧率一致性检查
脚本通过ffprobe读取第一个视频的帧率作为基准,遍历所有输入视频对比帧率,不一致时直接终止,避免拼接后出现播放跳帧或卡顿问题。
2. 分辨率强制缩放
使用ffmpeg的scale和pad滤镜,将非1080p的视频缩放至目标分辨率,同时保持原始宽高比,空白区域自动填充黑边,确保所有视频分辨率统一。
3. Logo添加功能
通过movie滤镜加载Logo图片,配合colorchannelmixer调整透明度,再用overlay滤镜将Logo放置在指定位置(默认左上角),如果未找到Logo文件会自动跳过该步骤。
4. Closed GOP裁剪
计算视频总帧数与GOP大小的整数倍,裁剪掉多余的结尾帧,确保每个视频都以完整的closed GOP结束,这是MPEG-DASH直播流避免播放异常的关键要求。
5. MPEG-DASH适配编码
使用libx264编码器,设置固定的GOP大小和keyint_min,关闭场景切换自动关键帧(sc_threshold 0),确保编码后的视频符合DASH直播的分段要求。
内容的提问来源于stack exchange,提问作者Massimo Vantaggio
相关产品推荐
相关产品推荐

