- 修正「不允許的明文 HTTP 流量」錯誤
- 修正「SSLHandshakeException」、「CertPathValidatorException」和「ERR_CERT_AUTHORITY_INVALID」錯誤
- 為什麼無法搜尋某些媒體檔案?
- 為什麼某些 MP3 檔案含有不正確的字幕?
- 為什麼影片跳轉速度變慢?
- 為什麼部分 MPEG-TS 檔案無法播放?
- 為什麼部分 MPEG-TS 檔案沒有字幕?
- 為什麼某些 MP4/FMP4 檔案無法正確播放?
- 為什麼有些串流因 HTTP 回應代碼 301 或 302 而失敗?
- 為什麼有些串流在 UnrecognizedInputFormatException 會失敗?
- 為什麼在部分裝置上,setPlaybackParameters 無法正常運作?
- 「在錯誤的執行緒上存取播放器」錯誤是什麼意思?
- 如何修正「意外狀態行:ICY 200 OK」?
- 如何查詢目前播放的串流是否為直播?
- 如何在應用程式在背景執行時繼續播放音訊?
- 為什麼 ExoPlayer 支援我的內容,但 ExoPlayer Cast 程式庫不支援我的內容?
- 為什麼內容無法播放,卻沒有顯示任何錯誤?
- 如何取得可載入並用於播放的解碼程式庫?
- 我可以使用 ExoPlayer 直接播放 YouTube 影片嗎?
- 影片播放不流暢
- 不穩定的 API Lint 錯誤
修正「不允許的明文 HTTP 流量」錯誤
如果應用程式在網路安全性設定不允許的情況下要求明文 HTTP 流量 (亦即 http://
,而非 https://
),就會發生這個錯誤。如果應用程式指定 Android 9 (API 級別 28) 以上版本,則根據預設設定會停用明文 HTTP 流量。
如果應用程式需要處理明文 HTTP 流量,您必須使用允許該連線的網路安全性設定。詳情請參閱 Android 的網路安全性說明文件。如要啟用所有明文 HTTP 流量,只要在應用程式 AndroidManifest.xml
的 application
元素中加入 android:usesCleartextTraffic="true"
即可。
ExoPlayer 試用版應用程式使用預設的「網路安全性設定」,因此不允許使用明文 HTTP 流量。您可以按照上述操作說明啟用。
修正「SSLHandshakeException」、「CertPathValidatorException」和「ERR_CERT_AUTHORITY_INVALID」錯誤
SSLHandshakeException
、CertPathValidatorException
和 ERR_CERT_AUTHORITY_INVALID
都表示伺服器的 SSL 憑證有問題。這些錯誤並不是 ExoPlayer 特有的。詳情請參閱 Android SSL 說明文件。
為什麼無法搜尋某些媒體檔案?
根據預設,ExoPlayer 不支援在媒體中搜尋,因為唯一執行準確搜尋作業的方法是讓玩家掃描整個檔案,並為其建立索引。ExoPlayer 會將這類檔案視為無法瀏覽。大部分的現代媒體容器格式包括用於搜尋的中繼資料 (例如範例索引)、明確定義的搜尋演算法 (例如,在 Ogg 的內插雙節搜尋),或表示內容為固定位元率。在這種情況下,ExoPlayer 會採用並支援有效的搜尋作業。
如果您需要跳轉,卻找不到媒體,建議您轉換內容,以使用更適當的容器格式。針對 MP3、ADTS 和 AMR 檔案,您也可以假設檔案具有固定位元率,詳情請參閱這篇文章。
為什麼某些 MP3 檔案含有不正確的字幕?
可變位元率 (VBR) MP3 檔案基本上不適合用於需要精確跳轉的用途。造成這種情況的原因有兩種:
- 就精確搜尋而言,容器格式在理想情況下應在標頭中提供精確的時間到位元組對應。此對應可讓玩家將要求的搜尋時間對應到對應的位元組偏移,然後開始要求、剖析和播放來自該位移的媒體。可惜的是,在 MP3 中指定這項對應的標頭 (例如 XING 標頭) 通常不夠精確。
- 至於沒有提供精確時間對位元組對應關係 (或任何時間到位元組對應) 的容器格式,如果容器中有絕對範例時間戳記,您還是可以執行精確搜尋。在這種情況下,玩家可以將搜尋時間對應至準確的對應位元組偏移、開始從該偏移要求媒體、剖析第一個絕對樣本時間戳記,以及有效地在媒體中執行引導式二進位檔搜尋,直到找到正確的樣本為止。遺憾的是,MP3 未在串流中加入絕對樣本時間戳記,因此這個方法不可能。
基於上述原因,如要精確搜尋 VBR MP3 檔案,唯一的方法是掃描整個檔案,然後在播放器中手動建構時間到位元組對應。您可以使用 FLAG_ENABLE_INDEX_SEEKING
啟用這項策略,使用 setMp3ExtractorFlags
在 DefaultExtractorsFactory
上設定該策略。請注意,此方法無法適當縮放至大型 MP3 檔案,特別是當使用者嘗試在開始播放後不久才嘗試前往串流即將結束時,這時玩家需要等到整個串流下載和索引之後,才能執行搜尋作業。在 ExoPlayer 中,我們決定針對速度進行最佳化,而不是提升準確率,因此 FLAG_ENABLE_INDEX_SEEKING
會預設為停用。
如果您要控制正在播放的媒體,強烈建議您使用更適當的容器格式,例如 MP4。我們知道 MP3 是最佳媒體格式的最佳選擇。
為什麼影片跳轉速度變慢?
播放器跳轉至影片中的新播放位置時,需要執行下列兩項操作:
- 將與新播放位置相對應的資料載入緩衝區 (如果這項資料已緩衝處理,可能就不需要進行)。
- 由於大多數影片壓縮格式都會用到影格內編碼,因此影片解碼器會在新的播放位置之前,開始從 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_UNITS
和 FLAG_ALLOW_NON_IDR_KEYFRAMES
。您可以使用 setTsExtractorFlags
在 DefaultExtractorsFactory
上設定這些旗標,也可以使用建構函式在 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_LISTS
或 FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS
,這會導致擷取器完全忽略編輯清單。您可以使用 setMp4ExtractorFlags
或 setFragmentedMp4ExtractorFlags
,在 DefaultExtractorsFactory
上設定這些屬性。
為什麼有些串流因 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.mp3
到 https://second.com/test.mp3
。兩者都是 HTTPS,因此並非跨通訊協定重新導向。第二個重新導向是從 https://second.com/test.mp3
到 http://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_MPD
、MimeTypes.APPLICATION_M3U8
或 MimeTypes.APPLICATION_SS
傳遞至 MediaItem.Builder
的 setMimeType
,明確指定串流類型。
另一個較不常見的原因是 ExoPlayer 不支援您嘗試播放的媒體的容器格式。在這種情況下,錯誤會照常運作,但歡迎您向我們的問題追蹤工具提交功能要求,包括容器格式和測試串流的詳細資料。提交新的功能要求前,請先搜尋現有的功能要求。
為什麼在部分裝置上,setPlaybackParameters 無法正常運作?
在 Android M 以下版本執行應用程式的偵錯版本時,使用 setPlaybackParameters
API 時可能會遇到效能不穩定、有聲成果和高 CPU 使用率問題。這是因為在這些 Android 版本上執行的偵錯版本,這個 API 重要的最佳化功能已停用。
請注意,這個問題只會影響偵錯版本。這項設定「不會」影響一律啟用最佳化功能的發布子版本。因此,您提供給使用者的版本不會受到影響。
「在錯誤的執行緒上存取播放器」錯誤是什麼意思?
請參閱入門指南的「執行緒附註」。
如何修正「意外狀態行:ICY 200 OK」?
如果伺服器回應包含 ICY 狀態行,而不是符合 HTTP 規定的狀態行,就會發生這個問題。ICY 狀態行已淘汰,請勿使用,因此如果您控制伺服器,請更新該伺服器,提供符合 HTTP 規定的回應。如果沒辦法完成,則使用 ExoPlayer OkHttp 程式庫來解決問題,因為其能正確處理 ICY 狀態行。
如何查詢目前播放的串流是否為直播?
您可以查詢玩家的 isCurrentWindowLive
方法。此外,您也可以檢查 isCurrentWindowDynamic
來確認視窗是否為動態 (也就是仍在隨時間更新)。
如何在應用程式於背景執行時繼續播放音訊?
請按照下列步驟操作,確保應用程式在背景運作時能繼續播放音訊:
- 您必須擁有運作中的前景服務。這樣可以防止系統終止您的程序以釋出資源。
- 您必須按住
WifiLock
和WakeLock
。確保系統能保持 Wi-Fi 無線電和 CPU 喚醒。只要使用ExoPlayer
,只要呼叫setWakeMode
,系統就會自動取得並在正確的時間釋出必要的鎖定,輕鬆達到這個目標。
請務必在不使用 setWakeMode
的情況下釋出鎖定,並在音訊不再播放時立即停止服務。
為什麼 ExoPlayer 支援我的內容,但 ExoPlayer Cast 程式庫不支援我的內容?
您嘗試播放的內容可能尚未啟用 CORS。Cast 架構內容必須啟用 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 保護或高影格速率內容時,可以嘗試啟用非同步緩衝區佇列。
不穩定的 API Lint 錯誤
Media3 保證部分 API 介面的二進位檔相容性。「無法」保證二進位檔相容性的部分會標示 @UnstableApi
。為清楚區分這項差異,使用不穩定的 API 符號時,除非加上 @OptIn
註解,否則會產生 Lint 錯誤。
@UnstableApi
註解並不代表 API 的品質或效能,只是代表該註解不會「API 凍結」。
您有兩種方法可處理不穩定的 API Lint 錯誤:
- 改用可達到相同結果的穩定 API。
- 繼續使用不穩定的 API,並使用
@OptIn
加上註解,如下所示。
新增 @OptIn
註解
Android Studio 可協助您新增註解:
![螢幕截圖:如何新增「選擇不採用」註解](https://developer.android.com/static/media/media3/exoplayer/images/unstable-api.png?authuser=0000&hl=zh-tw)
您也可以在 Kotlin 中手動為特定使用情形網站加上註解:
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
@OptIn(UnstableApi::class)
fun functionUsingUnstableApi() { ... }
使用 Java 時:
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
@OptIn(markerClass = UnstableApi.class)
private void methodUsingUnstableApis() { ... }
新增 package-info.java
檔案即可選擇加入整個套件:
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
只要隱藏 lint.xml
檔案中的特定 Lint 錯誤,即可選擇加入整個專案:
<?xml version="1.0" encoding="utf-8"?>
<lint>
<issue id="UnsafeOptInUsageError">
<option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
</issue>
</lint>
也有不應使用的 kotlin.OptIn
註解。請務必使用 androidx.annotation.OptIn
註解。