스트리밍
https://developer.android.com/codelabs/exoplayer-intro#0
Exoplayer란?
안드로이드에서 영상 재생을 위해 사용하는 플레이어로 기본 내장 라이브러리인 MediaPlayer가 있었는데
스트리밍 서비스가 주류를 이루면서 구글에서 DASH와 SmoothStreaming을 지원하는
ExoPlayer라이브러리를 도입했다.
1. Components
ExoPlayer: ExoPlayer의 라이브러리중 Renderer, 즉 화면에 뿌려주는 역할을 하는 컴포넌트다.
ExoPlayer 인터페이스로 커스텀하게 만들 수 있으며 SimpleExoPlayer는 ExoPlayer에서
제공하는 컴포넌트다.
val simpleExoplayer = ExoPlayerFactory.newSimpleInstance(requireContext(), trackSelector)
trackSelector: SimpleExoPlayer생성 과정에서 두번째 인자로 전달된 클래스는 영상의 Track 정보를
세팅하는 역할을 한다. 이 정보라면 예를 들면 선호하는 오디오 언어는 어떤 것인지,
비디오 사이즈는 무엇인지, 비디오 bitrate는 어떤 것으로 할지 등등 이런 것들을 말한다.
아래 코드는 TrackSelector를 만들 때 AdaptiveTrackSelection팩토리를 사용한 예시다.
AdaptiveTrackSelection팩토리 클래스는 현재 bandwidth 정보를 이용해 현재 선택된 track에서
최상의 퀄리티를 제공하는 역할을 한다고 한다.
Streaming서비스를 한다면 이쪽 클래스를 주요하게 보게 될 것 같다.
val bandwidthMeter = DefaultBandwidthMeter()
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(bandwidthMeter)
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
MediaSource: 영상에 출력할 미디어 정보를 가져오는 클래스다.
ExtractorFactory클래스를 통해 만드는데 이 클래스는 DataSource클래스를 주입해서 만든다.
여기서 사용한 DefaultDataSource도 다른 라이브러리처럼 ExoPlayer에서 uri형태로된 데이터를 읽어오기 위해
기본적으로 제공하는 라이브러리다.
val extractorFactory = ExtractorMediaSource.Factory(DefaultDataSourceFactory(context, Util.getUserAgent(context, context!!.applicationInfo.packageName)))
val mediaSource = extractorFactory.createMediaSource(Uri.parse(mediaPath))
Player: 영상 재생을 위해선 미디어를 읽어오는 작업뿐만 아니라 영상을 UI상에 뿌려줄 수 있는 뷰어가 필요한데
ExoPlayer용 뷰어가 따로있다.
아래 코드를 XML에 넣으면 된다. 재생바, 앞으로 당기기 같은 기본적인 UI기능도 지원한다.
<com.google.android.exoplayer2.ui.PlayerView
2. Play Video
컴포넌트들을 하나의 코드로 조합하면 재생이 가능하다.
코드의 순서는 설명한 순서와 조금 다른데 이는 클래스 생성후에 주입하기 위함이다.
exoPlayer.prepare(mediaSource)는 영상 정보를 가져오는 작업이고
fr_main_player.player.playWhenReady는 준비되면 영상을 시작하는 함수다.
val mediaPath = "http://"
val bandwidthMeter = DefaultBandwidthMeter()
val videoTrackSelectionFactory = AdaptiveTrackSelection.Factory(bandwidthMeter)
val trackSelector = DefaultTrackSelector(videoTrackSelectionFactory)
val exoPlayer = ExoPlayerFactory.newSimpleInstance(requireContext(), trackSelector)
val extractorFactory = ExtractyorMediaSource.Factory(
DefaultDataSourceFactory(
context,
Util.getUserAgent(context, context!!.appliactionInfo.packageName)
)
)
val mediaSource = extractorFactory.createMediaSource(Uri.parse(mediaPath))
fr_main_player.player = exoPlayer
exoPlayer.prepare(mediaSource)
fr_main_player.player.playWhenReady = true
3.Extension
Player.Listener: 영상 재생중 로딩에 실패하거나 Track속성이 바뀌거나 혹은 영상 재생이 완료된 경우에
대해서 리스너를 등록해줄 수 있는데 이 경우들은 뷰어에 리스너를 등록해서 구현이 가능하다.
아래 코드를 통해 어떤 경우에 대해서 콜백 호출이 가능한지 확인 해볼 수 있다.
fr_main_player.player.addListener(object: Player.EventListener{
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {}
override fun onPlayerError(error: ExoPlaybackException?) {}
override fun onLoadingChanged(isLoading: Boolean) {}
override fun onPositionDiscontinuity(reason: Int) {}
override fun onRepeatModeChanged(repeatMode: Int) {}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
if (playbackState == Player.STATE_ENDED) {
fr_main_player.player.seekTo(0)
fr_main_player.player.playWhenReady = true
}
}
})
CacheDataSource: 인터넷으로 영상을 받는 경우 여러번 재생을 할 때 마다 동일한 데이터를 계속 인터넷으로
불러오게돼 데이터 낭비할 수도 있는 문제가 있다.
ExoPlayer에서는 이 문제점을 해결하고자 별도의 미디어 데이터 저장 공간으로 Cache를 뒀다.
ExtractorMediaSource.Factory 함수에서 호출 할 수 있도록 임의의 클래스를 DataSource.Factory의
인터페이스를 구현한 형태로 만든다. 리턴 값으로는 CacheDataSource가 되는데 여기서 생성자에서 캐시가
가져야할 정보를 입력하게 된다.
exoplayer RTMP
https://karthikponnam.medium.com/rtmp-player-android-using-exo-media-player-ac7a012b7a25
참조 :
https://selfish-developer.com/entry/Exoplayer2-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
'안드로이드' 카테고리의 다른 글
Android Q 파일 삭제 ScopeStorage 삽질 (2) | 2024.03.20 |
---|---|
[Android] FCM을 사용해서 메시지를 보내는 과정 (FCM 추가) (0) | 2024.03.19 |
[Android] WorkManager (0) | 2024.03.18 |
푸시 알림 처리를 위한 PendingIntent 및 onNewIntent 사용하기 (0) | 2024.03.14 |
startActivityForResult 및 ActivityResultLauncher에 대한 명확한 이해 (0) | 2024.03.14 |