Cốt lõi của thư viện ExoPlayer là giao diện Player
. Một Player
cung cấp chức năng trình phát đa phương tiện truyền thống cấp cao, chẳng hạn như khả năng
lưu vào bộ đệm nội dung nghe nhìn, phát, tạm dừng và tua. Phương thức triển khai mặc định ExoPlayer
là
được thiết kế nhằm đưa ra ít giả định (và do đó áp dụng ít hạn chế đối với)
loại nội dung đa phương tiện đang được phát, cách thức và vị trí lưu trữ nội dung đa phương tiện cũng như cách thức
kết xuất. Thay vì triển khai trực tiếp việc tải và kết xuất nội dung nghe nhìn,
Quá trình triển khai ExoPlayer
uỷ quyền công việc này cho các thành phần được chèn
khi một trình phát được tạo hoặc khi các nguồn nội dung nghe nhìn mới được chuyển đến trình phát.
Các thành phần phổ biến cho tất cả quá trình triển khai ExoPlayer
là:
- Các thực thể
MediaSource
xác định nội dung nghe nhìn sẽ phát, tải nội dung nghe nhìn và mà từ đó có thể đọc nội dung nghe nhìn đã tải. Đã tạo một thực thểMediaSource
từMediaItem
củaMediaSource.Factory
bên trong trình phát. Họ cũng có thể được chuyển trực tiếp đến trình phát thông qua API danh sách phát dựa trên nguồn nội dung nghe nhìn. - Một thực thể
MediaSource.Factory
chuyển đổiMediaItem
thànhMediaSource
. Chiến lược phát hành đĩa đơnMediaSource.Factory
được chèn khi tạo trình phát. - Các thực thể
Renderer
kết xuất các thành phần riêng lẻ của nội dung nghe nhìn. Đây là được chèn khi tạo trình phát. - Một
TrackSelector
chọn các bản nhạc doMediaSource
cung cấp sẽ là được tiêu thụ bởi mỗiRenderer
có sẵn. MộtTrackSelector
được chèn khi tạo trình phát. LoadControl
kiểm soát thời điểmMediaSource
lưu vào bộ đệm thêm nội dung nghe nhìn, và lượng nội dung nghe nhìn được lưu vào bộ đệm.LoadControl
được chèn khi người chơi đã tạo.- Một
LivePlaybackSpeedControl
kiểm soát tốc độ phát trong khi phát trực tiếp số lần phát để cho phép trình phát luôn ở gần một điểm bù trực tiếp đã định cấu hình. ĐápLivePlaybackSpeedControl
được chèn khi tạo trình phát.
Khái niệm chèn các thành phần để triển khai các đoạn của người chơi có sẵn trong toàn bộ thư viện. Các cách triển khai mặc định của một số thành phần uỷ quyền công việc cho các thành phần được chèn thêm. Điều này cho phép nhiều các thành phần phụ cần được thay thế riêng lẻ bằng những thành phần triển khai được định cấu hình theo cách tuỳ chỉnh.
Tuỳ chỉnh trình phát
Một số ví dụ phổ biến về tuỳ chỉnh trình phát bằng cách chèn các thành phần là được mô tả bên dưới.
Định cấu hình ngăn xếp mạng
Chúng tôi có một trang về cách tuỳ chỉnh ngăn xếp mạng mà ExoPlayer sử dụng.
Lưu dữ liệu vào bộ nhớ đệm được tải từ mạng
Xem hướng dẫn về lưu vào bộ nhớ đệm tạm thời một cách nhanh chóng và tải nội dung nghe nhìn xuống.
Tuỳ chỉnh hoạt động tương tác với máy chủ
Một số ứng dụng có thể muốn chặn các yêu cầu và phản hồi HTTP. Bạn nên chèn tiêu đề yêu cầu tuỳ chỉnh, đọc tiêu đề phản hồi của máy chủ, sửa đổi các yêu cầu URI, v.v. Ví dụ: ứng dụng của bạn có thể tự xác thực bằng cách chèn mã thông báo làm tiêu đề khi yêu cầu các phân đoạn phương tiện.
Ví dụ sau minh hoạ cách triển khai những hành vi này bằng
chèn một DataSource.Factory
tuỳ chỉnh vào DefaultMediaSourceFactory
:
Kotlin
val dataSourceFactory = DataSource.Factory { val dataSource = httpDataSourceFactory.createDataSource() // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value") dataSource } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory) ) .build()
Java
DataSource.Factory dataSourceFactory = () -> { HttpDataSource dataSource = httpDataSourceFactory.createDataSource(); // Set a custom authentication request header. dataSource.setRequestProperty("Header", "Value"); return dataSource; }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(dataSourceFactory)) .build();
Trong đoạn mã trên, HttpDataSource
được chèn bao gồm tiêu đề
"Header: Value"
trong mỗi yêu cầu HTTP. Hành vi này được khắc phục cho mỗi
tương tác với một nguồn HTTP.
Để có cách tiếp cận chi tiết hơn, bạn có thể chèn hành vi đúng thời điểm bằng cách sử dụng
ResolvingDataSource
. Đoạn mã sau đây minh hoạ cách chèn
của yêu cầu ngay trước khi tương tác với nguồn HTTP:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time request headers. dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time request headers. dataSpec -> dataSpec.withRequestHeaders(getCustomHeaders(dataSpec.uri)));
Bạn cũng có thể dùng ResolvingDataSource
để thực hiện
các sửa đổi kịp thời của URI, như minh hoạ trong đoạn mã sau:
Kotlin
val dataSourceFactory: DataSource.Factory = ResolvingDataSource.Factory(httpDataSourceFactory) { dataSpec: DataSpec -> // Provide just-in-time URI resolution logic. dataSpec.withUri(resolveUri(dataSpec.uri)) }
Java
DataSource.Factory dataSourceFactory = new ResolvingDataSource.Factory( httpDataSourceFactory, // Provide just-in-time URI resolution logic. dataSpec -> dataSpec.withUri(resolveUri(dataSpec.uri)));
Tuỳ chỉnh cách xử lý lỗi
Việc triển khai một LoadErrorHandlingPolicy
tuỳ chỉnh cho phép các ứng dụng tuỳ chỉnh
cách ExoPlayer phản ứng với các lỗi tải. Ví dụ: một ứng dụng có thể muốn gặp lỗi nhanh
thay vì thử lại nhiều lần hoặc có thể muốn tuỳ chỉnh logic thời gian đợi
kiểm soát khoảng thời gian người chơi chờ giữa mỗi lần thử lại. Đoạn mã sau
cho biết cách triển khai logic thời gian đợi tuỳ chỉnh:
Kotlin
val loadErrorHandlingPolicy: LoadErrorHandlingPolicy = object : DefaultLoadErrorHandlingPolicy() { override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long { // Implement custom back-off logic here. return 0 } } val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setLoadErrorHandlingPolicy(loadErrorHandlingPolicy) ) .build()
Java
LoadErrorHandlingPolicy loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy() { @Override public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { // Implement custom back-off logic here. return 0; } }; ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)) .build();
Đối số LoadErrorInfo
chứa thêm thông tin về việc không tải được
tuỳ chỉnh logic dựa trên loại lỗi hoặc yêu cầu không thành công.
Tuỳ chỉnh cờ của trình trích xuất
Bạn có thể sử dụng cờ của trình trích xuất để tuỳ chỉnh cách trích xuất từng định dạng
từ các phương tiện truyền thông tiến bộ. Bạn có thể đặt chúng trên DefaultExtractorsFactory
được cung cấp cho DefaultMediaSourceFactory
. Ví dụ sau truyền một cờ
cho phép tìm kiếm dựa trên chỉ mục cho luồng MP3.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING) val player = ExoPlayer.Builder(context) .setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory)) .build()
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setMp3ExtractorFlags(Mp3Extractor.FLAG_ENABLE_INDEX_SEEKING); ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory(new DefaultMediaSourceFactory(context, extractorsFactory)) .build();
Bật tính năng tìm kiếm tốc độ bit liên tục
Đối với các luồng MP3, ADTS và AMR, bạn có thể bật tua gần đúng bằng cách sử dụng
giả định tốc độ bit không đổi với cờ FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
.
Bạn có thể đặt những cờ này cho từng trình trích xuất bằng cách sử dụng
DefaultExtractorsFactory.setXyzExtractorFlags
như mô tả ở trên. Người nhận
bật tính năng tìm kiếm tốc độ bit không đổi cho tất cả các trình trích xuất hỗ trợ tốc độ bit, hãy sử dụng
DefaultExtractorsFactory.setConstantBitrateSeekingEnabled
.
Kotlin
val extractorsFactory = DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true)
Java
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
Sau đó, ExtractorsFactory
có thể được chèn thông qua DefaultMediaSourceFactory
dưới dạng
được mô tả để tuỳ chỉnh cờ trình trích xuất ở trên.
Bật hàng đợi bộ đệm không đồng bộ
Hàng đợi bộ đệm không đồng bộ là một tính năng nâng cao trong quá trình kết xuất của ExoPlayer
quy trình vận hành các thực thể MediaCodec
ở chế độ không đồng bộ và
sử dụng các luồng bổ sung để lên lịch giải mã và hiển thị dữ liệu. Bật tính năng này
có thể giảm tình trạng rớt khung hình và tình trạng âm thanh chạy ngầm.
Tính năng xếp hàng đợi bộ đệm không đồng bộ được bật theo mặc định trên các thiết bị chạy Android 12 (API cấp 31) trở lên và có thể bật theo cách thủ công kể từ Android 6.0 (API cấp 23). Hãy cân nhắc việc bật tính năng này cho những thiết bị cụ thể mà bạn thấy là đã bị bỏ qua tình trạng chạy dưới khung hình hoặc âm thanh, đặc biệt là khi phát video được bảo vệ bằng DRM hoặc tốc độ khung hình cao nội dung.
Trong trường hợp đơn giản nhất, bạn cần chèn DefaultRenderersFactory
vào
trình phát như sau:
Kotlin
val renderersFactory = DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing() val exoPlayer = ExoPlayer.Builder(context, renderersFactory).build()
Java
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(context).forceEnableMediaCodecAsynchronousQueueing(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context, renderersFactory).build();
Nếu bạn đang tạo thực thể của trình kết xuất trực tiếp, hãy truyền
AsynchronousMediaCodecAdapter.Factory
đến MediaCodecVideoRenderer
và
Hàm khởi tạo MediaCodecAudioRenderer
.
Chặn lệnh gọi phương thức bằng ForwardingPlayer
Bạn có thể tuỳ chỉnh một số hành vi của thực thể Player
bằng cách gói thực thể đó vào
một lớp con của ForwardingPlayer
và các phương thức ghi đè để thực hiện bất kỳ
như sau:
- Truy cập các tham số trước khi truyền các tham số đó đến
Player
uỷ quyền. - Truy cập vào giá trị trả về từ
Player
uỷ quyền trước khi trả về. - Triển khai lại hoàn toàn phương thức.
Khi ghi đè phương thức ForwardingPlayer
, bạn phải đảm bảo phương thức
phương pháp triển khai vẫn tự nhất quán và tuân thủ Player
giao diện, đặc biệt là khi xử lý các phương thức dùng để
hành vi giống hệt hoặc có liên quan. Ví dụ:
- Nếu bạn muốn ghi đè mọi lượt "phát" , bạn cần ghi đè cả hai
ForwardingPlayer.play
vàForwardingPlayer.setPlayWhenReady
vì một phương thức gọi sẽ dự kiến hành vi của các phương thức này giống hệt nhau khiplayWhenReady = true
. - Nếu muốn thay đổi gia số tua đi, bạn cần phải ghi đè cả hai giá trị
ForwardingPlayer.seekForward
để thực hiện tua bằng vàForwardingPlayer.getSeekForwardIncrement
để báo cáo. mức tăng đã tuỳ chỉnh chính xác trở lại phương thức gọi. - Nếu bạn muốn kiểm soát nội dung mà trình phát quảng cáo về
Player.Commands
Bạn phải ghi đè cảPlayer.getAvailableCommands()
vàPlayer.isCommandAvailable()
cũng như nghe Gọi lạiPlayer.Listener.onAvailableCommandsChanged()
để nhận thông báo về những thay đổi đến từ trình phát cơ bản.
Tuỳ chỉnh MediaSource
Các ví dụ ở trên chèn các thành phần tuỳ chỉnh để sử dụng trong quá trình phát lại tất cả
Các đối tượng MediaItem
được truyền đến người chơi. Trong trường hợp tuỳ chỉnh chi tiết
bắt buộc, bạn cũng có thể chèn các thành phần tuỳ chỉnh vào từng
Các thực thể MediaSource
có thể được truyền trực tiếp đến người chơi. Ví dụ
bên dưới cho biết cách tuỳ chỉnh ProgressiveMediaSource
để sử dụng
DataSource.Factory
, ExtractorsFactory
và LoadErrorHandlingPolicy
:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri))
Java
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(customDataSourceFactory, customExtractorsFactory) .setLoadErrorHandlingPolicy(customLoadErrorHandlingPolicy) .createMediaSource(MediaItem.fromUri(streamUri));
Tạo thành phần tuỳ chỉnh
Thư viện cung cấp phương thức triển khai mặc định cho các thành phần được liệt kê ở trên cùng
của trang này cho các trường hợp sử dụng phổ biến. ExoPlayer
có thể sử dụng các thành phần này, nhưng
cũng có thể được xây dựng để sử dụng các phương pháp triển khai tuỳ chỉnh nếu các hành vi không theo chuẩn là
là bắt buộc. Một số trường hợp sử dụng triển khai tuỳ chỉnh là:
Renderer
– Bạn có thể cần triển khai mộtRenderer
tuỳ chỉnh để xử lý một loại phương tiện không được hỗ trợ bởi cách triển khai mặc định được cung cấp bởi thư viện của bạn.TrackSelector
– Việc triển khaiTrackSelector
tuỳ chỉnh cho phép ứng dụng thay đổi cách các kênh màMediaSource
hiển thị được chọn để tiêu thụ bởi từngRenderer
hiện có.LoadControl
– Việc triển khaiLoadControl
tuỳ chỉnh cho phép ứng dụng thay đổi chính sách lưu vào bộ đệm của trình phát.Extractor
– Nếu bạn cần hỗ trợ một định dạng vùng chứa hiện không được hỗ trợ được thư viện hỗ trợ, hãy cân nhắc triển khai một lớpExtractor
tuỳ chỉnh.MediaSource
– Việc triển khai một lớpMediaSource
tuỳ chỉnh có thể thích hợp nếu bạn muốn lấy mẫu nội dung đa phương tiện để cấp dữ liệu cho trình kết xuất hoặc nếu bạn muốn triển khai tính năng tổng hợpMediaSource
tuỳ chỉnh hành vi.MediaSource.Factory
– Triển khai mộtMediaSource.Factory
tuỳ chỉnh cho phép ứng dụng tuỳ chỉnh cách tạoMediaSource
từMediaItem
.DataSource
– Gói ngược dòng của ExoPlayer đã chứa một số Quá trình triển khaiDataSource
cho nhiều trường hợp sử dụng. Bạn nên triển khai lớpDataSource
của riêng bạn để tải dữ liệu theo cách khác, chẳng hạn như qua một giao thức tuỳ chỉnh, sử dụng ngăn xếp HTTP tuỳ chỉnh hoặc từ một giao thức cố định tuỳ chỉnh bộ nhớ đệm.
Khi tạo thành phần tuỳ chỉnh, bạn nên làm những việc sau:
- Nếu một thành phần tuỳ chỉnh cần báo cáo sự kiện cho ứng dụng, bạn nên
bạn làm như vậy bằng cách sử dụng cùng một mô hình như các thành phần ExoPlayer hiện có, để
ví dụ về cách sử dụng các lớp
EventDispatcher
hoặc truyền mộtHandler
cùng với một trình nghe đối với hàm khởi tạo của thành phần. - Các thành phần tuỳ chỉnh nên sử dụng cùng một mô hình như ExoPlayer hiện có
để cho phép ứng dụng định cấu hình lại trong khi phát. Để thực hiện việc này,
các thành phần tuỳ chỉnh nên triển khai
PlayerMessage.Target
và nhận các thay đổi về cấu hình trong phương thứchandleMessage
. Mã xử lý ứng dụng nên chuyển các thay đổi về cấu hình bằng cách gọi phương thứccreateMessage
của ExoPlayer, định cấu hình thông báo và gửi thông báo đến thành phần bằng cách sử dụngPlayerMessage.send
Đang gửi tin nhắn để gửi trên chuỗi phát sẽ đảm bảo rằng chúng được thực thi theo thứ tự cùng với bất kỳ thao tác nào khác đang được thực hiện trên trình phát.