본문 바로가기
Main

[Android] 스트리밍 서비스 개발 기록

by ca.rrot 2022. 10. 14.

2019년 9월부터 7개월간 진행했던 라이브 커머스 프로젝트 '라브' 개발에 대해 기록한 글입니다 :)

목차.

1. 스트리밍 서비스를 개발하게 된 계기

2. 라이브 스트리밍 구조 설계

3. [Android] 라이브 스트리밍 연동하기

4. [Android] 스크롤 되는 영상 뷰 만들기

 

 

스트리밍 서비스를 개발하게 된 계기

동대문에서 옷 촬영중인 왕홍

 

 

중국 타오바오 라이브 커머스가 대박 나고 우리나라 동대문에도 라이브 방송을 하는 중국 왕홍(인플루언서)들이 붐비던 2019년,

한국형 라이브 커머스를 개발해 보자!! 마음먹고 4명의 개발자가 뭉치게 되었습니다..!

 

 

라이브 스트리밍 구조 설계

라이브 스트리밍 구조 설계

[영상 송신 구조] - 클라이언트에서 영상을 H.264/AAC 포맷으로 인코딩 한 후 RTMP를 통해 서버에 전송합니다.

[영상 수신 구조] - 서버에서 HLS를 통해 m3u8 포맷의 재생 목록과 ts 데이터들을 받은 후 디코딩 하여 클라이언트에 영상을 송출합니다.

 

* RTMP(Real-Time Messaging Protocol)

RTMP는 어도비(Adobe) 독점 프로토콜로 전용 스트리밍 서버와 Adobe Flash Player 간의 오디오, 비디오 및 기타 데이터 전송을 위해 설계된 스트리밍 프로토콜입니다. Flash plugin이 전성기 시절에는 인터넷 브라우저의 98%를 차지하였기에 RTMP는 어디서나 사용되었고, 스트리밍 초기에 RTMP는 비디오 전송을 위한 사실상의 표준이었습니다.

RTMP는 지속적이고 대기 시간이 짧은 연결을 유지하고 원활한 스트리밍 경험을 유지하도록 설계된 TCP 기반 프로토콜입니다. 기본 1935번 포트를 사용하며 통신 실패 시 443 포트(RTMPS)나 80 포트(RTMPT)로 재시도합니다.

 

- Audio Codecs : AAC, AAC-LC, HE-AAC+ v1 & v2, MP3, Speex

- Video Codecs : H.264, VP8, VP6, Sorenson Spark®, Screen Video v1 & v2

- 재생 호환성 : 보편적이지 않음 (Flash 기술 단종)

- 장점 : 짧은 대기 시간 (5초) 및 최소 버퍼링

- 단점 : 업데이트 및 지원 중단 (2020.12.31)

 

* HLS(HTTP Live Streaming)

HLS는 확장성 및 적응형 비트 전송률 스트리밍을 위해 Apple이 개발한 표준 HTTP 기반 통신 프로토콜입니다. 오늘날 가장 널리 사용되는 프로토콜입니다. 스트리밍 데이터를 m3u8의 확장자를 가진 재생목록 파일과 잘게 쪼개놓은 다수의 ts 파일(동영상)을 HTTP를 통해 전송하는 방식을 사용합니다.

HLS의 장점 중 하나는 모든 인터넷 연결 장치가 HTTP를 지원하기 때문에 전용 서버가 필요한 스트리밍 프로토콜보다 간단하게 실행할 수 있다는 것입니다. 또 다른 장점은 HLS 스트리밍은 재생에 지장을 주지 않고 네트워크 상태에 따라 비디오 품질을 높이거나 낮출 수 있다는 것입니다. 이 기능은 '적응 비트 전송률 스트리밍'이라 알려져 있으며 이 기능이 없으면 네트워크가 느려진 경우 비디오 재생이 완전히 멈출 수 있습니다.

 

- Audio Codecs : AAC-LC, HE-AAC+ v1 및 v2, xHE-AAC, Apple Lossless, FLAC

- Video Codecs : H.265, H.264

- 재생 호환성 : 우수(모든 Google Chrome 브라우저, Android, Linux, Microsoft 및 MacOS 기기, 여러 셋톱 박스, 스마트 TV 및 기타 플레이어)

- 장점 : 적응형 비트 전송률, 안정적이고 널리 지원됨

- 단점 : 낮은 지연 시간보다 경험 품질이 우선

=> 단점 개선 : HLS는 전통적으로 6-30초의 대기시간을 제공했지만 2020년 5월 '저지연 HLS'을 HLS 표준에 통합하면서 지연시간 2초 미만의 스트리밍을 제공합니다.

 

* RTMP와 HLS 프로토콜을 모두 사용했을 때 이점

카메라 화면에서 최종 사용자 장치로의 이동 속도를 높이는 동시에 시청 경험을 최적화하기 위해 수집 및 전달에 다른 프로토콜이 사용되는 경우가 많습니다. RTMP는 효율적인 비디오 송신에는 적합하지만 수신 쪽에서는 더 이상 의미가 없습니다. 반대로, 최종 마일 전송에는 HLS를 적극 권장하지만 송신 형식으로는 적합하지 않습니다. RTMP와 HLS의 조합을 사용하면 대기 시간을 너무 높이지 않고도 호환성을 극대화할 수 있습니다. 그림과 같은 아키텍처를 통해  라이브 비디오 전달 체인의 양쪽 끝에서 잘 지원되는 프로토콜을 사용할 수 있습니다.

 

추가 개념 정리)

인코딩과 디코딩

인코딩 - 부호화라고 하며, 원본을 알고리즘에 따라 압축하는 것입니다.

디코딩 - 복호화라고 하며, 데이터를 읽기 위해 압축한 것을 다시 해제하는 것입니다.

 

코덱(Codec)

Coder와 Decoder의 합성어입니다. 

코덱이란 데이터를 부호화하고 복호화 하는 것을 말합니다.

 

H.264/AAC

(H.264 : 비디오 코덱, AAC : 오디오 코덱)

H.264는 가장 많이 사용되는 효율적인 비디오 코덱으로 높은 데이터 압축률을 자랑합니다.

AAC는 디지털 오디오에서 쓰이는 표준적인 손실 데이터 압축방식으로 H.264와 호환됩니다.

 

 

[Android] 라이브 스트리밍 연동하기

영상을 송신하는 부분은 Stream Github Library를 사용하여 구현하였습니다. 

 implementation 'com.github.pedroSG94.rtmp-rtsp-stream-client-java:rtplibrary:X.X.X'

Android Camera2 Api를 이용하여 화면을 촬영하고 GLSurfaceView에 촬영 영상을 렌더링 합니다. 

촬영 데이터는 Android MediaCodec을 이용해 H.264/AAC로 인코딩 후 RTMP 프로토콜로 서버에 전송합니다.

 

영상을 수신하는 부분은 Google ExoPlayer Library를 사용하여 구현하였습니다.

implementation 'com.google.android.exoplayer:exoplayer-core:X.X.X'
implementation 'com.google.android.exoplayer:exoplayer-ui:X.X.X'
implementation 'com.google.android.exoplayer:exoplayer-hls:X.X.X'

HLS 프로토콜을 사용하기 위해 exoplayer-hls를 추가로 implementation 합니다.

HLS를 통해 m3u8 재생목록 파일과 h.264/AAC 형식의 ts 동영상 파일을 앱에 수신하고 미디어 소스 변환 후 ExoPlayerView에 영상을 재생합니다.

 

[결과물]

스트리밍 연동 후 테스트 촬영한 영상입니다.

(왼쪽 - 방송 송출 / 오른쪽 - 방송 수신)

 

[Android] 스크롤 되는 영상 뷰 만들기

사용자가 화면을 아래로 스와이프 했을 때 스트리밍 영상이 스크롤 되고 자동 재생되는 기능을 개발하였습니다.

 

1. 사용자가 화면 위아래로 스와이프 했을 때 중앙 스냅 효과 구현하기

PagerSnapHelper를 이용해 한 아이템씩 화면 중앙에 스냅 되는 효과를 구현했습니다.

PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(mRecyclerView);

 

2.  아이템 변화 시 썸네일 이미지 & 동영상 재생되게 하기

recyclerview를 상속해서 custom video recyclerview를 만들었습니다.

 

비디오를 스크롤 했을 때 재생되기까지의 처리 과정입니다.

1) recyclerview item에 썸네일 이미지 보이기

2) 디바이스 전체 높이에서 아이템이 일정 비율 이상 보이면 VideoSurfaceView 생성

3. VideoSurfaceView에 SimpleExoPlayer 연결 후 비디오 재생 요청 후 progressBar 보이기

4. SimpleExoPlayer의 EventListener에서 비디오 상태를 체크하고 비디오 준비단계가 되면 기존 썸네일, progressBar 숨기기

5. 비디오 재생

 

[결과물]

구현 후 테스트 촬영한 영상입니다.

(비디오 썸네일 이미지, 영상은 테스트용 무료 에셋을 사용하였습니다.)

 

 

 

 

읽어주셔서 감사합니다 :)

댓글