記錄一下爬取m4s流媒體格式的音視頻,老婆讓弄的沒辦法!
先介紹一下m4s是什么:
M4S文件是一種基于MPEG-4標準的分段視頻格式,專為在線流媒體傳輸設計。其核心特性是將視頻內(nèi)容分割為多個小片段,便于在網(wǎng)絡不穩(wěn)定時動態(tài)加載,提升播放流暢性。主要應用于在線視頻平臺和直播流媒體場景。
前提準備
-
工具安裝:安裝 FFmpeg(核心合并工具)
- Windows:下載 FFmpeg 官方包,解壓后將
ffmpeg.exe路徑加入系統(tǒng)環(huán)境變量; - macOS:
brew install ffmpeg; - Linux:
sudo apt install ffmpeg(Debian/Ubuntu)或sudo yum install ffmpeg(CentOS)。
- Windows:下載 FFmpeg 官方包,解壓后將
核心步驟(分 2 種場景)
場景 1:單視頻 + 單音頻 M4S 文件(無分片)
M4S 文件本質(zhì)是帶少量頭部的 fMP4 格式,直接剝離頭部后用 FFmpeg 合并即可:
步驟 1:提取純音視頻數(shù)據(jù)(可選但推薦)
部分 M4S 文件頭部有非媒體數(shù)據(jù),需先剝離(若直接合并失敗再執(zhí)行此步):
bash
運行
# Windows(PowerShell)
# 剝離視頻頭部(前12字節(jié),不同網(wǎng)站可能不同,如B站是12字節(jié))
Get-Content -Path video.m4s -Encoding Byte | Select-Object -Skip 12 | Set-Content -Path video_raw.mp4 -Encoding Byte
# 剝離音頻頭部
Get-Content -Path audio.m4s -Encoding Byte | Select-Object -Skip 12 | Set-Content -Path audio_raw.mp4 -Encoding Byte
# macOS/Linux
# 剝離視頻頭部
tail -c +13 video.m4s > video_raw.mp4 # 13 = 12+1(跳過前12字節(jié))
# 剝離音頻頭部
tail -c +13 audio.m4s > audio_raw.mp4
步驟 2:合并音視頻為完整視頻
用 FFmpeg 將音視頻流封裝為 MP4(或 MKV/FLV 等):
bash
運行
# 直接合并(未剝離頭部時)
ffmpeg -i video.m4s -i audio.m4s -c:v copy -c:a copy output.mp4
# 若剝離了頭部,用剝離后的文件
ffmpeg -i video_raw.mp4 -i audio_raw.mp4 -c:v copy -c:a copy output.mp4
參數(shù)說明:
-i:指定輸入文件;
-c:v copy:視頻流直接復制(不重新編碼,速度快);
-c:a copy:音頻流直接復制;
output.mp4:輸出文件名。
場景 2:多分片 M4S 文件(從 MPD 解析出多個分片)
若 MPD 里是分片的 M4S(如 video_1.m4s、video_2.m4s...),需先合并分片,再合并音視頻;我爬取的視頻就是這個場景的,過程比較麻煩,講清楚就好了!
步驟 1:合并視頻分片(含初始化文件)
MPD 中視頻的「初始化文件 + 分片」是連續(xù)的媒體流,需按「初始化文件 → 分片 1→分片 2→...→分片 10(我是10個切片具體按實際情況)」的順序合并:
Windows(PowerShell):
powershell
# 合并 720P 視頻(初始化文件 + 10 個分片,按順序拼接)
Get-Content -Path .\5\video_720p-0.m4s -Encoding Byte | Set-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-1.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-2.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-3.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-4.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-5.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-6.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-7.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-8.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-9.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
Get-Content -Path .\5\video_720p-10.m4s -Encoding Byte | Add-Content -Path video_720p_all.m4s -Encoding Byte
macOS/Linux(終端):
bash
運行
# 合并 720P 視頻(順序:初始化文件 + 分片 1-10)
cat 5/video_720p-0.m4s 5/video_720p-1.m4s 5/video_720p-2.m4s 5/video_720p-3.m4s 5/video_720p-4.m4s 5/video_720p-5.m4s 5/video_720p-6.m4s 5/video_720p-7.m4s 5/video_720p-8.m4s 5/video_720p-9.m4s 5/video_720p-10.m4s > video_720p_all.m4s
執(zhí)行后,會生成合并后的視頻文件 video_720p_all.m4s。
步驟 2:合并音頻分片(含初始化文件)
同理,按「初始化文件 → 分片 1-10(我是10個切片具體按實際情況)」順序合并音頻:
Windows(PowerShell):
powershell
# 合并 128kbps 音頻
Get-Content -Path .\8\audio_128kb-0.m4s -Encoding Byte | Set-Content -Path audio_128kb_all.m4s -Encoding Byte
Get-Content -Path .\8\audio_128kb-1.m4s -Encoding Byte | Add-Content -Path audio_128kb_all.m4s -Encoding Byte
# 重復添加 audio_128kb-2~10.m4s,命令和上面一致,僅替換數(shù)字
Get-Content -Path .\8\audio_128kb-10.m4s -Encoding Byte | Add-Content -Path audio_128kb_all.m4s -Encoding Byte
macOS/Linux(終端):
bash
運行
# 合并 128kbps 音頻
cat 8/audio_128kb-0.m4s 8/audio_128kb-1.m4s 8/audio_128kb-2.m4s 8/audio_128kb-3.m4s 8/audio_128kb-4.m4s 8/audio_128kb-5.m4s 8/audio_128kb-6.m4s 8/audio_128kb-7.m4s 8/audio_128kb-8.m4s 8/audio_128kb-9.m4s 8/audio_128kb-10.m4s > audio_128kb_all.m4s
執(zhí)行后,會生成合并后的音頻文件 audio_128kb_all.m4s。
步驟 3:剝離 M4S 頭部(關鍵步驟!)
從 MPD 可知,這些 M4S 是標準 DASH 分片,頭部有 12 字節(jié)的非媒體數(shù)據(jù)(大部分主流網(wǎng)站通用),需剝離后才能正常合并:
Windows(PowerShell):
powershell
# 剝離視頻頭部(跳過前 12 字節(jié))
Get-Content -Path video_720p_all.m4s -Encoding Byte | Select-Object -Skip 12 | Set-Content -Path video_raw.mp4 -Encoding Byte
# 剝離音頻頭部
Get-Content -Path audio_128kb_all.m4s -Encoding Byte | Select-Object -Skip 12 | Set-Content -Path audio_raw.mp4 -Encoding Byte
macOS/Linux(終端):
bash
運行
# 剝離視頻頭部(tail -c +13 表示從第 13 字節(jié)開始讀取,即跳過前 12 字節(jié))
tail -c +13 video_720p_all.m4s > video_raw.mp4
# 剝離音頻頭部
tail -c +13 audio_128kb_all.m4s > audio_raw.mp4
執(zhí)行后生成 video_raw.mp4(純視頻流)和 audio_raw.mp4(純音頻流)。
我剝離頭部數(shù)據(jù),發(fā)現(xiàn)無法合成音視頻,大家都說要剝離,那為什么剝離呢,有沒有可能不剝離呢,剝離的原因是頭部有非媒體數(shù)據(jù),那如何確認是否有非媒體數(shù)據(jù)呢,方法當然是有的啦!
要判斷 M4S 文件頭部是否有額外自定義字節(jié),核心思路是對比「M4S 實際字節(jié)結(jié)構」和「標準 fMP4 頭部特征」 —— 標準 fMP4 開頭是固定的「box 標識」(如 ftyp/moof),若 M4S 開頭不是這些標識,說明存在額外自定義前綴(需剝離)。以下是 3 種實操方法,從簡單到專業(yè),覆蓋不同場景:
方法 1:用 FFmpeg 快速檢測(最易上手,推薦)
FFmpeg 能直接解析音視頻文件的字節(jié)結(jié)構,只需執(zhí)行一行命令,即可判斷是否有非標準頭部:
bash
運行
# 檢測單個 M4S 文件(比如初始化文件 video_720p-0.m4s)
ffmpeg -i 5/video_720p-0.m4s
結(jié)果解讀:
? 正常(無額外頭部):FFmpeg 能識別流信息,輸出類似以下內(nèi)容(包含編碼、分辨率等):
plaintext
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '5/video_720p-0.m4s':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isomavc1
Duration: 00:00:00.00, start: 0.000000, bitrate: N/A
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709), 1280x720 [SAR 1:1 DAR 16:9], 0 kb/s, 25 fps, 25 tbr, 12800 tbn (default)
? 異常(有額外頭部):FFmpeg 提示「無效數(shù)據(jù)」,無法識別流,輸出類似:
plaintext
[mov,mp4,m4a,3gp,3g2,mj2 @ 000001c99f99a780] moov atom not found
5/video_720p-0.m4s: Invalid data found when processing input
?? 補充:若拼接后的完整 M4S(如 video_full.m4s)檢測失敗,更能說明存在額外頭部(單個分片可能因數(shù)據(jù)短檢測不準,拼接后更準確)。
方法 2:查看文件十六進制開頭(精準判斷,適合進階)
標準 fMP4(M4S 本質(zhì)是 fMP4 分片)的開頭字節(jié)是固定的「box 標識」(ASCII 字符),只需查看 M4S 文件的前 16 字節(jié)十六進制,即可判斷是否有自定義前綴:
步驟 1:導出 M4S 文件前 16 字節(jié)的十六進制
Windows(PowerShell):
powershell
# 導出 video_720p-0.m4s 前 16 字節(jié)到 hex.txt
Get-Content -Path 5/video_720p-0.m4s -Encoding Byte -TotalCount 16 | ForEach-Object { $_.ToString("X2") } | Out-File -FilePath hex.txt -Encoding ASCII
# 查看結(jié)果
Get-Content hex.txt
macOS/Linux(終端):
bash
運行
# 直接查看 video_720p-0.m4s 前 16 字節(jié)十六進制
xxd -l 16 5/video_720p-0.m4s
步驟 2:對比標準 fMP4 開頭(判斷是否有自定義前綴)
情況 十六進制開頭特征 是否需要剝離?
標準 fMP4(無前綴) 開頭是 66 74 79 70(對應 ASCII ftyp),或 6D 6F 6F 66(moof) ? 不需要
有自定義前綴 開頭是隨機字節(jié)(如 00 00 00 0C、23 20 00 00 等),且前 12/16 字節(jié)后才出現(xiàn) ftyp/moof ? 需要剝離
示例:
正常 M4S 開頭(無前綴):66 74 79 70 69 73 6F 6D ...(前 4 字節(jié)是 ftyp);
異常 M4S 開頭(有 12 字節(jié)前綴):00 00 00 0C 23 20 00 00 00 00 00 00 66 74 79 70 ...(前 12 字節(jié)是自定義數(shù)據(jù),第 13 字節(jié)開始是標準 ftyp)。
方法 3:逐字節(jié)剝離測試(暴力驗證,適合排查)
若前兩種方法無法確定,可通過「逐字節(jié)剝離測試」找到自定義前綴的長度,步驟如下:
1.先拼接完整的 M4S 文件(初始化 + 所有分片):
powershell
# 拼接 720P 視頻為 video_full.m4s(完整保留所有字節(jié))
Get-Content -Path 5/video_720p-0.m4s -Encoding Byte | Set-Content -Path video_full.m4s -Encoding Byte
Get-Content -Path 5/video_720p-1.m4s -Encoding Byte | Add-Content -Path video_full.m4s -Encoding Byte
# ... 追加 2~10.m4s ...
- 依次嘗試剝離 8/12/16/20 字節(jié),用 FFmpeg 檢測是否正常:
powershell
# 嘗試剝離 8 字節(jié)
Get-Content -Path video_full.m4s -Encoding Byte | Select-Object -Skip 8 | Set-Content -Path test_8.mp4 -Encoding Byte
ffmpeg -i test_8.mp4 # 檢測是否識別流
# 嘗試剝離 12 字節(jié)
Get-Content -Path video_full.m4s -Encoding Byte | Select-Object -Skip 12 | Set-Content -Path test_12.mp4 -Encoding Byte
ffmpeg -i test_12.mp4
# 嘗試剝離 16 字節(jié)
Get-Content -Path video_full.m4s -Encoding Byte | Select-Object -Skip 16 | Set-Content -Path test_16.mp4 -Encoding Byte
ffmpeg -i test_16.mp4
3.結(jié)果:能讓 FFmpeg 正常識別流的「剝離字節(jié)數(shù)」,就是自定義前綴的長度(比如剝離 12 字節(jié)后正常,說明前綴是 12 字節(jié))。
結(jié)論就是:只要 FFmpeg 無法直接識別 M4S 文件(拼接后),就說明有自定義頭部;通過十六進制或逐字節(jié)測試,可確定需要剝離的具體長度。
剝離處理完了最后一步就是合并
重新合并音視頻
bash
運行
ffmpeg -i video_raw.mp4 -i audio_raw.mp4 -c:v copy -c:a copy final_720p.mp4