Latest Post

Tăng thứ hạng và truy cập tự nhiên với 10 phương pháp SEO hay nhất Kiếm Tiền Online (mmo): Khái Niệm và Các Hình Thức Phổ Biến

Phát video và âm thanh là một hoạt động phổ biến trên các thiết bị Android, và để thực hiện điều này, Android Framework cung cấp MediaPlayer như một giải pháp đơn giản và hiệu quả. MediaPlayer giúp dễ dàng thực hiện các chức năng cơ bản liên quan đến phát đa phương tiện.

Ngoài ra, Android cũng cung cấp các API đa phương tiện cấp thấp như MediaCodec, AudioTrack, và MediaDrm, giúp những nhà phát triển tạo ra trải nghiệm đa phương tiện tùy chỉnh theo mong muốn. Điều này có nghĩa là bạn có thể xây dựng trình phát đa phương tiện với các tính năng và giao diện riêng biệt.

Tuy nhiên, có một số trường hợp mà MediaPlayer không đáp ứng tốt, như khi bạn cần một giao diện người dùng tùy chỉnh, muốn theo dõi sự kiện trong danh sách phát video, hoặc cần tối ưu hóa tốc độ chiếu video. Đối với những yêu cầu như vậy, việc sử dụng các công nghệ và thư viện khác như ExoPlayer có thể là lựa chọn phù hợp hơn.

Những nhược điểm đó đã được khắc phục trên Exoplayer

ExoPlayer là gì?

ExoPlayer là một thư viện mã nguồn mở phát lại phương tiện được Google phát triển cho hệ điều hành Android. Được xây dựng bằng Java, ExoPlayer mang đến nhiều ưu điểm so với MediaPlayer, với tính tối ưu, linh hoạt và ổn định.

Các tính năng nổi bật của ExoPlayer bao gồm khả năng phát video và âm thanh, xáo trộn, lặp lại, hỗ trợ phụ đề, quản lý danh sách phát, khả năng lưu trữ và tải xuống, phát quảng cáo, streaming trực tiếp, nghệ thuật album, chế độ ngoại tuyến, và nhiều tiện ích mở rộng khác.

Nhiều ứng dụng nổi tiếng như Vevo, Twitter, BBC iPlayer, Netflix, Spotify, Facebook, Whatsapp, Twitch và nhiều ứng dụng khác trong Google Play Store đều tin dùng ExoPlayer để cung cấp trải nghiệm phương tiện mạnh mẽ và linh hoạt cho người dùng. Đến nay, có hơn 140.000 ứng dụng sử dụng ExoPlayer, là minh chứng cho sức mạnh và độ phổ biến của thư viện này trong cộng đồng phát triển Android.

Nhưng có 1 lưu ý là ExoPlayer chỉ hỗ trợ từ API 16 trở lên

Như bạn đã thấy, phiên bản Android tối thiểu trong dự án hiện tại của bạn là API cấp 16, chiếm 99,2% thiết bị Android đang hoạt động, Nên có vẻ nó cũng nằm trong sự tính toán của Google việc chỉ hỗ trợ API 16 trở lên cũng không phải vấn đề lớn lắm.

Giao diện mặc định của Exoplayer

Ngoài ra bạn có thể tùy chỉnh thêm các nút mặc định bằng việc sử dụng chính stype của exo mặc định: trước, tua lại, xáo trộn, phát, tạm dừng, chuyển tiếp, tiếp theo 1 nút đặc biệt: lặp lại

Đối với nút mặc định, thật dễ dàng để thêm từng nút trong tệp bố cục phát lại bằng cách thêm ImageButton và màu nút tùy chỉnh với tông màu, nút có thể vẽ với kiểu từ ExoPlayer

Nếu bạn xử lý phát / tạm dừng mà không phát lại, bạn có thể sử dụng mã này trong mã của mình. Sử dụng player.playWhenReady = false để tạm dừng phát phương tiện và* player.playWhenReady = true* để phát phương tiện và lưu trạng thái với playbackState.

Demo

Nào chúng ta cùng làm thử 1 demo để hiểu rõ hơn cách sử dụng của nó nhé

1. Cấu hình

Đầu tiên, thêm phụ thuộc ExoPlayer vào trong build.gradle mô-đun của bạn phiên bản hiện tại là 2.8.2 triển khai 'com.google.android.exoplayer: exoplayer: 2.8.2'

Sau đó cấp quyền truy cập internet cho thiết bị

<uses-permission android:name=”android.permission.INTERNET”/>

2. Custom lại giao diện

Bạn có thể sử dụng giao diện mặc định như mình hướng dẫn ở trên hoặc custom lại

Lưu ý: Để sử dụng được file layout thì bạn phải để tên file là ‘exo_playback_control_view.xml’ để ghi đè lên file gốc với các id như trên

exo_playback_control_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_gravity="bottom"
              android:layoutDirection="ltr"
              android:background="#CC000000"
              android:orientation="vertical">
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingTop="4dp"
            android:orientation="horizontal">
        <ImageButton android:id="@id/exo_prev"
                     style="@style/ExoMediaButton.Previous"/>
        <ImageButton android:id="@id/exo_rew"
                     style="@style/ExoMediaButton.Rewind"/>
        <ImageButton android:id="@id/exo_repeat_toggle"
                     style="@style/ExoMediaButton"/>
        <ImageButton android:id="@id/exo_play"
                     style="@style/ExoMediaButton.Play"/>
        <ImageButton android:id="@id/exo_pause"
                     style="@style/ExoMediaButton.Pause"/>
        <ImageButton android:id="@id/exo_ffwd"
                     style="@style/ExoMediaButton.FastForward"/>
        <ImageButton android:id="@id/exo_next"
                     style="@style/ExoMediaButton.Next"/>
    </LinearLayout>
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="4dp"
            android:gravity="center_vertical"
            android:orientation="horizontal">
        <TextView android:id="@id/exo_position"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textSize="14sp"
                  android:textStyle="bold"
                  android:paddingLeft="4dp"
                  android:paddingRight="4dp"
                  android:includeFontPadding="false"
                  android:textColor="#FFBEBEBE"/>
        <com.google.android.exoplayer2.ui.DefaultTimeBar
                android:id="@id/exo_progress"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="26dp"/>
        <TextView android:id="@id/exo_duration"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textSize="14sp"
                  android:textStyle="bold"
                  android:paddingLeft="4dp"
                  android:paddingRight="4dp"
                  android:includeFontPadding="false"
                  android:textColor="#FFBEBEBE"/>
        <FrameLayout
                android:id="@+id/exo_fullscreen_button"
                android:layout_width="32dp"
                android:layout_height="32dp"
                android:layout_gravity="right">
            <ImageView
                    android:id="@+id/exo_fullscreen_icon"
                    android:layout_width="18dp"
                    android:layout_height="18dp"
                    android:layout_gravity="center"
                    android:adjustViewBounds="true"
                    android:scaleType="fitCenter"
                    android:src="@drawable/ic_fullscreen_expand"/>
        </FrameLayout>
    </LinearLayout>
</LinearLayout>

Kết quả đạt được:


3. Xử lý logic

Đầu tiên chúng ta phải khởi tạo exoplayer

override fun onResume() {
super.onResume()
if (mExoPlayerView == null) {
mExoPlayerView = findViewById(R.id.exo_player) as SimpleExoPlayerView
initFullscreenDialog()
initFullscreenButton()
val streamUrl = "http://qthttp.apple.com.edgesuite.net/1010qwoeiuryfg/sl.m3u8"
val userAgent = Util.getUserAgent(this@Activity, applicationContext.applicationInfo.packageName)
val httpDataSourceFactory = DefaultHttpDataSourceFactory(
userAgent,
null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
true
)
val dataSourceFactory = DefaultDataSourceFactory(this@Activity, null, httpDataSourceFactory)
val daUri = Uri.parse(streamUrl)
mVideoSource = HlsMediaSource(daUri, dataSourceFactory, 1, null, null)
}
initExoPlayer()
if (mExoPlayerFullscreen) {
(exo_player.parent as ViewGroup).removeView(exo_player)
mFullScreenDialog.addContentView(
exo_player,
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
)
mFullScreenDialog.show()
}
}

Sau đó xử lý logic thu phóng màn hình

 private fun openFullscreenDialog() {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
        (exo_player.parent as ViewGroup).removeView(exo_player)
        mFullScreenDialog.addContentView(
            exo_player,
            ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
        )
        mExoPlayerFullscreen = true
        mFullScreenDialog.show()
    }
    private fun closeFullscreenDialog() {
        requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        (mExoPlayerView?.parent as ViewGroup).removeView(mExoPlayerView)
        main_media_frame.addView(mExoPlayerView)
        mExoPlayerFullscreen = false
        mFullScreenDialog.dismiss()
        exo_fullscreen_icon.setImageDrawable(
            ContextCompat.getDrawable(
                this@Activity,
                R.drawable.ic_fullscreen_expand
            )
        )
    }

Cuối cùng là xử lý khi màn hình pauser hoặc stop

override fun onPause() {
        super.onPause()
        if (exo_player != null && exo_player.player != null) {
            mResumeWindow = exo_player.player.currentWindowIndex
            mResumePosition = Math.max(0, exo_player.player.contentPosition)
            exo_player.player.release()
        }
            mFullScreenDialog.dismiss()
    }

Có một lưu ý nhở Để ứng dụng của bạn có thể chạy mượt mà và lưu lại được state khi đang sử dụng mà không bị load lại dữ liệu khi xoay màn hình bạn nên thêm dòng code này vào Manifest android:configChanges="orientation|screenSize|layoutDirection"

Trên đây chỉ là một số hướng dẫn cơ bản về Exoplayer ủa mình, ngoài ra nó còn rất nhiều điều thú vị nữa mà trong bài viết này mình không thể đưa ra hết được

App demo

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *