Android (안드로이드)

[Android] ExoPlayer - RTSP 스트리밍 연결

Oscar:) 2024. 11. 28. 09:00
728x90

 

 

 

안드로이드 Jetpack의 Media3에 포함된

ExoPlayer를 사용하여 RTSP 스트리밍을 진행해본다.

 

 

공식 문서 ↓

 

RTSP  |  Android media  |  Android Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. RTSP 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. ExoPlayer는 실시간 RTSP와 주문형 RTSP를 모두 지원합

developer.android.com

 

 

 

연결할 네트워크 스트림 주소는 다음과 같다.

rtsp://210.99.70.120:1935/live/cctv048.stream

 

공공 데이터 포털에서 제공해주는 교통정보 CCTV 스트림 주소다.

 

 

 

 


 

 

✅ Manifest 권한 추가

 

AndroidManifest.xml

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

 

네트워크 스트리밍을 진행할 것이기에 인터넷 권한을 추가해주자.

 

 

 

 

 

✅ 의존성 설정

 

build.gradle.kts (Module:app)

implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-ui:1.4.1")
implementation("androidx.media3:media3-exoplayer-rtsp:1.4.1")

 

안드로이드 공식 동영상 플레이어라지만, 의존성을 추가해줘야 한다.

 

ExoPlayer는 기본적으로 추가해주고, UI도 추가해줘야 한다.

ExoPlayer가 Media3에 통합되면서 Media3-UI를 별개로 구분하는 듯한 느낌이다.

또한 ExoPlayer로 RTSP 통신을 구현하려면, RTSP 의존성을 별도로 추가해줘야 한다.

 

 

 

 

 

✅ 레이아웃 설정

 

activity_main.xml

    <androidx.media3.ui.PlayerView
        android:id="@+id/playerview"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:use_controller="false"
        app:show_buffering="never"
        />

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:indeterminateTint="@color/white"
        />

 

ExoPlayer를 이용하기 위해서는 Media3PlayerView를 사용해야 한다.

 

설정한 속성 2개를 간단히 설명하자면

 

- use_controller="false"

동영상 컨트롤러를 표시하지 않는 설정이다.

어차피 '실시간' 스트리밍이기 때문에, 재생 · 정지 등의 버튼이 불필요하다.

필요한 사람은 사용해도 무방하다.

 

- show_buffering="never"

버퍼링 중 프로그래스바를 표시하지 않는 설정이다.

PlayerView에 적용된 기본 프로그래스바는 회색인데, 눈에 잘 띄지 않아서 과감히 버린다.

 

대신, 위 처럼 별도의 프로그래스바를 직접 만들어주면 된다.

 

 

 

 

 

✅ RTSP 스트리밍

 

스트리밍에 필요한 코드는 다음과 같다.

private fun exoPlayerInit() {

    // 네트워크 스트림 주소를 Uri 형식으로 초기화
    val uri = "rtsp://210.99.70.120:1935/live/cctv048.stream".toUri()
    
    // ExoPlayer 초기화
    val player = ExoPlayer.Builder(this).build()
    
    // 레이아웃에 선언한 PlayerView에 ExoPlayer 초기화
    bind.playerview.player = player
    
    // ExoPlayer에 Uri를 포함한 MediaItem 세팅
    player.setMediaItem(MediaItem.fromUri(uri))
    
    // ExoPlayer 준비
    player.prepare()
    
    // ExoPlayer 준비 완료되면 자동으로 재생
    player.playWhenReady = true
    
    // ExoPlayer에 장착하는 콜백 리스너들
    player.addListener(object: Player.Listener {
    
        // 재생 상태 변경 시 호출
    	override fun onIsPlayingChanged(isPlaying: Boolean) {
            super.onIsPlayingChanged(isPlaying)
            
            // 재생 상태에 따라 프로그래스바 가시성 변경
            bind.progressbar.visibility = if (isPlaying) View.GONE else View.VISIBLE
        }
        
        // 에러 발생 시 호출
        override fun onPlayerError(error: PlaybackException) {
            super.onPlayerError(error)
            // 예외처리 코드 작성
        }
    })
}

 

코드 한 줄마다 주석을 작성했으니 확인하기 바란다.

 

참고로, ExoPlayer에 장착하는 콜백 리스너의 종류는 정말 많다.

예시로 2개만 장착했을 뿐이다.

 

 

상황에 맞게 원하는 콜백 리스너를 사용해주면 될 것 같다.

 

 

 

 

 

주석을 제외한 메인 액티비티의 전체 코드는 다음과 같다.

 

MainActivity.kt

private lateinit var bind: ActivityMainBinding

override fun onCreate() {
    ...
    bind = ActivityMainBinding.inflate(layoutInflater)
    setContentView(bind.root)
    
    exoPlayerInit()
}

private fun exoPlayerInit() {
    val uri = "rtsp://210.99.70.120:1935/live/cctv048.stream".toUri()
    val player = ExoPlayer.Builder(this).build()
    bind.playerview.player = player
    
    player.setMediaItem(MediaItem.fromUri(uri))
    
    player.prepare()
    player.playWhenReady = true
    
    player.addListener(object: Player.Listener {
    	override fun onIsPlayingChanged(isPlaying: Boolean) {
            super.onIsPlayingChanged(isPlaying)
            bind.progressbar.visibility = if (isPlaying) View.GONE else View.VISIBLE
        }
        
        override fun onPlayerError(error: PlaybackException) {
            super.onPlayerError(error)
            // 예외처리
        }
    })
}

 

 

 

 

 

✅ 결과

 

● 스트리밍 연결 중

 

onIsPlayingChanged 콜백이 true로 도착할 때까지

검정 배경화면에 프로그래스바가 표시된다.

 

 

 

 

● 스트리밍 연결 성공 후

 

프로그래스바가 사라지며 영상이 출력되는 모습이다.

 

 

 

 

 

✅ RTSP 스트리밍 로그 확인하기

 

번외로, ExoPlayer에 MediaItem을 직접 세팅하지 않고

MediaSource를 세팅하면 더 많은 맞춤 옵션을 설정할 수 있다.

// player.setMediaItem(MediaItem.fromUri(uri))

val mediaItem = MediaItem.fromUri(uri)
val mediaSource = RtspMediaSource.Factory().setDebugLoggingEnabled(true).createMediaSource(mediaItem)
player.setMediaSource(mediaSource)

 

위 처럼 MediaSource를 사용하여 디버그로깅 설정을 해주면

다음과 같이 RTSP 통신이 이루어지는 과정을 로그로 확인할 수 있다.

 

 

지난 포스팅에서 공부했었던 RTSP 명령어대로

클라이언트와 서버간 요청과 응답이 이루어지고 있는 것을 확인할 수 있다.

 

 

 

 

 


 

 

 

 

ExoPlayer 사용하면서 느껴진 건, 확실히 공식 라이브러리라서 그런지

사용성이 정말 편리했고 다양한 기능을 제공받을 수 있어서 좋았다.

 

 

 

 

728x90