안녕하세요? 닉네임간편입니다. 이번 시간에는 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
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
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
4) use_controller
비디오를 재생하면 재생 버튼 등이 있는 컨트롤러가 있습니다.
이를 사용할지 설정하는 속성입니다. true로 설정하면 컨트롤러를 사용할 수 있습니다.
속성에 대한 자세한 사항은 아래 사이트에서 참조할 수 있습니다.
https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/ui/PlayerView.html
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는 구글 무비나 유튜브 앱에 사용될 정도로 널리 사용되고 있는데요, 그만큼 유용하고 중요한 라이브러리입니다. 따라서 이번 시간에 잘 정리되었으면 좋겠습니다.
'Android > 꼭 공부해야 할 라이브러리' 카테고리의 다른 글
Koin을 통해 의존성 주입하기 (0) | 2021.12.18 |
---|---|
Glide 를 사용해서 이미지 설정하기 (0) | 2021.10.13 |
예제로 알아보는 DiffUtil - RecyclerView 성능을 향상하자! (0) | 2021.10.03 |
Room 을 사용해 데이터를 관리하자! with 사용법과 예제 (0) | 2021.10.02 |
[웹에서 데이터 가져오기] 3. GSON (0) | 2021.09.29 |