分布式FFMPEG转码集群
分布式FFMPEG转码集群
- 分布式FFMPEG转码集群
- 思路
- 安装与配置
- 存储节点
- 计算节点
- 控制节点
- 使用方法和测试
- 结束语
- 更新日志
- [2018-06-27] 代码已上传到GitHub。项目链接: https://github.com/chn-lee-yumi/distributed_ffmpeg_transcoding_cluster
思路
- 分布式转码集群
- 暂时的目标: FFMPEG实现任意格式转MP4。
- 1控制节点,3计算节点。
- 存储暂时采用单节点的共享存储(NFS),可尝试分布式存储。
- 所有节点对CPU架构无要求,暂时用x86进行测试,后期加入ARM架构。
- 控制节点和计算节点通信暂时使用SSH。
- 思路: 控制节点收到请求,将文件传到共享存储,计算视频总帧数,然后发送命令给计算节点,不同节点按照各自权重(手动设置,可加性能测试功能)处理一定的连续帧,输出到共享存储,全部节点转码完毕后交由存储节点进行合并,并清理共享临时文件,最后控制节点返回转码后的视频链接。
安装与配置
- 测试组网:三台公网VPS cn.gcc.ac.cn, hk.gcc.ac.cn, us.gcc.ac.cn
- 存储节点:hk.gcc.ac.cn
- 控制节点:cn.gcc.ac.cn
- 计算节点:cn.gcc.ac.cn,hk.gcc.ac.cn,us.gcc.ac.cn
存储节点
- 存储节点系统是Debian
# 安装NFS
apt-get install nfs-kernel-server
# 新建共享文件夹,用于放渲染前上传的文件、渲染后的分片文件、渲染后的完整文件。
mkdir -p /srv/distributed_ffmpeg_transcoding_shared_files
mkdir /srv/distributed_ffmpeg_transcoding_shared_files/upload
mkdir /srv/distributed_ffmpeg_transcoding_shared_files/tmp
mkdir /srv/distributed_ffmpeg_transcoding_shared_files/download
chmod -R 777 /srv/distributed_ffmpeg_transcoding_shared_files
- 修改文件
/etc/exports
,将目录共享出去 - upload目录,控制节点有读写权限,计算节点有只读权限
- tmp,计算节点有读写权限
- download目录,存储计算节点有读写权限(由于这里只有单节点存储,就不需要共享了)
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check)
#
/srv/distributed_ffmpeg_transcoding_shared_files/upload cn.gcc.ac.cn(ro,insecure) us.gcc.ac.cn(ro,insecure)
/srv/distributed_ffmpeg_transcoding_shared_files/tmp cn.gcc.ac.cn(rw,insecure) us.gcc.ac.cn(rw,insecure)
- 注:特别注意要用insecure,否则会挂载不上,显示access denied。这个坑了我好久。
- 修改完后用
exportfs -arv
生效。可以使用showmount -e
查看。
计算节点
# 新建目录
mkdir -p /srv/distributed_ffmpeg_transcoding_shared_files/upload
mkdir -p /srv/distributed_ffmpeg_transcoding_shared_files/tmp
# 挂载NFS,这里只是临时挂载,可以修改fstab或开机启动脚本进行自动挂载
mount hk.gcc.ac.cn:/srv/distributed_ffmpeg_transcoding_shared_files/upload /srv/distributed_ffmpeg_transcoding_shared_files/upload
mount hk.gcc.ac.cn:/srv/distributed_ffmpeg_transcoding_shared_files/tmp /srv/distributed_ffmpeg_transcoding_shared_files/tmp
# 安装ffmpeg
apt-get install ffmpeg
- 注:现在jessie要在
source.list
添加deb http://ftp.debian.org/debian jessie-backports main
才能找到这个包。
控制节点
# 生成ssh公钥并拷贝到计算节点
ssh-keygen -t rsa
ssh-copy-id -i ~/.ssh/id_rsa.pub hk.gcc.ac.cn # 拷贝公钥到计算节点
ssh-copy-id -i ~/.ssh/id_rsa.pub us.gcc.ac.cn -p 10022 # 拷贝公钥到计算节点,这个节点的ssh端口是10022
# 创建并挂载upload目录
mkdir -p /srv/distributed_ffmpeg_transcoding_shared_files/upload
mount hk.gcc.ac.cn:/srv/distributed_ffmpeg_transcoding_shared_files/upload /srv/distributed_ffmpeg_transcoding_shared_files/upload
保存下面这个脚本并加执行权限,名字随意,我保存为dffmpeg.sh。
#!/bin/bash
# 分布式FFMPEG转码 v1.2
# 支持任意格式视频转成MP4
# Usage:dffmpeg.sh [input_file] [ffmpeg_output_parameter]
# Usage:dffmpeg.sh test.mp4
# Usage:dffmpeg.sh test.mp4 -c mpeg4
# Usage:dffmpeg.sh test.mp4 -c mpeg4 -b:v 1M
# TODO:?###配置项
storage_node="hk.gcc.ac.cn"
storage_node_ssh_port=22
compute_node=("us.gcc.ac.cn" "hk.gcc.ac.cn" "cn.gcc.ac.cn") # 计算节点
compute_node_ssh_port=(10022 22 22) # 计算节点的ssh端口
compute_node_weight=(10 50 15) # 计算节点的权重
nfs_path=/srv/distributed_ffmpeg_transcoding_shared_files #共享目录
###配置项结束upload_path=$nfs_path/upload
tmp_path=$nfs_path/tmp
download_path=$nfs_path/download
input_file=$1
ffmpeg_output_parameter=${@:2}# display函数,输出彩色
ECHO=`which echo`
display(){local type=$1local msg=${@:2}if [[ $type = "[Info]" ]]; then$ECHO -e "\\033[1;36;40m[Info] $msg \\033[0m"elif [[ $type = "[Error]" ]]; then$ECHO -e "\\033[1;31;40m[Error] $msg \\033[0m"elif [[ $type = "[Exec]" ]]; then$ECHO -e "\\033[1;33;40m[Exec] $msg \\033[0m"elif [[ $type = "[Success]" ]]; then$ECHO -e "\\033[1;32;40m[Success] $msg \\033[0m"else$ECHO -e $@fi
}### 开始函数重载
# 重载cp,记录log
CP=`which cp`
cp(){local src=$1local dst=$2display [Exec] cp ${@:1}$CP ${@:1}
}
# 重载rm,记录log
RM=`which rm`
rm(){display [Exec] rm ${@:1}$RM ${@:1}
}
# 重载ssh,记录log
SSH=`which ssh`
ssh(){display [Exec] ssh ${@:1}$SSH ${@:1}
}
### 函数重载完毕# 检查输入文件
if [ -f $input_file ]
thendisplay [Info] Input: $input_filedisplay [Info] FFmpeg output parameter: $ffmpeg_output_parameterfilename=$(date +%s) # 用时间戳做文件名display [Info] Uploading file, please wait a while. Temporary filename: $filenamecp $input_file $upload_path/$filename
elsedisplay [Error] Input error!exit
fi# 计算计算节点总权重
total_weight=0
for i in ${compute_node_weight[*]}
dototal_weight=$[$total_weight + $i]
done
display [Info] Compute node total weight: $total_weight# 分发任务
video_length=$(ffprobe -show_format $input_file -loglevel error| grep duration | awk -F = '{printf $2}')
part_start=0
part_end=0
node_number=${#compute_node[*]}
# for i in {0..${#compute_node[*]}} # 不知为啥不能这样写
for ((i=0; i<$node_number; i++))
do# echo ${compute_node[$i]},${compute_node_weight[$i]} # 显示计算节点及其权重part_end=$(echo "scale=2; $part_start + $video_length * ${compute_node_weight[$i]} / $total_weight" | bc )display [Info] Compute node ["${compute_node[$i]}"] : start[$part_start] , end[$part_end]# ssh ${compute_node[$i]} -p ${compute_node_ssh_port[$i]} "ffmpeg -ss $part_start -i $upload_path/$filename -to $part_end $ffmpeg_output_parameter $tmp_path/${filename}_$i.mp4 -loglevel error; touch $tmp_path/${filename}_$i.txt" & # -ss在前面,The input will be parsed using keyframes, which is very fast. 但可能会造成视频部分片段重复。ssh ${compute_node[$i]} -p ${compute_node_ssh_port[$i]} "ffmpeg -i $upload_path/$filename -ss $part_start -to $part_end $ffmpeg_output_parameter $tmp_path/${filename}_$i.mp4 -loglevel error; touch $tmp_path/${filename}_$i.txt" & # -ss在后面,速度会变慢,但是不会造成视频片段重复part_start=$part_endecho "file '${filename}_$i.mp4'" >> $tmp_path/${filename}_filelist.txt
done # 不断检查任务是否完成
display [Info] Checking if the tasks are completed.
while :
dofor ((i=0; i<$node_number; i++))doif [ -f $tmp_path/${filename}_$i.txt ]thenif [ $i==$[$node_number - 1] ] # 如果全部完成了thenbreak 2elsecontinuefielsebreakfidonesleep 1display ".\c"
done
display !# 进行视频拼接
display [Info] Tasks all completed! Start to join them.
ssh $storage_node -p $storage_node_ssh_port "ffmpeg -f concat -i $tmp_path/${filename}_filelist.txt -c copy $download_path/$filename.mp4 -loglevel error"#清除临时文件和上传的文件
display [Info] Clean temporary files.
rm -r $tmp_path/${filename}*
rm $upload_path/${filename}display [Success] Mission complete! Output path: [$download_path/$filename.mp4]# ffmpeg常用命令。参考 https://www.cnblogs.com/frost-yen/p/5848781.html#ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 test.mp4 # 计算帧数量,参考 https://stackoverflow.com/questions/2017843/fetch-frame-count-with-ffmpeg# 截取视频,参考 https://trac.ffmpeg.org/wiki/Seeking
#ffmpeg -ss 00:01:00 -i test.mp4 -to 00:02:00 -c copy cut.mp4
#ffmpeg -ss 1 -i test.mp4 -to 2 -c copy cut.mp4
#ffmpeg -ss 1 -i test.mp4 -t 1 -c copy -copyts cut.mp4
# 获取视频长度
#ffprobe -show_format test_video.mp4 | grep duration | awk -F = '{printf $2}' > /tmp/1.txt# 合并视频 https://blog.csdn.net/doublefi123/article/details/47276739
使用方法和测试
- 在控制节点运行:
dffmpeg.sh test.mp4 -c mpeg4 -b:v 1M
- 其中test.mp4为需要转码的文件,mpeg4是编码格式,1M是视频码率。
- 最后会输出一个mp4文件在download目录。
- 由于我的三个服务器分布在公网不同地域,瓶颈在NFS的读写速度,所以最终转码速度会比较慢。如果服务器先缓存了要转码的文件,那么最终转码速度是比一台服务器转码快的。
- 代码运行效果如下图
结束语
- 觉得这个好玩,所以我就写了。本来是打算用几个树莓派做测试的,不过树莓派现在只有一个,先用VPS测试一下。
- 脚本中有一段注释了的代码
for i in {0..${#compute_node[*]}}
,这是我一开始的写法,但是发现不能用。我不知道为什么不能那样写,所以写成for ((i=0; i<$node_number; i++))
。如果知道答案的还请指点一下。 - 我觉得
不断检查任务是否完成
那部分的判断代码不大好看,不知道有没有更简洁的方法。
更新日志
- v1.1:修复问题:最后的视频长度会比原来长。原因在于
-ss
参数的位置,详见代码注释。 - v1.2:新增内容:支持FFmpeg输出参数。输出彩色详细信息。
分布式FFMPEG转码集群相关推荐
- 网易视频云分享:如何搭建视频转码集群
随着媒体技术的发展,以及硬件设备的普及和移动设备的触角延伸之社会各个角落,人们可以随时随地产生信息.而这些海量信息中,有不少多媒体信息.多媒体信息成为了人们信息分享的重要方式.毫不夸张地说,现在是一个 ...
- 如何搭建视频转码集群、播放服务器
本文由作者张远道授权网易云社区发布. 转码集群的搭建 随着媒体技术的发展,以及硬件设备的普及和移动设备的触角延伸之社会各个角落,人们可以随时随地产生信息.而这些海量信息中,有不少多媒体信息.多媒体信 ...
- 搭建高吞吐量 Kafka 分布式发布订阅消息 集群
搭建高吞吐量 Kafka 分布式发布订阅消息 集群 简介 Kafka 是一种高吞吐的分布式发布订阅消息系统,能够替代传统的消息队列用于解耦合数据处理,缓存未处理消息等,同时具有更高的吞吐率,支持分区. ...
- 大数据之-Hadoop完全分布式_完全分布式模式下的集群配置---大数据之hadoop工作笔记0034
然后前面我们准备好了,完全分布式下用的集群环境,下面我们,开始配置hadoop集群 我们这里用hadoop102,hadoop103,hadoop104 这3台机器. 需要hadoop102,103, ...
- 分布式协调服务Zookeeper集群搭建
分布式协调服务Zookeeper集群搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装jdk环境 1>.操作环境 [root@node101.yinzhengjie ...
- hadoop历史背景hdfs分布式文件系统hadoop的集群模式单机模式伪分布
hadoop历史背景&hdfs分布式文件系统&hadoop的集群模式&单机模式&伪分布 1.hadoop的历史背景 lucense ---->nutch----& ...
- ⑬云上场景:蜻蜓fm,基于ECS构建的转码集群
蜻蜓fm是华语地区最好的收音机APP,同样是年度App Store最佳收听广播电台的工具.提供全球3000多个电台频道,以及点播内容,24小时不间断提供在线收听,打造跨地域收听广播的完美服务. 蜻蜓与 ...
- Zookeeper命令操作(初始Zookeeper、JavaAPI操作、分布式锁实现、模拟12306售票分布式锁、Zookeeper集群搭建、选举投票)
Zookeeper命令操作(初始Zookeeper.JavaAPI操作.分布式锁实现.模拟12306售票分布式锁.Zookeeper集群搭建.选举投票) 1.初始Zookeeper Zookeeper ...
- 分布式 - 分布式体系架构:集群和分布式
文章目录 01. 什么是集群? 02. 集群为什么可以提高系统的可靠性? 03. 集群为什么可以提高系统的性能? 04. 什么是分布式计算? 05. 如何进行分布式计算? 06. 集群如何提高计算效率 ...
最新文章
- 几张图帮你弄清楚什么是 RPC
- php xxtea加密,PHP实现的XXTEA加密解密算法示例
- 搜索引擎爬虫蜘蛛的UserAgent收集
- Android配置build.gradle解锁更高逼格玩法(多版本共存、分服务器打包等)
- React Native开发环境搭建记录
- echarts控制只显示部分数据的折线图_Python数据可视化之pyecharts入门
- 1-9其他数据库注入
- php怎么创建进程,在php中为长时间运行的进程创建后台进程
- java 接口与包_java常用类包接口
- Python实现二分法搜索
- 《信息处理技术员考试考前冲刺预测卷及考点解析》下午案例复习重点
- hive-0.11.0安装方法具体解释
- 对PV操作问题的理解综合
- java collections_[20]-Collections工具类
- leetcode刷题正则表达式
- Illustrator 教程,如何在 Illustrator 中重新塑造文本?
- 基于Echarts5实现的动态排序柱状图
- linkedblockingqueue 后 take 不消化_消化不良的症状原因有哪些?
- boost::filesystem使用手册
- kali安装loic
热门文章
- 基于STM32F103移植FreeRTOS教程
- 连接linux的一些工具
- OpenCV将BGR转换为NV12
- Archlinux 安装桌面环境 dwm + polybar
- 图片大小如何调整到100k?如何把图片改成100kb以内?
- 内核启动错误:use vmalloc=size to increase size.
- 【Linux:CentOS7】查看JDK版本信息报错解决
- MATLAB运用——设计船舶模型
- 百度Java面试题前200页。
- 博杰声学测试软件,音频分析仪 - Audio Precision 官方网站 - 声学和音频测试公认的标准...