近期做了一個視頻培訓項目,使用了文件服務器存放視頻文件。但是播放效果不理想,部分手機端用戶(主要是移動的4G網絡下)播放非常不流暢,
經過一輪探討和諮詢,解決方案如下:
1. 諮詢服務器租賃房,得知服務器默認申請的電信的IP網段,因此又申請了移動的ip網段,這樣可根據用戶的運營商給其分配對應的訪問ip。(如果有域名可使用DNS判斷匹配,否則只能通過ip手動匹配)
2. 視頻做了流化處理。原視頻是mp4文件,使用的是開源的ffmpeg
步驟1: 安裝ffmpeg工具
不管時windows還是linux安裝都很簡單。但是在linux安裝需要注意的是需要一個插件。需要指定libx264
這裏貼出我重新安裝的步驟:(參考)
#yum安裝必要包
yum install autoconf automake cmake freetype-devel gcc gcc-c++ git libtool make mercurial nasm pkgconfig zlib-devel
#安裝x264
git clone --depth 1 git://git.videolan.org/x264
ls
cd x264
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" ./configure --enable-static
報錯,需要安裝nasm 至少2.14,不能用yum install nasm,yum安裝是last版本
wget http://www.nasm.us/pub/nasm/releasebuilds/2.14/nasm-2.14.tar.xz
ls
tar Jxvf nasm-2.14.tar.xz
ls
cd nasm-2.14
ls
./configure
make && make install
cd ../x264
ls
# 指定PKG_CONFIG_PATH,不指定則在安裝ffmpeg就算加--enable-libx264,也會提示找不到。不加,則在轉換時提示unknow encoder libx264
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig" ./configure --enable-static
make && make install
cd ..
# 檢查是否安裝成功
ffmpeg -version
# 安裝時默認時加入環境變量,所以在任何地方執行就可以。提示如下,重點是有libx264字樣
[java@iZt4n36uo36nxgg8z2hb2kZ ffmpeg]$ ffmpeg -version
ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 4.8.5 (GCC) 20150623 (Red Hat 4.8.5-28)
configuration: --enable-gpl --enable-nonfree --enable-libfreetype --enable-libx264
libavutil 56. 22.100 / 56. 22.100
libavcodec 58. 35.100 / 58. 35.100
libavformat 58. 20.100 / 58. 20.100
libavdevice 58. 5.100 / 58. 5.100
libavfilter 7. 40.101 / 7. 40.101
libswscale 5. 3.100 / 5. 3.100
libswresample 3. 3.100 / 3. 3.100
libpostproc 55. 3.100 / 55. 3.100
ps:實際安裝時忘記安裝x264,安裝後記得要把x264的lib刷到緩存裏,否則會找不到
1、首先打開/etc/ld.so.conf文件
2、加入動態庫文件所在的目錄:執行vi /etc/ld.so.conf,在"include ld.so.conf.d/*.conf"下方增加"/usr/local/lib"。
3、保存後,在命令行終端執行:/sbin/ldconfig -v;其作用是將文件/etc/ld.so.conf列出的路徑下的庫文件緩存到/etc/ld.so.cache以供使用,因此當安裝完一些庫文件,或者修改/etc/ld.so.conf增加了庫的新搜索路徑,需要運行一下ldconfig,使所有的庫文件都被緩存到文件/etc/ld.so.cache中,如果沒做,可能會找不到剛安裝的庫。
經過以上三個步驟,"error while loading shared libraries"的問題通常情況下就可以解決了。
步驟2: 測試,安裝成功後,執行轉換命令:
令:
ffmpeg -i video2.mp4 -c:v libx264 -hls_time 60 -hls_list_size 0 -c:a aac -strict -2 -f hls t/video2.m3u8
步驟3.以下就是正在轉換
...略...
com.skyjilygao.util.VideoThread : frame= 3 fps=0.0 q=0.0 size=N/A time=00:00:01.08 bitrate=N/A speed=2.09x
com.skyjilygao.util.VideoThread : frame= 20 fps= 19 q=0.0 size=N/A time=00:00:01.36 bitrate=N/A speed=1.32x
com.skyjilygao.util.VideoThread : frame= 29 fps= 17 q=0.0 size=N/A time=00:00:01.49 bitrate=N/A speed=0.85x
com.skyjilygao.util.VideoThread : frame= 38 fps= 15 q=0.0 size=N/A time=00:00:01.64 bitrate=N/A speed=0.667x
com.skyjilygao.util.VideoThread : frame= 40 fps= 13 q=0.0 size=N/A time=00:00:01.70 bitrate=N/A speed=0.54x
com.skyjilygao.util.VideoThread : frame= 48 fps= 13 q=0.0 size=N/A time=00:00:01.83 bitrate=N/A speed=0.485x
...略...
步驟4 內嵌到代碼裏(java)
/**
* 拼接ffmpeg命令:ffmpeg -i test.mp4 -c:v libx264 -hls_time 60 -hls_list_size 0 -c:a aac -strict -2 -f hls output.m3u8
* @param source
* @return
*/
private boolean processM3U8(String source, String target) {
File targetFile = new File(target);
File parentDir = targetFile.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}
List<String> commend = new ArrayList<String>();
commend.add(ffmpeg);
commend.add("-i");
commend.add(source);
commend.add("-c:v");
commend.add("libx264");
commend.add("-hls_time");
commend.add("60");
commend.add("-hls_list_size");
commend.add("0");
commend.add("-c:a");
commend.add("aac");
commend.add("-strict");
commend.add("-2");
commend.add("-f");
commend.add("hls");
commend.add(target);
this.cmdList = commend;
// 通過ProcessBuilder創建
// processBuilder(commend);
// 通過runtime創建
runtimeBuilder(getCommand());
return true;
}
注意:命令通過list傳入,所以遇到空格,下一個參數就是一個list的元素。不能寫成 commend.add("-hls_time 60");這樣執行會變成ffmpeg -i test.mp4 -c:v libx264 "-hls_time 60" -hls_list_size 0 -c:a aac -strict -2 -f hls output.m3u8導致執行失敗
這裏是關鍵代碼。
命令簡單解釋下:
-hls_time 60: 設置每片的長度,我這裏是60秒,爲一個片段。
-hls_list_size 0:設置播放列表保存的最多條目,我這裏設置爲0會保存有所片信息,默認值爲5
更多命令可以百度或Google
步驟4.在內嵌到代碼裏(java)
/**
* 拼接ffmpeg命令:ffmpeg -i test.mp4 -c:v libx264 -hls_time 60 -hls_list_size 0 -c:a aac -strict -2 -f hls output.m3u8
* @param source
* @return
*/
private boolean processM3U8(String source, String target) {
File targetFile = new File(target);
File parentDir = targetFile.getParentFile();
if (!parentDir.exists()) {
parentDir.mkdirs();
}
List<String> commend = new ArrayList<String>();
commend.add(ffmpeg);
commend.add("-i");
commend.add(source);
commend.add("-c:v");
commend.add("libx264");
commend.add("-hls_time");
commend.add("60");
commend.add("-hls_list_size");
commend.add("0");
commend.add("-c:a");
commend.add("aac");
commend.add("-strict");
commend.add("-2");
commend.add("-f");
commend.add("hls");
commend.add(target);
this.cmdList = commend;
// 通過ProcessBuilder創建
// processBuilder(commend);
// 通過runtime創建
runtimeBuilder(getCommand());
return true;
}