使用PHP結合Ffmpeg快速搭建流媒體服務實踐
一、背景
筆者想將自己收藏的一些電影放到網站上可以用來隨時播放,不過遇到了一個問題,便是如果直接將MP4檔案放放到網站目錄當中,手機端必須下載整個視訊才可以播放,而如果跨外網傳輸,這實在是不太現實。
為了解決這個問題,便想著搭建一套流媒體服務,這樣手機就可以邊看邊下載,查詢了一些資料了了解到需要先將視訊分成一小片來傳輸,比如將MP4轉碼為M3U8格式,查詢了相關轉碼方法,比較主流的方式是使用ffmpeg這個開源工具
二、操作概要
1. 安裝Ffmpeg
2. 服務搭建
3. 功能測試
三、搭建ffmpeg
視訊轉碼的工具可能有很多,但開源且使用人數最多的還是莫過於ffmpeg這個工具,具體功能筆者不在這裡詳細講解;安裝此工具的方式有很多,比如apt安裝、原始碼安裝、docker安裝等等,不過docker是跨平臺的,因此筆者這裡將以docker方式安裝為例
3.1 映象下載
首先筆者需要下載對應的docker映象,參考命令如下
docker pull jrottenberg/ffmpeg
命令執行過程中將會從遠處下載映象,這個時間由當前的網路頻寬所決定,當下載完成之後,可以看到如下參考資訊
Using default tag: latest
latest: Pulling from jrottenberg/ffmpeg
b234f539f7a1: Pull complete
55172d420b43: Pull complete
5ba5bbeb6b91: Pull complete
43ae2841ad7a: Pull complete
f6c9c6de4190: Pull complete
2a0ef76bfa54: Pull complete
40ddf796a4bb: Pull complete
32ba137d2764: Pull complete
Digest: sha256:bcf65375f593518de7e450fd6b775d16a047d3ded00957c2e794e2fe8f7e1590
Status: Downloaded newer image for jrottenberg/ffmpeg:latest
3.2 容器執行
當容器下載完畢之後,可以用一些命令進行驗證是否能夠正常執行,如下參考命令
docker run jrottenberg/ffmpeg
命令執行完畢之後,會返回如下結果
Hyper fast Audio and Video encoder
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
Getting help:
..... 省略
Audio options:
-aframes number set the number of audio frames to output
-aq quality set audio quality (codec-specific)
-ar rate set audio sampling rate (in Hz)
-ac channels set number of audio channels
-an disable audio
-acodec codec force audio codec (`copy` to copy stream)
-vol volume change audio volume (256=normal)
-af filter_graph set audio filters
Subtitle options:
-s size set frame size (WxH or abbreviation)
-sn disable subtitle
-scodec codec force subtitle codec (`copy` to copy stream)
-stag fourcc/tag force subtitle tag/fourcc
-fix_sub_duration fix subtitles duration
-canvas_size size set canvas size (WxH or abbreviation)
-spre preset set the subtitle options to the indicated preset
3.3 檢視支援協議
FFmpeg所支援的輸入輸出協議非常多,比如可以選擇file協議作為來源,使用hls協議作為輸出結果,具體所支援的協議可以通過如下命令檢視
docker run jrottenberg/ffmpeg -protocols
執行命令之後,參考結果如下
ffmpeg version 3.4.2 Copyright (c) 2000-2018 the FFmpeg developers
built with gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.9) 20160609
configuration: --disable-debug --disable-doc --disable-ffplay --enable-shared --enable-avresample --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-gpl --enable-libass --enable-libfreetype --enable-libvidstab --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libtheora --enable-libvorbis
..... 省略
Supported file protocols:
Input:
async
cache
concat
crypto
data
..... 省略
Output:
crypto
file
..... 省略
tls
udp
3.4 轉換測試
現在筆者使用FFmpeg對視訊進行轉碼測試,命令非常簡單,首先需要通過-v
將視訊所在的目錄掛載到容器中,然後使用-i
選項找到容器中對應的視訊檔案;
接著就可以對編碼進行一些選項,比如-hls_time 10
便是將檔案沒10秒輸出一個TS檔案,-hls_list_size 0
則是在m3u8檔案中記錄所以ts
檔案(預設是記錄最後五個TS檔案),引數最後則填寫檔案輸出路徑,具體參考命令如下:
docker run -v /Users/song/video:/root/download jrottenberg/ffmpeg:latest -i /root/download/1.mp4 -hls_time 10 -hls_list_size 0 -f hls /root/download/index.m3u8
命令執行過程中會展示轉換進度,參考如下返回所示
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: mp42mp41
encoder : Lavf57.83.100
Stream #0:0(eng): Video: h264 (libx264), yuv420p(progressive), 1920x1080, q=-1--1, 30 fps, 90k tbn, 30 tbc (default)
Metadata:
creation_time : 2018-08-21T15:09:24.000000Z
handler_name : Alias Data Handler
encoder : Lavc57.107.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
Stream #0:1(eng): Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s (default)
Metadata:
creation_time : 2018-08-21T15:09:24.000000Z
handler_name : Alias Data Handler
encoder : Lavc57.107.100 aac
frame= 82 fps= 12 q=29.0 size=N/A time=00:00:02.62 bitrate=N/A speed=0.381x
此時便可以在剛才的掛載點檢視TS檔案,如下圖所示
現在筆者將剛才的TS檔案都刪除,在下面將使用自動化完成。
四、服務搭建
在上一步中筆者已經成功通過終端使用FFmpeg將視訊進行轉碼,下面筆者將結合PHP程式碼將這些操作完全自動化實現,這樣便可以達到通過手機訪問網站,服務端自動完成轉碼播放的需求,這個過程包括建立虛擬主機、編寫展示視訊列表、視訊自動解碼三個部分
4.1 建立虛擬主機
首先筆者需要藉助nginx搭建一個web服務,這時便需要修改配置檔案,但並不記得nginx配置檔案存放位置,此時可以藉助如下命令
sudo nginx -t
得到結果如下,在結果中可以便可以看到nginx的配置檔案存放位置
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
使用vim編輯器直接編輯nginx配置檔案
vim /usr/local/etc/nginx/nginx.conf
然後在配置檔案中加入如下參考配置資訊
server {
listen 8089;
server_name localhost;
root /Users/song/mycode/work/test/video;
location / {
index index.html index.htm index.php;
}
location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
4.2 獲取視訊列表
nginx配置完成之後,便需要編寫PHP程式碼,通過PHP可以獲取到目錄的視訊列表,然後將其輸出到網頁當中,參考程式碼如下所示
<?php
$list = scandir(`/Users/song/video/`);
foreach ($list as $key => $val) {
if (!in_array(pathinfo($val, PATHINFO_EXTENSION), [`mp4`, `rmvb`, `wmv`])) {
continue;
}
?>
<a class="btn btn-default btn-video btn-lg" href="./encode.php?name=<?= $val ?>" role="button">
<h2><?= $val ?></h2></a>
<?php }
} ?>
在程式碼中,首先通過scandir
讀取資料夾下所有檔案,然後進行foreach迴圈,通過字尾名來判斷是否為視訊檔案,如果是視訊檔案,則輸出一個連結地址方便使用者選擇。
4.3 進行視訊轉碼
上面的程式碼在列出視訊列表之後,當使用者點選連結後就需要使用FFmpeg進行轉碼,參考程式碼如下
<?php
//接收必要引數
$name = $_GET[`name`] ?? `1.mp4`;
$forced = $_GET[`forced`] ?? 0;
$fileName = getFileName($name);
$outPath = `/Users/song/video`;
$inPath = `/root/download`;
$dir = __DIR__;
//判斷之前是否已經轉碼,如果不強制轉碼便先返回
if (is_dir("$outPath/$fileName") && empty($forced)) {
header("location:./static/{$fileName}/index.m3u8");
die;
}
//將目標對映過來
system("ln -s {$outPath} {$dir}/static");
//先建立資料夾
system("mkdir -p {$outPath}/{$fileName}");
//進行轉碼
$ffmpeg = "docker run -v $outPath:/root/download jrottenberg/ffmpeg:latest";
$cmd = "nohup $ffmpeg -i {$inPath}/{$name} -hls_time 10 -hls_list_size 0 -f hls -r 25 {$inPath}/{$fileName}/index.m3u8 >> ./code.log &";
system($cmd);
//延時執行跳轉
returnUrl($fileName);
function getFileName($filename)
{
$houzhui = substr(strrchr($filename, `.`), 1);
$result = basename($filename, "." . $houzhui);
return $result;
}
function returnUrl($fileName)
{
echo "<a class=`btn btn-video btn-lg` href=`./static/{$fileName}/index.m3u8`><h1>正在處理中...點選進行跳轉</h1></a>";
die;
}
在上面程式碼當中,考慮檔案是否已經被轉碼,如果已經轉碼過了直接返回播放地址,否則建立一個存放TS檔案的資料夾,然後進行轉碼,轉碼的時候使用nohup命令可以讓FFmpeg非同步執行,然後PHP返回播放地址。
五、檢驗與測試
通過前面的步驟,筆者已經完整的搭建了一套流媒體伺服器,下面將檢驗這些服務是否能否正常執行,包括視訊列表展示、視訊轉碼是否正常、已經轉碼的視訊能否播放
5.1 視訊列表
首先通過瀏覽器開啟URL地址如下
http://localhost:8089/
載入完成之後可以看到如下的視訊列表
讀者如果將上方的程式碼執行介面有稍有差異,因為筆者為了節省文章篇幅,並沒有將樣式程式碼放到文章當中,如需介面好看可以自行編寫樣式程式碼。
5.2 視訊轉碼
在視訊列表點選一個連結之後,後臺PHP程式將會執行轉碼任務,然後返回一個連結地址,如下圖所示
此時便代表FFmpeg已經在後臺執行,可以通過如下命令進行檢視FFmpeg這個容器的執行狀態,參考命令如下
docker ps
返回的參考結果如下所示
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ac3e7233eb9f jrottenberg/ffmpeg:latest "ffmpeg -i /root/dow…" 1 hours ago Up 1 hours keen_feynman
從上面的返回結果當中可以看出當前正有一個任務處於執行狀態,此時開啟視訊輸出目錄,會看到有多個ts格式的視訊檔案,這些檔案是剛在通過PHP自動執行所產生的,如下圖所示
當看到如上圖的轉碼視訊檔案時,便可以通過瀏覽器進行訪問
5.3 視訊播放
這裡需要記住,HLS協議是蘋果公司所開發的,因此除了蘋果的瀏覽器外,其他瀏覽器預設都是不支援m3u8的解析的,如果需要使用其他瀏覽器播放,需要安裝外掛;蘋果的預設就支援則不需要
筆者重新通過Safari瀏覽器開啟頁面,然後再次選擇1.mp4
視訊,則直接跳轉到了播放頁面,如下圖所示
看到這裡,搭建流媒體就基本已經完成了,如果需要將更多視訊播放,只需要將視訊檔案存放到指定的視訊目錄,網頁中便會自動讀取出來,頁面可能太簡化,讀者可以根據自己的需要將html頁面美化一下。
六、新書推薦
如果對筆者的實戰文章較為感興趣,可以關注筆者新書《PHP Web安全開發實戰》,現已在各大平臺上架銷售,封面如下圖所示
作者:湯青松
微信:songboy8888
日期:2018-10-28
相關文章
- docker 中使用原始碼方式搭建 SRS 流媒體服務Docker原始碼
- nginx+ffmpeg搭建流媒體伺服器(直播流)Nginx伺服器
- Ubuntu 中使用 Nginx+rtmp 搭建流媒體直播服務.mdUbuntuNginx
- Ubuntu 中使用 Nginx+rtmp 模組搭建流媒體視訊點播服務UbuntuNginx
- 【史上最全】Nginx+ffmpeg實現流媒體系統Nginx
- windows編譯ZLMediaKit流媒體服務webrtcWindows編譯Web
- 使用ffmpeg推送視訊流至流媒體伺服器(c語言)伺服器C語言
- Docker 搭建多容器組合服務 (nginx + PHP)DockerNginxPHP
- 資料服務在新媒體業務體系中的實踐
- Windows Server 2022 上搭建流媒體直播和點播服務WindowsServer
- 亞馬遜將推流媒體音樂服務 僅限Echo使用者使用亞馬遜
- YouGov:流媒體服務正在購買完結熱門節目的版權Go
- YouGov:2020年流媒體服務報告Go
- YouGov:56%的美國人訂閱了流媒體服務Go
- CNN:使用者資料引蘋果谷歌押注流媒體音樂服務CNN蘋果谷歌
- Semgrep結合GitLab實現程式碼審計實踐-服務端Gitlab服務端
- 使用Nginx搭建rtmp流媒體伺服器筆記Nginx伺服器筆記
- Disney 流媒體廣告 Flink 的應用實踐
- json-server 快速搭建介面服務 使用教程JSONServer
- 文化媒體系統如何快速搭建
- 快速搭建本地HTTP/2服務HTTP
- live-server 快速搭建服務Server
- 在nginx上搭建php服務NginxPHP
- 安永:43%的家庭願意接受廣告支援的流媒體服務
- SequoiaDB巨杉資料庫入門:快速搭建流媒體伺服器資料庫伺服器
- 一步一步搭建基於ffmpeg和sdl2的流媒體播放器播放器
- 1.RTMP流媒體伺服器搭建伺服器
- vlc簡單搭建流媒體伺服器伺服器
- nginx上搭建HLS流媒體伺服器Nginx伺服器
- 神器:新手快速搭建MySQL服務MySql
- 服務計算 TDD實踐——實現快速排序演算法排序演算法
- Java版流媒體編解碼和影像處理(JavaCPP+FFmpeg)Java
- Go單體服務開發最佳實踐Go
- Go 單體服務開發最佳實踐Go
- 使用 Nuxt.js 快速搭建服務端渲染(SSR) 應用UXJS服務端
- 使用Docker Swarm快速搭建與部署你的服務叢集DockerSwarm
- 使用json-Server快速模擬服務環境搭建JSONServer
- Laravel Exception結合自定義Log服務的使用LaravelException