본문 바로가기

Android/꼭 공부해야 할 라이브러리

예제로 알아보는 ExoPlayer

안녕하세요? 닉네임간편입니다. 이번 시간에는 ExoPlayer에 대해서 알아보겠습니다.

1. 개요

오디오 및 동영상 재생에 사용되는 오픈소스 프로젝트이며, 유튜브와 구글 무비 앱 등에서 사용될 정도로 유용하게 쓰입니다.

ExoPlayer는 MediaPlayer에서 지원하지 않는 DASH, SmoothStreaming 및 일반 암호화 같은 기능을 지원하며, 맞춤 설정 및 확장이 용이합니다.

2. 사용법 - 준비

1) 빌드 종속 항목 추가

build.gradle(app) 파일의 dependencies에 아래 코드를 입력합니다.

def exoplayer_version = "2.15.0"
implementation 'com.google.android.exoplayer:exoplayer:$exoplayer_version'

현재 버전과 상이할 수 있으니 아래 사이트에서 최신 버전을 확인하시기 바랍니다.

https://github.com/google/ExoPlayer/blob/release-v2/RELEASENOTES.md

 

GitHub - google/ExoPlayer: An extensible media player for Android

An extensible media player for Android. Contribute to google/ExoPlayer development by creating an account on GitHub.

github.com

exoplayer는 사용 목적에 따라 필요한 라이브러리를 추가할 수 있습니다. 만일 그렇지 않으면 엄청나게 많은 확장 함수를 다운로드하기 때문에, apk 크기가 커지고 앱의 성능이 저하될 수 있습니다.

따라서 개발자가 필요한 라이브러리를 개별적으로 추가할 수도 있습니다.

아래처럼 core와 ui 라이브러리만 추가할 수 있습니다.

implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"

물론 이때 core 라이브러리는 반드시 필요한 라이브러리이므로 항상 추가해줍니다.

2) Java 8

build.gradle(app) 파일에서 아래처럼 Java 8을 지원하도록 설정합니다.

compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}

3) 멀티덱스 사용 설정

앱 및 앱이 참조하는 라이브러리에서 메서드의 개수가 65,536개를 초과하게 되면 빌드 오류가 발생하게 됩니다. 이 오류는 앱이 안드로이드 아키텍처의 제한에 도달했음을 알리는 것이며, 65,536이라는 숫자는 단일 DEX 바이트 코드 파일 내에서 코드가 호출할 수 있는 참조의 총개수를 나타냅니다.

이때 멀티덱스를 사용해 앱이 다중 DEX 파일을 빌드하고 읽을 수 있도록 할 수 있습니다.

자세한 설명 : https://developer.android.com/studio/build/multidex

 

메서드가 64K개를 초과하는 앱에 관해 멀티덱스 사용 설정  |  Android 개발자  |  Android Developers

앱이 여러 DEX 파일을 빌드하고 읽을 수 있도록 하는 multidex라는 앱 구성의 사용설정 방법에 관해 알아보세요.

developer.android.com

API 레벨 21 이상에서는 멀티덱스가 기본적으로 사용되지만, 20 이하에서는 그렇지 않습니다. 따라서 추가적인 조치를 취해야 합니다.

이 경우 멀티덱스 라이브러리를 build.gradle(Module) 파일에 아래 코드를 추가합니다.

dependencies {
    def multidex_version = "2.0.1"
    implementation "androidx.multidex:multidex:$multidex_version"
}

이제 준비는 끝이 났으며, 예제를 통해 사용하는 법에 대해서 알아보겠습니다.

3. 사용법 - PlayerView

PlayerView는 실제 영상 또는 소리를 화면에 표시할 때 사용할 UI 요소입니다. XML 파일에 다음과 같이 선언해줍니다.

<com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/playerView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/black"
    app:controller_layout_id="@layout/custom_exo_view"
    app:auto_show="true"
    app:resize_mode="fixed_width"
    app:surface_type="surface_view"
    app:use_controller="true"/>

playerview는 다양한 속성을 사용해 커스텀할 수 있습니다. 제가 사용한 속성은 다음과 같습니다.

1) auto_show

콘텐츠가 재생되거나 정지할 때, 혹은 끝나거나 재생에 실패할 때 컨트롤러가 자동으로 나오도록 설정하는 속성입니다.

2) resize_mode

재생되는 콘텐츠를 plaerview 크기에 맞게 설정하는 속성입니다.

fit, fixed_width, fixed_height, fill, zoom의 속성으로 설정할 수 있습니다.

fixed_width로 설정하면 playerview의 너비에 맞게 콘텐츠 크기가 리사이즈됩니다.

3) surface_type

비디오 플레이백(playback0에 사용할 surface의 유형을 설정합니다.

surface_view, texture_view, spherical_gl_surface_view, video_decoder_gl_surface_view, 그리고 none이 있습니다.

만일 오디오만 재생을 한다면 none이 권장되는데, 왜냐하면 surface_view 나 texture_view는 비용이 많이 들 수 있기 때문입니다.

만일 일반적인 비디오 재생을 한다면 surface_view가 texture_view보다 재생에 있어 이점이 더 많기 때문에, 저는 surface_view를 사용했습니다.

더 자세한 정보는 아래 주소를 통해 확인하실 수 있습니다.

https://exoplayer.dev/ui-components.html

 

UI components - ExoPlayer

 

exoplayer.dev

4) use_controller

비디오를 재생하면 재생 버튼 등이 있는 컨트롤러가 있습니다.

이를 사용할지 설정하는 속성입니다. true로 설정하면 컨트롤러를 사용할 수 있습니다.

속성에 대한 자세한 사항은 아래 사이트에서 참조할 수 있습니다.

https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/ui/PlayerView.html

 

PlayerView (ExoPlayer library)

Sets whether the currently displayed video frame or media artwork is kept visible when the player is reset. A player reset is defined to mean the player being re-prepared with different media, the player transitioning to unprepared media or an empty list o

exoplayer.dev

5) controller_layout_id

플레이어 뷰에서 사용할 컨트롤러의 레이아웃도 커스텀하여 지정할 수 있습니다. 제가 만든 화면은 다음과 같습니다.

4. 사용법 - ExoPlayer

ExoPlayer 객체를 만들어줍니다. PlayerView에 ExoPlaer 객체를 바인딩해서 화면에 비디오를 표시합니다.

SimpleExoPlayer.Builder를 통해 만들어주는 것이 쉽기 때문에 이를 사용합니다.

SimpleExoPlayer는 ExoPlayer의 인터페이스입니다.

사용 방법은 아래 코드와 같습니다.

simpleExoPlayer = SimpleExoPlayer.Builder(this)
    .build()
    .also{exoPlayer->
playerView.player= exoPlayer
}

build() 메서드를 통해 만들어주고 PlayerView 객체의 player에 exoplayer 객체를 설정합니다.

이때 주의해야 할 점이 있다면, exoplayer 객체 생성은 메모리 해제(release)와 대응되어야 합니다.

즉, onCreate() 에서 생성했다면 onDestroy에서 release 하고, onStart()에서 생성했다면 onStop()에서 release 해야 합니다. onResume() - onPause() 도 마찬가지입니다.

저는 onCreate() 메서드에서 객체를 초기화했으므로 onDestroy() 메서드에서 release했습니다.

5. 사용법 - MediaItem

MediaItem은 콘텐츠를 재생하기 위해서 필요한 가장 작은 요소입니다.

MediaItem에는 다양한 유형이 있으며, 저는 비디오 url을 사용했습니다.

아래 코드처럼 url로부터 MediaItem을 만들 수 있습니다.

그리고 setMediaItem() 메서드를 통해 exoplayer 객체에 MediaItem을 설정하면 이제 화면에 콘텐츠를 재생할 수 있습니다.

val videoUrl = urls.get(movieTitle.text.toString())
val mediaItem = MediaItem.fromUri(Uri.parse(videoUrl))
simpleExoPlayer.setMediaItem(mediaItem)

6. 사용법 - 재생

simpleExoPlayer.prepare()
var position = getSharedIntData("prefPlay", "position${currentTitle}")
simpleExoPlayer.seekTo(position.toLong())
simpleExoPlayer.play()

먼저 prepare() 메서드를 통해 재생 준비를 합니다.

만일 저장된 재생 위치가 있다면 위 코드처럼 가져와도 되고, 그렇지 않다면 바로 play() 메서드를 통해 재생을 시작하면 됩니다. 일반적으론 버튼이나 뷰의 클릭 리스너에 play() 메서드를 넣어서 재생하도록 설정합니다.

7. 사용법 - 생명주기 메서드

생명주기 메서드를 이용해 exoplayer 객체의 상태를 관리합니다.

override fun onResume() {
        super.onResume()
        val position = getSharedIntData("prefPlay", "position${currentTitle}")
        simpleExoPlayer.seekTo(position.toLong())
    }

    override fun onPause() {
        super.onPause()
        simpleExoPlayer.pause()
        simpleExoPlayer.playWhenReady = true
        setSharedData("prefPlay", "position${currentTitle}", simpleExoPlayer.currentPosition.toInt())
    }

    override fun onStop() {
        super.onStop()
        simpleExoPlayer.stop()
        simpleExoPlayer.playWhenReady = false
    }

    override fun onDestroy() {
        super.onDestroy()
        simpleExoPlayer.release()
    }

1) onResume()

화면이 '재개됨' 상태로 진입하면 SharedPreferences에 저장한 재생 위치를 가져와 해당 위치에서 재생할 수 있도록 설정합니다. 물론 재생 위치를 가져올 때는 어떤 방법을 사용하든 상관없습니다.

이때 seekTo() 메서드를 사용하면 됩니다.

2) onPause()

동영상을 일시 정지하고, 이것의 재생 위치를 저장합니다.

그리고 playWhenReady를 true로 설정해 다시 재생될 준비가 된다면 재생하도록 설정합니다.

3) onStop()

exoplayer를 정지하고 playWhenReady를 false로 설정합니다.

4) onDestroy()

exoplayer를 release 합니다.

7. 마무리

이번 시간에는 ExoPlayer 라이브러리에 대해서 알아보았습니다. ExoPlayer는 구글 무비나 유튜브 앱에 사용될 정도로 널리 사용되고 있는데요, 그만큼 유용하고 중요한 라이브러리입니다. 따라서 이번 시간에 잘 정리되었으면 좋겠습니다.

728x90
반응형