疑難排解


修正「不允許的明文 HTTP 流量」錯誤

如果應用程式在網路安全性設定不允許的情況下要求明文 HTTP 流量 (亦即 http://,而非 https://),就會發生這個錯誤。如果應用程式指定 Android 9 (API 級別 28) 以上版本,則根據預設設定會停用明文 HTTP 流量。

如果應用程式需要處理明文 HTTP 流量,您必須使用允許該連線的網路安全性設定。詳情請參閱 Android 的網路安全性說明文件。如要啟用所有明文 HTTP 流量,只要在應用程式 AndroidManifest.xmlapplication 元素中加入 android:usesCleartextTraffic="true" 即可。

ExoPlayer 試用版應用程式使用預設的「網路安全性設定」,因此不允許使用明文 HTTP 流量。您可以按照上述操作說明啟用。

修正「SSLHandshakeException」、「CertPathValidatorException」和「ERR_CERT_AUTHORITY_INVALID」錯誤

SSLHandshakeExceptionCertPathValidatorExceptionERR_CERT_AUTHORITY_INVALID 都表示伺服器的 SSL 憑證有問題。這些錯誤並不是 ExoPlayer 特有的。詳情請參閱 Android SSL 說明文件

為什麼無法搜尋某些媒體檔案?

根據預設,ExoPlayer 不支援在媒體中搜尋,因為唯一執行準確搜尋作業的方法是讓玩家掃描整個檔案,並為其建立索引。ExoPlayer 會將這類檔案視為無法瀏覽。大部分的現代媒體容器格式包括用於搜尋的中繼資料 (例如範例索引)、明確定義的搜尋演算法 (例如,在 Ogg 的內插雙節搜尋),或表示內容為固定位元率。在這種情況下,ExoPlayer 會採用並支援有效的搜尋作業。

如果您需要跳轉,卻找不到媒體,建議您轉換內容,以使用更適當的容器格式。針對 MP3、ADTS 和 AMR 檔案,您也可以假設檔案具有固定位元率,詳情請參閱這篇文章

為什麼某些 MP3 檔案含有不正確的字幕?

可變位元率 (VBR) MP3 檔案基本上不適合用於需要精確跳轉的用途。造成這種情況的原因有兩種:

  1. 就精確搜尋而言,容器格式在理想情況下應在標頭中提供精確的時間到位元組對應。此對應可讓玩家將要求的搜尋時間對應到對應的位元組偏移,然後開始要求、剖析和播放來自該位移的媒體。可惜的是,在 MP3 中指定這項對應的標頭 (例如 XING 標頭) 通常不夠精確。
  2. 至於沒有提供精確時間對位元組對應關係 (或任何時間到位元組對應) 的容器格式,如果容器中有絕對範例時間戳記,您還是可以執行精確搜尋。在這種情況下,玩家可以將搜尋時間對應至準確的對應位元組偏移、開始從該偏移要求媒體、剖析第一個絕對樣本時間戳記,以及有效地在媒體中執行引導式二進位檔搜尋,直到找到正確的樣本為止。遺憾的是,MP3 未在串流中加入絕對樣本時間戳記,因此這個方法不可能。

基於上述原因,如要精確搜尋 VBR MP3 檔案,唯一的方法是掃描整個檔案,然後在播放器中手動建構時間到位元組對應。您可以使用 FLAG_ENABLE_INDEX_SEEKING 啟用這項策略,使用 setMp3ExtractorFlagsDefaultExtractorsFactory 上設定該策略。請注意,此方法無法適當縮放至大型 MP3 檔案,特別是當使用者嘗試在開始播放後不久才嘗試前往串流即將結束時,這時玩家需要等到整個串流下載和索引之後,才能執行搜尋作業。在 ExoPlayer 中,我們決定針對速度進行最佳化,而不是提升準確率,因此 FLAG_ENABLE_INDEX_SEEKING 會預設為停用。

如果您要控制正在播放的媒體,強烈建議您使用更適當的容器格式,例如 MP4。我們知道 MP3 是最佳媒體格式的最佳選擇。

為什麼影片跳轉速度變慢?

播放器跳轉至影片中的新播放位置時,需要執行下列兩項操作:

  1. 將與新播放位置相對應的資料載入緩衝區 (如果這項資料已緩衝處理,可能就不需要進行)。
  2. 由於大多數影片壓縮格式都會用到影格內編碼,因此影片解碼器會在新的播放位置之前,開始從 I-Frame (主要畫面格) 解碼。為確保搜尋的「準確」 (也就是說,播放作業完全在跳轉位置開始),所有在前一個 I 影格和搜尋位置之間的影格都必須解碼並立即捨棄 (未顯示在畫面上)。

(1) 導入的延遲時間可透過增加玩家記憶體中緩衝的資料量,或是將資料預先快取至磁碟來降低。

(2) 導入的延遲時間可透過 ExoPlayer.setSeekParameters 降低搜尋準確度,或者重新編碼影片來增加 I-Frame 的頻率 (進而增加輸出檔案)。

為什麼部分 MPEG-TS 檔案無法播放?

部分 MPEG-TS 檔案未包含存取單位分隔符號 (AUD)。根據預設,ExoPlayer 仰賴澳幣來偵測影格邊界。同樣地,部分 MPEG-TS 檔案也不包含 IDR 主要畫面格。根據預設,ExoPlayer 只考慮這些主要畫面格類型。

系統要求播放缺少 AAUD 或 IDR 主要畫面格的 MPEG-TS 檔案時,ExoPlayer 似乎會卡在緩衝狀態。如果您需要播放這類檔案,可以分別使用 FLAG_DETECT_ACCESS_UNITSFLAG_ALLOW_NON_IDR_KEYFRAMES。您可以使用 setTsExtractorFlagsDefaultExtractorsFactory 上設定這些旗標,也可以使用建構函式DefaultHlsExtractorFactory 上設定。使用 FLAG_DETECT_ACCESS_UNITS 沒有任何副作用,除了相對於澳幣的影格界線偵測運算成本而言相當昂貴。使用 FLAG_ALLOW_NON_IDR_KEYFRAMES 可能會導致播放一開始出現視覺毀損情形,並在播放部分 MPEG-TS 檔案後立即執行跳轉。

為什麼部分 MPEG-TS 檔案沒有字幕?

部分 MPEG-TS 檔案包含 CEA-608 音軌,但並未在容器中繼資料宣告,因此 ExoPlayer 無法偵測這類檔案。如要手動指定任何字幕軌,請向 DefaultExtractorsFactory 提供預期字幕格式清單,包括可在 MPEG-TS 串流中識別的無障礙頻道:

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory()
    .setTsSubtitleFormats(
      listOf(
        Format.Builder()
          .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
          .setAccessibilityChannel(accessibilityChannel)
          // Set other subtitle format info, such as language.
          .build()
      )
    )
val player: Player =
  ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, extractorsFactory)).build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory()
        .setTsSubtitleFormats(
            ImmutableList.of(
                new Format.Builder()
                    .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
                    .setAccessibilityChannel(accessibilityChannel)
                    // Set other subtitle format info, such as language.
                    .build()));
Player player =
    new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

為什麼某些 MP4/FMP4 檔案無法正常播放?

部分 MP4/FMP4 檔案含有編輯清單,可藉由略過、移動或重複樣本清單來重新編寫媒體時間軸。ExoPlayer 能夠部分支援套用編輯清單。舉例來說,當同步處理樣本開始時,可能會延遲或重複執行一組樣本,但不會截斷音訊樣本或片頭媒體,用於未啟動同步樣本的編輯作業。

如果您發現媒體內容意外遺漏或重複,請嘗試設定 Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTSFragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS,這會導致擷取器完全忽略編輯清單。您可以使用 setMp4ExtractorFlagssetFragmentedMp4ExtractorFlagsDefaultExtractorsFactory 上設定這些屬性

為什麼有些串流因 HTTP 回應代碼 301 或 302 而失敗?

HTTP 回應代碼 301 和 302 都表示重新導向。您可以在維基百科上找到簡要說明。當 ExoPlayer 發出要求並收到狀態碼為 301 或 302 的回應時,通常會追蹤重新導向並正常開始播放。預設不執行跨通訊協定重新導向的情況。跨通訊協定重新導向是從 HTTPS 重新導向至 HTTP,反之亦然 (或這種做法較不常見的在另一組通訊協定之間)。您可以使用 wget 指令列工具測試網址是否會導致跨通訊協定重新導向,如下所示:

wget "https://yourserver.com/test.mp3" 2>&1  | grep Location

輸出內容應如下所示:

Location: https://second.com/test.mp3 [following]
Location: http://third.com/test.mp3 [following]

本例有兩次重新導向。第一個重新導向是從 https://yourserver.com/test.mp3https://second.com/test.mp3。兩者都是 HTTPS,因此並非跨通訊協定重新導向。第二個重新導向是從 https://second.com/test.mp3http://third.com/test.mp3。這會從 HTTPS 重新導向至 HTTP,因此屬於跨通訊協定重新導向。ExoPlayer 在預設設定中不會追蹤這個重新導向,表示播放失敗。

如有需要,您可以將 ExoPlayer 設定為在將應用程式中使用的 DefaultHttpDataSource.Factory 執行個體執行個體化時,遵循跨通訊協定重新導向。請在這裡瞭解如何選取及設定網路堆疊。

為什麼有些串流在 UnrecognizedInputFormatException 中會失敗?

這個問題與播放失敗下列表單有關:

UnrecognizedInputFormatException: None of the available extractors
(MatroskaExtractor, FragmentedMp4Extractor, ...) could read the stream.

這個錯誤的原因有兩種。最常見的原因是您嘗試播放 DASH (mpd)、HLS (m3u8) 或 SmoothStreaming (ism、isml) 內容,但播放器會嘗試以漸進式串流的形式播放內容。如要播放這類串流,您必須依附於個別的 ExoPlayer 模組。如果串流 URI 的結尾不是標準副檔名,您也可以將 MimeTypes.APPLICATION_MPDMimeTypes.APPLICATION_M3U8MimeTypes.APPLICATION_SS 傳遞至 MediaItem.BuildersetMimeType,明確指定串流類型。

另一個較不常見的原因是 ExoPlayer 不支援您嘗試播放的媒體的容器格式。在這種情況下,錯誤會照常運作,但歡迎您向我們的問題追蹤工具提交功能要求,包括容器格式和測試串流的詳細資料。提交新的功能要求前,請先搜尋現有的功能要求。

為什麼在部分裝置上,setPlaybackParameters 無法正常運作?

在 Android M 以下版本執行應用程式的偵錯版本時,使用 setPlaybackParameters API 時可能會遇到效能不穩定、有聲成果和高 CPU 使用率問題。這是因為在這些 Android 版本上執行的偵錯版本,這個 API 重要的最佳化功能已停用。

請注意,這個問題只會影響偵錯版本。這項設定「不會」影響一律啟用最佳化功能的發布子版本。因此,您提供給使用者的版本不會受到影響。

「在錯誤的執行緒上存取播放器」錯誤是什麼意思?

請參閱入門指南的「執行緒附註」。

如何修正「意外狀態行:ICY 200 OK」?

如果伺服器回應包含 ICY 狀態行,而不是符合 HTTP 規定的狀態行,就會發生這個問題。ICY 狀態行已淘汰,請勿使用,因此如果您控制伺服器,請更新該伺服器,提供符合 HTTP 規定的回應。如果沒辦法完成,則使用 ExoPlayer OkHttp 程式庫來解決問題,因為其能正確處理 ICY 狀態行。

如何查詢目前播放的串流是否為直播?

您可以查詢玩家的 isCurrentWindowLive 方法。此外,您也可以檢查 isCurrentWindowDynamic 來確認視窗是否為動態 (也就是仍在隨時間更新)。

如何在應用程式於背景執行時繼續播放音訊?

請按照下列步驟操作,確保應用程式在背景運作時能繼續播放音訊:

  1. 您必須擁有運作中的前景服務。這樣可以防止系統終止您的程序以釋出資源。
  2. 您必須按住 WifiLockWakeLock。確保系統能保持 Wi-Fi 無線電和 CPU 喚醒。只要使用 ExoPlayer,只要呼叫 setWakeMode,系統就會自動取得並在正確的時間釋出必要的鎖定,輕鬆達到這個目標。

請務必在不使用 setWakeMode 的情況下釋出鎖定,並在音訊不再播放時立即停止服務。

為什麼 ExoPlayer 支援我的內容,但 ExoPlayer Cast 程式庫不支援我的內容?

您嘗試播放的內容可能尚未啟用 CORSCast 架構內容必須啟用 CORS 才能播放。

為什麼內容無法播放,卻未顯示錯誤?

這可能是因為您播放內容的裝置不支援特定媒體取樣格式。只要將 EventLogger 新增為玩家的事件監聽器,並在 Logcat 中尋找類似線條,即可輕鬆確認這一點:

[ ] Track:x, id=x, mimeType=mime/type, ... , supported=NO_UNSUPPORTED_TYPE

NO_UNSUPPORTED_TYPE 表示裝置無法解碼 mimeType 指定的媒體範例格式。如要瞭解支援的範例格式,請參閱 Android 媒體格式說明文件如何載入解碼程式庫並用於播放?

如何取得可載入並用於播放的解碼程式庫?

  • 大部分的解碼器程式庫都有手動檢查及建構依附元件的步驟,因此請確認您已按照相關程式庫的 README 中的步驟操作。例如,對於 ExoPlayer FFmpeg 程式庫,您必須遵循 Library/decoder_ffmpeg/README.md 中的操作說明,包括針對想播放的格式傳送設定旗標至啟用解碼器
  • 如果程式庫含有原生程式碼,請確認您使用的是 README 中指定的正確 Android NDK 版本,並留意設定和建構期間是否發生的任何錯誤。按照 README 中的步驟進行後,您應該就會看到 .so 檔案出現在每個支援架構的程式庫路徑 libs 子目錄中。
  • 如要使用試用版應用程式中的程式庫嘗試播放,請參閱啟用隨附解碼器。如需從自己的應用程式使用程式庫的操作說明,請參閱程式庫的 README 檔案。
  • 如果您使用的是 DefaultRenderersFactory,則解碼器載入後,Logcat 中應該會顯示資訊層級記錄行,例如「Loaded FfmpegAudioRenderer」。如果缺少該行為,請確認應用程式對解碼程式庫具有依附元件。
  • 如果您在 Logcat 中看到來自 LibraryLoader 的警告等級記錄,就表示無法載入程式庫的原生元件。如果發生這種情況,請檢查是否已正確按照程式庫的 README 步驟操作,並且按照指示操作,過程中並未輸出任何錯誤。

如果您仍然無法順利使用解碼程式庫,請查看 Media3 Issue Tracker,瞭解近期是否有任何相關問題。如果您需要提報新的問題,而且問題與建構程式庫的原生部分有關,請附上執行 README 操作說明的完整指令列輸出內容,協助我們診斷問題。

我可以使用 ExoPlayer 直接播放 YouTube 影片嗎?

不可以,ExoPlayer 無法播放 YouTube 的影片 (例如 https://www.youtube.com/watch?v=... 格式的網址),請改用 YouTube IFrame Player API,這是在 Android 裝置上播放 YouTube 影片的官方方式。

影片播放不流暢

舉例來說,如果內容位元率或解析度超過裝置功能,則裝置可能無法快速解碼內容。您可能需要使用品質不佳的內容,才能在這類裝置上取得良好效能。

如果您在搭載 Android 6.0 (API 級別 23) 至 Android 11 (API 級別 30) 的 Android 版本裝置上遇到影片延遲問題,尤其是播放受 DRM 保護或高影格速率內容時,可以嘗試啟用非同步緩衝區佇列