- 修正「不允許明文 HTTP 流量」錯誤
- 修正「SSLHandshakeException」、「CertPathValidatorException」和「ERR_CERT_AUTHORITY_INVALID」錯誤
- 為什麼有些媒體檔案無法跳轉?
- 為什麼某些 MP3 檔案的跳轉功能不準確?
- 為什麼影片跳轉速度緩慢?
- 為什麼有些 MPEG-TS 檔案無法播放?
- 為什麼部分 MPEG-TS 檔案找不到字幕?
- 為什麼有些 MP4/FMP4 檔案無法正常播放?
- 為什麼有些串流會失敗,並顯示 HTTP 回應代碼 301 或 302?
- 為什麼有些串流會失敗,並顯示 UnrecognizedInputFormatException?
- 為什麼 setPlaybackParameters 在某些裝置上無法正常運作?
- 「Player is accessed on the wrong thread」錯誤代表什麼意思?
- 如何修正「Unexpected status line: ICY 200 OK」?
- 如何查詢播放中的串流是否為直播?
- 如何讓應用程式在背景播放音訊?
- 為什麼 ExoPlayer 支援我的內容,但 ExoPlayer Cast 程式庫不支援?
- 為什麼內容無法播放,但沒有顯示錯誤?
- 如何載入解碼程式庫並用於播放?
- 可以直接用 ExoPlayer 播放 YouTube 影片嗎?
- 影片播放不流暢
- 不穩定 API Lint 錯誤
- 如何測試或找出新最佳化功能或功能造成的問題?
修正「不允許明文 HTTP 流量」錯誤
如果應用程式在網路安全性設定不允許的情況下,要求明文 HTTP 流量 (即 http:// 而非 https://),就會發生這項錯誤。如果應用程式指定 Android 9 (API 級別 28) 以上版本為目標,預設設定會停用明文 HTTP 流量。
如果應用程式需要處理明文 HTTP 流量,則必須使用允許這類流量的網路安全性設定。詳情請參閱 Android 的網路安全說明文件。如要啟用所有明文 HTTP 流量,只要將 android:usesCleartextTraffic="true" 新增至應用程式 AndroidManifest.xml 的 application 元素即可。
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 影格 (主要畫面格) 開始解碼,因為大多數影片壓縮格式都使用影格內編碼。為確保跳轉準確 (也就是播放作業從跳轉位置開始),系統必須解碼前一個 I 影格和跳轉位置之間的所有影格,並立即捨棄 (不顯示在螢幕上)。
如要減少 (1) 造成的延遲,可以增加播放器在記憶體中緩衝的資料量,或將資料預先快取到磁碟。
如要減少 (2) 造成的延遲,可以使用 ExoPlayer.setSeekParameters 降低跳轉精確度,或重新編碼影片,提高 I 影格頻率 (這會導致輸出檔案變大)。
為什麼有些 MPEG-TS 檔案無法播放?
部分 MPEG-TS 檔案不含存取單位分隔符 (AUD)。根據預設,ExoPlayer 會依賴 AUD 偵測影格邊界,同樣地,部分 MPEG-TS 檔案不含 IDR 主要畫面格。根據預設,ExoPlayer 只會考量這類主要畫面格。
如果要求 ExoPlayer 播放缺少 AUD 或 IDR 主要畫面格的 MPEG-TS 檔案,ExoPlayer 會卡在緩衝狀態。如要播放這類檔案,可以分別使用 FLAG_DETECT_ACCESS_UNITS 和 FLAG_ALLOW_NON_IDR_KEYFRAMES。您可以使用 setTsExtractorFlags 在
DefaultExtractorsFactory 上設定這些旗標,或使用
建構函式在
DefaultHlsExtractorFactory 上設定。
使用 FLAG_DETECT_ACCESS_UNITS 不會有任何副作用,但相較於以 AUD 為基礎的影格邊界偵測,運算成本較高。播放部分 MPEG-TS 檔案時,使用 FLAG_ALLOW_NON_IDR_KEYFRAMES 可能會導致播放開始時和跳轉後,暫時出現視覺損毀。
為什麼部分 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.example.com/test.mp3" 2>&1 | grep Location
輸出內容大致如下:
Location: https://secondserver.example.net/test.mp3 [following]
Location: http://thirdserver.example.org/test.mp3 [following]
在這個範例中,有兩個重新導向。第一個重新導向是從 https://yourserver.example.com/test.mp3 到 https://secondserver.example.net/test.mp3。兩者都是 HTTPS,因此這不是跨通訊協定重新導向。第二次重新導向是從 https://secondserver.example.net/test.mp3 到 http://thirdserver.example.org/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 不支援您嘗試播放的媒體容器格式。在這種情況下,失敗是預期行為,但歡迎透過Issue Tracker提交功能要求,並附上容器格式和測試串流的詳細資料。提交新的功能要求前,請先搜尋現有的功能要求。
為什麼 setPlaybackParameters 在某些裝置上無法正常運作?
在 Android M 及更早版本上執行應用程式的偵錯版本時,使用 setPlaybackParameters API 可能會遇到效能不穩、音訊不自然和 CPU 使用率過高的情況。這是因為在這些 Android 版本上執行的偵錯版本,會停用這個 API 的重要最佳化功能。
請注意,這個問題只會影響偵錯版本。這不會影響發布子版本,因為發布子版本一律會啟用最佳化功能。因此,您提供給使用者的版本不應受到這個問題影響。
「Player is accessed on the wrong thread」錯誤代表什麼意思?
請參閱入門頁面的「執行緒注意事項」一節。
如何修正「Unexpected status line: 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 程式庫,就必須按照 libraries/decoder_ffmpeg/README.md 中的操作說明,包括將設定旗標傳遞至啟用解碼器,以便播放任何格式。
- 如果程式庫含有原生程式碼,請務必使用 README 中指定的正確 Android NDK 版本,並留意設定和建構期間出現的任何錯誤。按照 README 中的步驟操作後,您應該會在程式庫路徑的
libs子目錄中,看到每個支援架構的.so檔案。 - 如要嘗試在試用版應用程式中使用程式庫播放,請參閱「啟用隨附解碼器」。如要瞭解如何在自己的應用程式中使用程式庫,請參閱程式庫的 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 影片的官方方式,請改用這個 API。
影片播放不流暢
舉例來說,如果內容位元率或解析度超出裝置能力,裝置可能無法快速解碼內容。您可能需要使用品質較低的內容,才能在這類裝置上獲得良好效能。
如果裝置搭載 Android 6.0 (API 級別 23) 至 Android 11 (API 級別 30) 之間的版本,且影片出現卡頓情形 (特別是在播放受 DRM 保護或高影格率的內容時),可以嘗試啟用非同步緩衝區佇列。
不穩定 API lint 錯誤
Media3 保證部分 API 介面的二進位檔相容性。「不」保證二進位檔相容性的部分會標示 @UnstableApi。為明確區分,除非使用 @OptIn 加上註解,否則使用不穩定的 API 符號會產生 Lint 錯誤。
@UnstableApi 註解並未暗示 API 的品質或效能,僅表示 API 並非「API 凍結」。
您可以透過兩種方式處理不穩定 API Lint 錯誤:
- 請改用可達到相同結果的穩定 API。
- 繼續使用不穩定的 API,並使用
@OptIn註解用法,如下所示。
新增 @OptIn 註解
Android Studio 可協助您新增註解:
您也可以手動為特定用途網站加上註解:
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 檔案:
Kotlin
// In your package-info.kt
@OptIn(UnstableApi::class)
package name.of.your.package
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
Java
// In your 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 註解。
如何測試或找出新最佳化功能或功能造成的問題?
Media3 包含功能旗標基礎架構,在 Canary 模式下,預設會啟用新推出的功能和最佳化功能。
如果您懷疑應用程式中的問題或迴歸與新推出的功能或最佳化有關,可以暫時停用 Canary 模式:
Flags.setCanaryModeEnabled(false);
或使用 Flags.disableFlag(flagId) 個別停用特定功能旗標。如要進一步瞭解如何設定 Canary 模式、覆寫旗標,以及設定遠端終止參數,請參閱功能旗標和 Canary 模式指南。