HLS 란?

HEETAE HEO·2023년 4월 8일
0
post-thumbnail

HLS란?

HLS(HTTP Live Streaming)은 가장 널리 사용되는 비디오 스트리밍 프로토콜입니다. 이 프로토콜은 동영상을 여러 개의 작은 세그먼트로 분할하고, 이러한 세그먼트를 HTTP 기반의 웹 서버를 통해 전송합니다. 클라이언트는 이 세그먼트를 다운로드하여 연속적으로 재생함으로써 스트리밍 영상을 시청할 수 있습니다.

HLS의 주요 특징

  1. 적응형 스트리밍(Adaptive Streaming) : HLS는 네트워크 상태에 따라 동적으로 비트레이트를 변경하여 최적의 영상 품질을 제공합니다. 서버는 다양한 해상도와 비트레이트의 동여상 세그먼트를 저장하고, 클라이언트는 현재의 네트워크 상태에 적합한 세그먼트를 선택하여 재생합니다.

  2. 라이브 스트리밍 및 VOD 지원 : HLS는 라이브 스트리밍과 비디온 온-디맨드 모두를 지원합니다. 라이브 스트리밍의 경우, 실시간으로 생성되는 세그먼트를 클라이언트에 전송하며, VOD의 경우 이미 저장된 세그먼트를 전송합니다.

  3. 널리 지원되는 형식 : HLS는 Ios, Android, macOs, Windows 등 다양한 플랫폼에서 지원됩니다. 또한 대부분의 웹 브라우저에서도 지원되며, HTML5 Video 태그를 사용하여 플레이할 수 있습니다.

  4. DRM(Digital Rights Management)지원 : HLS는 FairPlay Streaming, Widevine, PlayReady 등 다양한 DRM 기술을 통해 콘텐츠의 저작권 보호를 지원합니다.

HLS 스트리밍을 구현하기 위해서는 서버와 클라이언트 모두 해당 프로토콜을 지원해야하 합니다. 서버에서는 동영상을 세그먼트로 분할하고, M3U8 플레이리스트 파일을 생성하여 클라이언트에 전달해야 하며, 클라이언트에서는 이를 해석하여 영상을 재생해야합니다.

간단 HLS 스트리밍 구현

  • 먼저 프로젝트의 build.gradle(Module)에서 Exoplayer 라이브러리를 추가해야합니다.
dependencies {
	implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
}
  • Hilt 모듈에서 Exoplayer 인스턴스 제공하는 메서드 정의
@Module
@InstallIn(SingletonComponent:class)
object AppModule{

	@Provides
    fun provideExoPlayer(@ApplicationContext context: Context): SimpleExoPlayer {
    return SimpleExoPlayer.Builder(context).build()
    }
  • ViewModel을 생성하고 Hilt로 주입된 ExoPlayer 인스턴스를 사용합니다.
@HiltViewModel
class MainViewModel @Inject construtor(
	application: Application,
    private val expPlayer: SimpleExoPlayer
): AndroidViewModel(application) {

	private val userAgent = Uilt.getUserAgent(application, application.packageName)
    private val dataSourceFactory = DefaultHttpDataSourceFactory(userAgent)
    
    fun preparePlayer(streamUrl: String){
    
  	    val hlsMediaSource = buildHlsMediaSource(streamUrl)
    	exoPlayer.setMediaSource(hlsMediaSource)
    	exoPlayer.prepare()
    }
      private fun buildHlsMediaSource(streamUrl: String): MediaSource {
        val uri = Uri.parse(streamUrl)
        return HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri)
    }

    override fun onCleared() {
        super.onCleared()
        exoPlayer.release()
    }
}

사용 변수 설명

userAgent : Util.getUserAgent(application, application.packageName)를 사용하여 userAgent를 생성하는 이유는 Exoplayer가 서버와 통신할 때 사용할 HTTP 헤더에 User-Agent 값을 설정하기 위함입니다.

dataSourceFactory: DefaultHttpDataSourceFactory(userAgent)를 사용하여 dataSourceFactory 인스턴스를 생성하는 이유는, 이를 통해 ExoPlayer가 미디어 데이터를 로드하는 DataSource를 설정하기 위함입니다. DefaultHttpDataSourceFactory는 HTTP를 통해 미디어 데이터를 로드할 수 있는 DataSource를 생성하는 팩토리 클래스입니다. 생성된 DataSource는 ExoPlayer에 의해 사용되어 미디어 데이터를 로드하고 재생할 수 있게 합니다. 위에서 생성한 userAgent를 DefaultHttpDataSourceFactory의 인자로 전달함으로써, 서버와 통신할 때 User-Agent 헤더를 포함할 수 있습니다.

  • Activity에서 viewModel을 주입받고 스트리밍을 준비합니다.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.viewModels
import com.google.android.exoplayer2.ui.PlayerView
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val viewModel: PlayerViewModel by viewModels()
    private lateinit var playerView: PlayerView
    private lateinit var binding : ActivityMainBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.playerView.player = viewModel.exoPlayer

        val streamUrl = "https://example.com/hls_stream.m3u8"
        viewModel.preparePlayer(streamUrl)
    }

    override fun onStart() {
        super.onStart()
        viewModel.exoPlayer.playWhenReady = true
    }

    override fun onStop() {
        super.onStop()
        viewModel.exoPlayer.playWhenReady = false
    }
}

처럼 작성하여 간단하게 스트리밍 환경을 구현할 수 있습니다. 현재 영상 관련 처리 기술에 관심이 생기기 시작했기에 네트워크 환경 및 해당 실시간 영상처리에 관한 글을 꾸준히 작성할 것 같습니다!!! 읽어주셔서 감사합니다.

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글