歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~javascript
不久前,團隊發現其Android平臺App在播放MV視頻《鳳凰花開的路口》時,會帶有如電流聲通常的雜音,這影響了用戶體驗。 研發同窗在初步定位時,發現有以下特徵:java
然而,各平臺都是統一用HLS格式播放,即源頭都是同樣的。對於該問題,咱們的定位思路以下:git
分析播放流程如上圖(圖中內容從左往右),歸納其關鍵步驟以下:github
read_thread
;audioq
;sampq
。avformat_open_input
;avformat_find_stream_info
;av_find_best_stream
;stream_component_open
;av_read_frame(ic, pkt)
;audioq
中;audio_thread
中對audioq
中的數據進行decoder_decode_frame
解碼;AVFrame
存放到sampq
中;aout_thread_n
中,經過調用回調接口sdl_audio_callback
,對sampq
中的音頻幀數據進行解碼成PCM數據;AudioTrack
播放。在梳理出播放流程後,標記出找到有可能出錯的環節,方便進行「分層定位」(圖中黃色標記)數組
AudioTrack
的設置是否有問題;接下來,根據難易程度,對上述環節逐個驗證。框架
把Android平臺播放的ts文件與各平臺的進行比對,發現二者同樣,該環節正常。機器學習
經過日誌檢查AudioTrack
如下配置參數:函數
以上參數設置的值與音頻流的相符合,該環節正常。工具
驗證解碼邏輯是否有問題,能夠經過對PCM數據進行分析來確認。 對aout_thread_n
進行修改,將PCM數據額外輸出到本地,並與正常的PCM數據進行對比。
正常PCM數據頻譜圖:
異常PCM數據頻譜圖:
正常PCM數據波形圖:
異常PCM數據波形圖:
對比分析可得出:
若解碼邏輯正常,再結合以前已經驗證文件下載正常。能夠推測是數據讀取環節出現異常。
經過對數據讀取的各步驟增長日誌後,發如今av_find_best_stream
音頻流選擇時出現異常: ffmpeg -i
發現,該視頻ts分片有2個音頻流
經過強制分別讀取兩條音頻流數據播放,發現:
基於此,也就驗證了在第3步中的假設是正確的。
由上分析,能夠得出結論:Android平臺選擇了第二條數據有問題的流進行播放。
分析代碼,大體以下所列,av_find_best_stream
函數選擇音頻流,該函數會根據2個主要參數進行選擇:
avformat_find_stream_info
)時,額外解碼出來的幀數(選擇多的)int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
int wanted_stream_nb, int related_stream,
AVCodec **decoder_ret, int flags)
{
for (i = 0; i < nb_streams; i++) {
count = st->codec_info_nb_frames; //音頻流探測中解碼的幀數
bitrate = avctx->bit_rate;//音頻流的比特率
multiframe = FFMIN(5, count);
//先比較解碼幀數,再比較音頻流比特率,誰大誰選
if ((best_multiframe > multiframe) ||
(best_multiframe == multiframe && best_bitrate > bitrate) ||
(best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count))
continue;
best_count = count;
best_bitrate = bitrate;
best_multiframe = multiframe;
ret = real_stream_index;//最後選擇的流index
best_decoder = decoder;
}
return ret;
}
複製代碼
在該視頻中,咱們能夠看到:
codec_info_nb_frames | bit_rate | |
---|---|---|
audio_stream 1 | 38 | 122625 |
audio_stream 2 | 39 | 126375 |
第二條流的解碼幀數和比特率要比第一條高,所以選擇了第二條流播放
分析了以上選擇規則後,咱們對各平臺、框架進行了選擇規則的對比:
備註:
ffmpeg -i INPUT_FILE -map 0:0 -map 0:2 -map 0:1 -c copy -y OUTPUT_FILE
ffmpeg -i INPUT_FILE_1 -i INPUT_FILE_2 -map 0:0 -map 0:1 -map 0:2 -map 1:0 -c copy OUTPUT_FILE
從以上數據看到,iOS和PC平臺會默認選擇第一條流,而在Android平臺的FFmpeg和ExoPlayer會根據音頻流屬性來選擇數值更好的一條。
但以上2個選擇方案都沒法識別「內容異常」的音頻流。
所以,處理該問題,須要從音源上進行修復和規避,咱們的建議是從源頭杜絕,從終端規避:
相關閱讀
此文已由做者受權騰訊雲+社區發佈,更多原文請點擊
搜索關注公衆號「雲加社區」,第一時間獲取技術乾貨,關注後回覆1024 送你一份技術課程大禮包!
海量技術實踐經驗,盡在雲加社區!