爬取m4s格式音視頻

記錄一下爬取m4s流媒體格式的音視頻,老婆讓弄的沒辦法!
先介紹一下m4s是什么:
M4S文件是一種基于MPEG-4標準的分段視頻格式,專為在線流媒體傳輸設計。其核心特性是將視頻內(nèi)容分割為多個小片段,便于在網(wǎng)絡不穩(wěn)定時動態(tài)加載,提升播放流暢性。主要應用于在線視頻平臺和直播流媒體場景。

前提準備

  1. 工具安裝:安裝 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)。

核心步驟(分 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 ...
  1. 依次嘗試剝離 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
就是這樣啦結(jié)束!
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容