정상에서 IT를 외치다

[Android, ExoPlayer2] ExoPlayer2 개념 및 사용방법 본문

안드로이드

[Android, ExoPlayer2] ExoPlayer2 개념 및 사용방법

Black-Jin 2019. 3. 25. 11:59
반응형

안녕하세요. 블랙진입니다.


RecyclerView 에서 비디오를 재생하라는 미션이 주어져 어떻게 하면 이를 효율적으로 보여줄수 있을까 고민하다 ExoPlayer 를 알게 되었습니다. 이에 ExoPlayer 를 선택한 이유와 간단한 사용법에 대해 포스팅 해보겠습니다.


ExoPlayer?



구글에서 만든 오픈 소스 미디어 플레이 라이브러리 입니다. 기존에 오디오와 비디오 재생은 MediaPlayer를 사용했었지만 ExoPlayer가 나온 이후에는 MediaPlayer 보다 더욱 작고 유연하며 안정적이므로 많은 개발자들이 사용하는 오픈 소스 라이브러리가 되었습니다. 물론 우리가 즐겨보는 유튜브와 구글 무비도 ExoPlayer 를 사용해서 만들었습니다.



사용 조건은?


안드로이드 4.1 (젤리빈) 이상에서 사용가능합니다.

링크



1. 라이브러리 추가하기


root 프로젝트의 build gradle에 아래 코드를 추가해 줍니다.

- google 과 jcenter 에서 라이브러리를 가져올 수 있게 해줍니다.


repositories {
google()
jcenter()

}


app 프로젝트의 build gradle에 아래 코드를 추가해줍니다.

- ExoPlayer 는 자바8을 사용하기 때문에 이를 사용할 수 있게 해주는 라이브러리를 추가해 줍니다.


android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}


Core 와 Ui 를 추가해 줍니다. 최신버전은 ReleaseNote 에서 확인하세요.


def exoplayer_version = '2.9.3'
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"


cf) 저는 m3u8 파일을 사용할 예정이기 때문에 HLS(Http Live Streaming) 를 사용할 수 있는 라이브러리를 추가해 주었습니다. 


implementation "com.google.android.exoplayer:exoplayer-hls:$exoplayer_version"


이렇게 exoplayer 의 사용 목적에 따라 필요한 라이브러리만 추가해 주어야 합니다. 이를 구분해 주지 않으면 어마무시하게 많은 확장함수들을 다운로드 받기 때문에 앱의 성능을 떨어뜨릴 수 있습니다. 아래는 github 문서에서 있는 5가지 라이브러리에 대한 설명입니다.



위 라이브러리 외에도 다양한 확장 기능이 있습니다. 이는 ExoPlayer/extensions 에서 확인해주세요.



2. ExoPlayer 사용하기


코드랩을 따라하며 제 입맛대로 조금 수정했습니다. 구글의 코드랩을 따라해보고 싶으신 분은 링크를 참고해 주세요.


activity.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/exoPlayerView"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

300 x 300 크기의 PlayerView 를 중앙에 배치했습니다.



MainActivity.class


변수 선언 및 초기화

private PlayerView exoPlayerView;
private SimpleExoPlayer player;

private Boolean playWhenReady = true;
private int currentWindow = 0;
private Long playbackPosition = 0L;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

exoPlayerView = findViewById(R.id.exoPlayerView);

}


비디오플레이어 초기화

private void initializePlayer() {
if (player == null) {

player = ExoPlayerFactory.newSimpleInstance(this.getApplicationContext());

//플레이어 연결
exoPlayerView.setPlayer(player);

}

String sample = "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";

MediaSource mediaSource = buildMediaSource(Uri.parse(sample));

//prepare
player.prepare(mediaSource, true, false);

//start,stop
player.setPlayWhenReady(playWhenReady);
}

ExoplayerFactory 는 context 하나로 초기화 해줄 수 있지만 아래 코드와 같이 필요에 따라 파라미터를 추가해 줄 수 있습니다. 각 파라미터의 기능 및 역활은 ExoPlayer Class Reference 를 참고해 주세요.


DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this.getApplicationContext());
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
DefaultLoadControl loadControl = new DefaultLoadControl();

player = ExoPlayerFactory.newSimpleInstance(
this.getApplicationContext(),
renderersFactory,
trackSelector,
loadControl);


미디어 소스 초기화

private MediaSource buildMediaSource(Uri uri) {

String userAgent = Util.getUserAgent(this, "blackJin");

return new ExtractorMediaSource.Factory(new DefaultHttpDataSourceFactory(userAgent))
.createMediaSource(uri);
}

위 HttpDataSource 는 인터넷상에 있는 mp3, mp4 파일 재생을 도와줍니다. 저는 m3u8 을 추가로 사용해야 되기 때문에 아래와 같이 코드를 분리했습니다.


private MediaSource buildMediaSource(Uri uri) {

String userAgent = Util.getUserAgent(this, "blackJin");

if (uri.getLastPathSegment().contains("mp3") || uri.getLastPathSegment().contains("mp4")) {

return new ExtractorMediaSource.Factory(new DefaultHttpDataSourceFactory(userAgent))
.createMediaSource(uri);

} else if (uri.getLastPathSegment().contains("m3u8")) {

//com.google.android.exoplayer:exoplayer-hls 확장 라이브러리를 빌드 해야 합니다.
return new HlsMediaSource.Factory(new DefaultHttpDataSourceFactory(userAgent))
.createMediaSource(uri);

} else {

return new ExtractorMediaSource.Factory(new DefaultDataSourceFactory(this, userAgent))
.createMediaSource(uri);
}

}



비디오 플레이어 해제

private void releasePlayer() {
if (player != null) {
playbackPosition = player.getCurrentPosition();
currentWindow = player.getCurrentWindowIndex();
playWhenReady = player.getPlayWhenReady();

exoPlayerView.setPlayer(null);
player.release();
player = null;

}
}


비디오 플레이어 초기화와 해제는 항상 맞물러 있어야 합니다. (onCreate - onDestory) , (onStart - onStop) , (onResume - onPause) 이렇게 해주시면 됩니다. 아래는 위 예제의 전체 코드 입니다.




플레이어 변화 감지하기


player.addListener(new Player.EventListener() {

/**
* @param playWhenReady - Whether playback will proceed when ready.
* @param playbackState - One of the STATE constants.
*/
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

switch (playbackState) {

case Player.STATE_IDLE: // 1
//재생 실패
break;
case Player.STATE_BUFFERING: // 2
// 재생 준비
break;
case Player.STATE_READY: // 3
// 재생 준비 완료
break;
case Player.STATE_ENDED: // 4
// 재생 마침
break;
default:
break;
}
}
});

추가로 player 에 리스너를 추가하여 사용할 수 있습니다. 각 playbackState 의 값과 역활은 아래와 같습니다.


/**
* The player does not have any media to play.
*/
int STATE_IDLE = 1;
/**
* The player is not able to immediately play from its current position. This state typically
* occurs when more data needs to be loaded.
*/
int STATE_BUFFERING = 2;
/**
* The player is able to immediately play from its current position. The player will be playing if
* {@link #getPlayWhenReady()} is true, and paused otherwise.
*/
int STATE_READY = 3;
/**
* The player has finished playing the media.
*/
int STATE_ENDED = 4;



정리


RecyclerView 에 비디오 뷰를 추가해야 되는 미션이 주어져 어떻게 하면 좋을지 고민하다가 다음 같은 특징으로 ExoPlayer 를 선택하게 되었습니다. 


1. 젤리빈(APi 16~18) 이상에서 동작 되기 때문에 거의 모든 기기에서 호환이 됩니다.

2. MediaPlayer 보다 안정적이고 유연합니다. (커스텀 하기 좋습니다)


아래는 제가 참고한 링크들 입니다. 긴글 읽어 주셔서 감사합니다.


<참고자료>

ExoPlayer Code Lap

ExoPlayer Google/github

ExoPlayer Developer guide


Meduim-Playing Video by ExoPlayer (2017 Google I/O)


ExoPlayer in RecyclerView

반응형
Comments