:從 FLV 尾部缺幀到 3.1.8 候選構(gòu)建驗(yàn)證)
音視頻直播移動開發(fā)【免費(fèi)下載鏈接】pure_live純粹直播:嗶哩嗶哩/虎牙/斗魚/快手/抖音/網(wǎng)易cc/YY直播/Twitch直播/SOOP直播/M38自定義源應(yīng)有盡有。項(xiàng)目地址https://gitcode.com/gh_mirrors/pur/pure_live點(diǎn)擊查看免費(fèi)下載導(dǎo)讀本文圍繞 pure_live純粹直播錄制鏈路中一個隱蔽但關(guān)鍵的媒體缺陷展開當(dāng)用戶在 FLV 直播錄制過程中手動停止時如果已經(jīng)轉(zhuǎn)發(fā)的 AVC 數(shù)據(jù)尾部仍欠一個畫面picture舊邏輯會立即關(guān)閉輸入導(dǎo)致最終 MP4 在嚴(yán)格解碼時因缺少畫面的訪問單元而失敗。本文完整梳理該問題的發(fā)現(xiàn)過程、根因定位、常量內(nèi)存修復(fù)設(shè)計、終止證據(jù)契約以及修復(fù)后 16 組 Android 原生場景對應(yīng)的累計候選構(gòu)建3.1.84121的完整驗(yàn)證與驗(yàn)收口徑并給出對應(yīng)的源碼級實(shí)現(xiàn)依據(jù)。讀完本文你可以掌握FLV 標(biāo)簽邊界與 H.264 Annex-B 訪問單元邊界的關(guān)系、pure_live 錄制停止預(yù)算與排空語義的實(shí)現(xiàn)、以及該項(xiàng)目候選發(fā)布前質(zhì)量門禁與構(gòu)建核驗(yàn)的完整流程。一、問題發(fā)現(xiàn)克拉克拉雙協(xié)議原生錄制審計修復(fù)的起點(diǎn)來自一次真實(shí)平臺的雙協(xié)議錄制審計詳見 克拉克拉雙協(xié)議原生錄制與尾部缺幀審計。通過注冊的 KilakilaSite 萌星目錄選擇公開免費(fèi) UID分別調(diào)用生產(chǎn)鏈路的StreamResolverService、請求頭工廠、命令生成器、FFmpegManager與 MP4 轉(zhuǎn)存服務(wù)進(jìn)行 HLS/FLV 雙協(xié)議短錄HLS4 段、源大小 1,035,692 B成品 MP4 852,088 B / 32.864 秒H.264 320×240 AAC嚴(yán)格完整解碼退出 0、stderr 為空FLV采集停止code0、inputDrainedtrue、forcedCancelfalse轉(zhuǎn)存也code0但成品 MP4659,962 B 嚴(yán)格解碼失敗——失敗 MP4 有 257 個視頻包最后一包在偏移 659,925、長度僅 37 B只含長度前綴 33 B 的 type-6 SEI沒有 VCL 畫面報錯missing picture in access unit with size 37。該案例同時暴露了一個保護(hù)盲點(diǎn)FLV 停止與轉(zhuǎn)存都返回 code0舊的完整性分類器沒有識別出這個精確的缺幀解析錯誤導(dǎo)致原始 TS 分片在轉(zhuǎn)存誤報成功后被刪除MP4 雖保留但已無法修復(fù)。這一發(fā)現(xiàn)直接否定了FLV 標(biāo)簽完整即錄制成功的假設(shè)。1.1 獨(dú)立解碼檢查自身的校正首次檢查只斷言退出碼HLS 雖退出 0默認(rèn) null 輸出時基仍有 DTS 提示。隨后檢查 MP4 全部視頻 PTS 嚴(yán)格遞增最小正間隔 3000/90000 秒并在改用-fps_mode passthrough -enc_time_base demux后對同一未改變文件全解碼HLS 退出 0 且 stderr 為空FLV 仍因缺幀失敗。該設(shè)置保留解碼輸出時基不過濾錯誤、刪幀或修改原文件且 stderr 必須為空被加入斷言。初版聯(lián)網(wǎng)運(yùn)行的原始探針另存為native-probe-first.dart避免用后改腳本冒充已運(yùn)行輸入。二、根因FLV 標(biāo)簽完整 ≠ AVC 訪問單元完整通過保存的原始完整 FLV 標(biāo)簽12.041 秒、316,784 BSHAFB26AE91222B6639B2C3DFB8FAA7B5FFD5F1E441530A0DAB67962BA1F9695596共 688 標(biāo)簽加文件頭其中 42 個視頻標(biāo)簽在畫面 NAL 后仍有 SEI做不依賴新直播時序的邊界復(fù)現(xiàn)用完整標(biāo)簽前綴 獨(dú)立 FFmpeg CLI 做 FLV→TS→MP4 與完整解碼截止點(diǎn)輸入字節(jié)采集/轉(zhuǎn)存退出嚴(yán)格完整解碼含尾 SEI 視頻標(biāo)簽之前80,0090 / 00錯誤為空該完整視頻標(biāo)簽之后80,3380 / 0缺幀失敗再包含下一視頻標(biāo)簽82,4880 / 00錯誤為空結(jié)論FLV 標(biāo)簽完整不保證后續(xù) Annex-B 訪問單元尾部完整。維護(hù)分支引入的 FLV 輸入橋解決了半個標(biāo)簽被截斷的問題但把完整 FLV 標(biāo)簽當(dāng)作足夠的停止條件已保存樣本含 picture 后的 SEI下游 H.264 Annex-B parser 把它視為下一訪問單元的開始停止在此處會留下沒有畫面的尾包。這類過弱邊界假設(shè)屬于fork-regression新平臺觸發(fā)舊假設(shè)凍結(jié)上游未發(fā)生 fetch/merge。三、修復(fù)設(shè)計常量內(nèi)存的 AVC 訪問單元邊界觀察器修復(fù)提交1abbff9abc78e698f8bb24e6a542bb2ecf35484d沒有走把失敗改成錯誤提示的捷徑而是完成已復(fù)現(xiàn)邊界的實(shí)際修復(fù)。核心實(shí)現(xiàn)位于 ffmpeg_flv_input_relay.dart 中的FlvAvcAccessUnitBoundary按 AVC 配置聲明的 1/2/4 字節(jié) NAL 長度掃描標(biāo)簽AVCDecoderConfigurationRecord的lengthSizeMinusOne長度 3 為 AVC 配置保留值直接視為無效只讀 NAL 頭不解碼、不積累整場直播、不猜其他 codec 格式遇到 type 1/2/5非 IDR / 分割 / IDR 畫面則清除待畫面狀態(tài)遇到 type 6~9SEI/SPS/PPS/AUD則置為待畫面畸形長度置為不確定狀態(tài)且不偽造完整邊界音頻、腳本標(biāo)簽與正常媒體內(nèi)容全部原樣轉(zhuǎn)發(fā)沒有重排 NAL、全局過濾 SEI、截掉畫面或轉(zhuǎn)碼用戶停止時若已轉(zhuǎn)發(fā)的前綴仍等待畫面則繼續(xù)讀到下一個不再留下待完成前綴的完整畫面邊界同一網(wǎng)絡(luò)塊中后續(xù)標(biāo)簽不再轉(zhuǎn)發(fā)。正常邊界和連接前停止仍立即關(guān)閉輸入。final type tag[offset] 31; if (type 1 || type 2 || type 5) { pending false; // 畫面到達(dá)訪問單元完整 } else if (type 6 type 9) { pending true; // SEI/SPS/PPS/AUD下一訪問單元前綴 }配套的FlvInputFramer只負(fù)責(zé) FLV 幀定界11 字節(jié)標(biāo)簽頭 DataSize 數(shù)據(jù) PreviousTagSize單標(biāo)簽最大 0xffffff 載荷無生命周期緩沖增長轉(zhuǎn)發(fā)時逐標(biāo)簽原樣提交給下游 native reader。四、停止語義與終止證據(jù)契約停止側(cè)仍使用原有3000 ms服務(wù)級停止預(yù)算inputDrainBudgetMs: drainKind flv ? 3000未增加定時等待或重試。終止證據(jù)在 ffmpeg_service.dart 的terminalEvidence()中集中生成inputDrained: finishRequested !forcedCancel flvInputRelay?.hasPendingAccessUnit ! true, if (flvInputRelay ! null) flvAccessUnitPending: flvInputRelay!.hasPendingAccessUnit, inputIntegrityError: liveRecording (hasInputPacketError || flvInputRelay?.hasPendingAccessUnit true || FFmpegMediaIntegrity.hasPacketError(fallbackLogs)),關(guān)鍵語義變化inputDrained不再把已知 AVC 未完成情況寫成排空成功新增flvAccessUnitPending終止證據(jù)字段并沿既有inputIntegrityError持久化/源保留路徑處理未新增任務(wù)數(shù)據(jù) schema先前缺幀錯誤保留源保護(hù)繼續(xù)有效看不到完整邊界、網(wǎng)絡(luò)停滯或上游提前 EOF 時保留不完整標(biāo)志和源分片而非悄悄刪掉待完成元數(shù)據(jù)正常時間戳修正、停止 I/O、原生線程退出提示仍按現(xiàn)有分類處理不 blanket 攔截警告新 session 不繼承前次損壞。本次修復(fù)不承諾缺失后續(xù)畫面的源流自動變成完整錄像——如果所有后續(xù)標(biāo)簽仍留下前綴或期限內(nèi)未取得完整邊界結(jié)果仍明確失敗/保留源不把這種情況計為健康錄制。五、回歸驗(yàn)證52 項(xiàng)定向回歸與四場景固定輸入修復(fù)后進(jìn)行 52 項(xiàng)定向回歸含長度、配置變化、未知/畸形輸入、正常畫面/填充尾部、連續(xù)輸入和終止證據(jù)合同兩個真實(shí) loopback 紅項(xiàng)在舊代碼上均失敗停止立即結(jié)束而非等待畫面隨后52/52 通過、五文件 analyze 104.1 秒無問題。增加只讀轉(zhuǎn)發(fā)字節(jié)計數(shù)核驗(yàn)實(shí)際輸入范圍后最終仍 52/52。原生探針使用保存的 316,784 B FLVSHA 未改變固定在 6 秒附近觸發(fā)停止使用真正的FFmpegManager、輸入橋、轉(zhuǎn)存服務(wù)與獨(dú)立全解碼不以假原生執(zhí)行器代替場景停止前輸入 / 最終轉(zhuǎn)發(fā)停止實(shí)測結(jié)果正常畫面邊界158140 / 158140 B23 msMP4 成功完整解碼 0、錯誤為空尾部有前綴隨后提供完整畫面158469 / 163709 B16 ms原字節(jié)保留MP4 成功完整解碼 0、錯誤為空上游停滯158469 / 158469 B3020 ms原 3 秒預(yù)算后強(qiáng)制停止TS 保留、無最終 MP4上游提前 EOF158469 / 158469 B11 ms不假報排空TS 保留、無最終 MP4兩種缺失輸入均inputDrainedfalse / inputIntegrityErrortrue正常兩例為 true / false重放服務(wù)按門閂批量供給后續(xù)字節(jié)16 ms 僅為這次固定輸入的實(shí)際耗時不是公網(wǎng)幀等待保證。四例均結(jié)束實(shí)際原生會話并釋放轉(zhuǎn)存狀態(tài)全部通過1 個原生集成測試總耗時 387.657 秒含排隊/編譯。六、真實(shí)生產(chǎn)雙協(xié)議復(fù)測通過當(dāng)前注冊適配器重新獲取萌星目錄、主播 UID 和簽名輸入HLS 選擇當(dāng)前樣本FLV 以同 UID 重新解析不復(fù)用舊簽名 URL也不與先前固定輸入混為同一廣播使用生產(chǎn)請求頭、命令、原生采集、分片轉(zhuǎn)存及完整解碼探針輸入時間 UTC成品時長源片數(shù) / 源大小MP4 字節(jié) / SHA-256HLS04:10:1432.872 s4 / 1,047,348 B864,615 B /EA59DD0A53E87F2600853548C2693FCB8E6DC0347B57DE13D9B17B0E5BD3DA78FLV04:12:1928.933333 s3 / 947,520 B746,070 B /0C8A9A87BE3929969C5A47B6418C4EEF929EF5BD0600419D386557AF0CD6B1C9兩者均為 H.264 320×240 AAC完整成品解碼退出 0 且 stderr 為空停止后原生會話與轉(zhuǎn)存操作釋放正常源片工作副本在提交后刪除。FLV 此次停止 246 ms、forcedCancelfalse、inputDrainedtrue、flvAccessUnitPendingfalse。真實(shí)短錄沒有覆蓋所有隨機(jī)停止點(diǎn)由上述固定邊界重放提供確定性對照HLS 1/1、FLV 1/1。七、累計 Android 候選構(gòu)建與完整核驗(yàn)修復(fù)與壞源保留保護(hù)26de4378見 克拉克拉原生尾部審計連同先前萌星目錄修復(fù)匯總到干凈提交966735384aa3224f217fa14eb4e72769a6edafac完成一次完整質(zhì)量門禁及 Android arm64 Debug 構(gòu)建詳見 AVC 停止修復(fù)累計 Android 候選。7.1 質(zhì)量門禁Flutter 3.47.0 / Dart 3.13 固定入口鎖文件未改變2098/2098 Flutter 測試、42/42 公共接口通過全量 analyze 一次、233.3 秒無問題質(zhì)量記錄20260908T042959828Z-quality-full.json572.715 秒峰值 CPU 44.01%、13,039,648,768 B結(jié)束活躍重型進(jìn)程 0倉庫檢查 4301 個跟蹤文件、0 錯誤、2 個既有提示已審閱公開 TLS 測試私鑰和空 catch 清單本輪原生依賴預(yù)取及 Windows FFmpeg hook 均報告 SHA 校驗(yàn)通過沒有升級 SDK、插件或原生庫。7.2 Android arm64 Debug 構(gòu)建產(chǎn)物構(gòu)建記錄20260908T043750521Z-build-androidarm64-debug.json1042.431 秒含前置質(zhì)量階段Gradle 413.2 秒workers16峰值 CPU 75.48%、14,141,349,888 B包名com.mystyle.pureliveversionName3.1.8基礎(chǔ) build4121arm64 偏移 2000Manifest versionCode6121唯一 ABI arm64-v8a16 個原生 ELF 的 LOAD 對齊至少 0x4000APK 對齊、1262 項(xiàng) Flutter 資源、版本/翻譯與關(guān)鍵原生庫完整性門禁通過實(shí)際中英文萌星名稱與能力說明逐值核對測試 TLS 私鑰未打包大小288,139,348 BSHA-25645D2D8C2386F4F86CAC83917472960D1725599FB5F03AA6852E039D331E0D84E簽名校驗(yàn)通過證書 SHA-2561e832295a696cf8210bca063e458bad0be12dfa64939d3362ff11b8f237ff7b9與先前 ae5232b2 歸檔 Debug 包一致歸檔位置local-artifacts/candidates/android-96673538/PureLive-3.1.8-4121-android-arm64-v8a-debug.apk復(fù)制后哈希復(fù)核舊包哈希仍正確未覆蓋通用local-artifacts/3.1.8-4121/中其他平臺文件屬于歷史獨(dú)立構(gòu)建目錄列表不是本輪全平臺構(gòu)建成功。7.3 質(zhì)量門禁的誠實(shí)性細(xì)節(jié)首次由調(diào)用者誤選 Windows PowerShell 5.1在解析無 BOM 中文腳本時失敗未進(jìn)入 Flutter analyze/測試或 Gradle保留失敗質(zhì)量記錄20260908T041939717Z-quality-full.json與原日志同一源碼在實(shí)際工作環(huán)境 PowerShell 7.6.5 解析、平臺合同檢查通過后重跑未通過編輯測試、刪中文或跳過門禁掩蓋錯誤。構(gòu)建記錄保留增量緩存與 daemonFROM-CACHE0 / UP-TO-DATE0、configuration cache 未復(fù)用Firebase 未來 KGP 兼容性警告保留沒有借機(jī)升級依賴。八、后續(xù)驗(yàn)收與交付邊界候選保留了既有 15 組累計 Android 原生場景新增本候選 AVC 正常/待畫面/停滯/EOF 及源保留驗(yàn)證共16 組待驗(yàn)Windows 已通過的原生固定輸入和真實(shí)雙協(xié)議短錄繼續(xù)作為定位證據(jù)不替代 Android 原生 FFmpeg 或界面驗(yàn)收。設(shè)備操作前仍按當(dāng)前窗口、共享 purelive 租約、顯式 serial、指定設(shè)備與當(dāng)前簽名核驗(yàn)執(zhí)行覆蓋安裝保留數(shù)據(jù)不重啟、不清數(shù)據(jù)、不修改網(wǎng)絡(luò)/Root/LSP??趶匠吻逦窗惭b、未操作手機(jī)、未發(fā)布候選通過不是原生/UI/長錄驗(yàn)收通過版本保持 3.1.84121Windows GUI 候選仍 f3de664a歷史矩陣仍為 62 項(xiàng)20 PASS、32 RUN、10 NR16 組候選專項(xiàng)不與 42 個未閉環(huán)大項(xiàng)簡單相加或當(dāng)作剩余 Bug 數(shù)12 組參考平臺尚未注冊全平臺/長錄/性能和正式 3.2.0 條件繼續(xù)未提前宣稱完成本機(jī)證據(jù)目錄local-artifacts/avc-stop-android-candidate-20260908/保留首次失敗、重跑日志、簽名結(jié)果、源凍結(jié)、16 組 native-handoff、校驗(yàn)索引及終態(tài) checkpoint。九、總結(jié)從克拉克拉雙協(xié)議短錄中的一次缺幀解碼失敗到FlvAvcAccessUnitBoundary的常量內(nèi)存邊界觀察、flvAccessUnitPending終止證據(jù)與源保留保護(hù)再到累計 Android 候選的完整構(gòu)建核驗(yàn)這條修復(fù)鏈貫穿了 pure_live 錄制模塊發(fā)現(xiàn)問題 → 固定輸入復(fù)現(xiàn) → 根因修復(fù) → 回歸 真實(shí)復(fù)測 → 候選門禁的完整閉環(huán)。其核心工程原則值得借鑒邊界判斷必須以媒體語義AVC 訪問單元為準(zhǔn)而非容器語法FLV 標(biāo)簽為準(zhǔn)任何完整聲明都必須有可審計的終止證據(jù)支撐修復(fù)不掩蓋失敗寧可保留源分片與不完整標(biāo)志也不把壞源誤報為健康錄制。相關(guān)實(shí)現(xiàn)可繼續(xù)深入閱讀FFmpeg FLV 輸入橋?qū)崿F(xiàn)、終止證據(jù)與完整性分類、錄制控制器源保留處理、任務(wù)模型完整性字段。贊分享音視頻直播移動開發(fā)【免費(fèi)下載鏈接】pure_live純粹直播:嗶哩嗶哩/虎牙/斗魚/快手/抖音/網(wǎng)易cc/YY直播/Twitch直播/SOOP直播/M38自定義源應(yīng)有盡有。項(xiàng)目地址https://gitcode.com/gh_mirrors/pur/pure_live點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Wand-Enhancer 完整指南從零構(gòu)建 WeMod 本地增強(qiáng)工具到手機(jī)面板跑通只需 1 次掃碼Wand Enhancer 完整指南從零構(gòu)建 WeMod 本地增強(qiáng)工具到手機(jī)面板跑通只需 1 次掃碼 打開設(shè)置頁看到升級到 Pro和月費(fèi)的那個瞬間多數(shù)桌面應(yīng)用前端ArchiveBox 自定義 Django Widgets 深度解析TagEditorWidget、InlineTagEditorWidget 與 URLFiltersWidgetArchiveBox 自定義 Django Widgets 深度解析TagEditorWidget、InlineTagEditorWidget 與 URLFi音視頻直播移動開發(fā)gopass 版本發(fā)布全流程指南從 goreleaser 配置、RC 候選到可復(fù)現(xiàn)構(gòu)建與產(chǎn)物驗(yàn)證gopass 版本發(fā)布全流程指南從 goreleaser 配置、RC 候選到可復(fù)現(xiàn)構(gòu)建與產(chǎn)物驗(yàn)證 gopass 使用 goreleaser https://l應(yīng)用安全開發(fā)工具上一篇FanControl終極教程Windows風(fēng)扇智能控制完整指南下一篇5分鐘快速上手My-TODOs跨平臺桌面待辦工具完全指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考