올리브영 테크블로그 포스팅 HLS 기반 숏폼 스트리밍 구현기: iOS/Android 호환성 대응 사례
Tech

HLS 기반 숏폼 스트리밍 구현기: iOS/Android 호환성 대응 사례

MP4에서 M3U8로의 전환부터 플랫폼별 렌더링 최적화까지 – 실전 개발 경험 공유

2025.05.29

안녕하세요! 올리브영 리뷰와 커뮤니티 FE개발을 담당하고 있는 뽀야미입니다!

이번 포스팅에서는 커뮤니티 서비스 셔터에 숏폼 콘텐츠를 도입한 전체 과정을 공유드리려고 합니다. 셔터는 올리브영의 SNS 커뮤니티 서비스로, 사용자들이 자유롭게 메이크업에 대한 정보나 사용 후기를 나누는 공간입니다. 개발 초기 단계부터 성능 최적화까지, 프론트엔드 개발자 관점에서 마주한 기술적 도전과 해결책을 담아보았습니다!



숏폼 콘텐츠, 왜 중요할까?


요즘 SNS는 관계 형성보다는 추천 콘텐츠 중심으로 변화하고 있어요. 사용자는 짧은 시간 안에 원하는 정보를 얻고, 더 나은 추천 경험을 기대하죠. 이런 흐름에서 숏폼은 빠른 몰입과 직관적인 정보 전달이 가능해 최적의 콘텐츠 포맷이 됩니다.

셔터에도 숏폼을 통해 뷰티, 상품 정보를 효과적으로 제공하고, 사용자 경험을 확장하면서 브랜드와의 연결을 자연스럽게 만들어갈 수 있도록 개발을 진행했습니다!




숏폼 콘텐츠, 어떻게 만들까?


셔터 내에서 콘텐츠 경험을 더욱 다양화하기 위해 숏폼 콘텐츠 도입을 결정하였습니다. 단순히 영상을 추가하는 것에 그치지 않고, 빠르고 끊김 없는 스트리밍을 통해 최상의 사용자 경험을 제공하기 위해 다양한 기술적 요소들을 검토했습니다.

MP4, DASH, HLS 등 여러 포맷을 비교 분석한 결과, 호환성, 스트리밍 속도, 적응형 비트레이트(ABR) 지원 측면에서 M3U8(HLS) 포맷이 가장 우수하다고 판단했습니다. 특히, iOS에서 네이티브 지원이 가능하고, 다양한 네트워크 환경에서도 안정적인 재생이 가능한 점이 큰 장점이었습니다.

그 결과, 여러 기준에 부합하며 저희가 추구하는 UX에 가장 적합한 형태로 M3U8(HLS) 포맷을 채택하게 되었습니다.

M3U8, 왜 선택했을까?

숏폼 콘텐츠에서 가장 중요한 부분은 빠른 재생과 끊김 없는 시청 경험입니다! 기존 MP4 방식은 파일을 처음부터 끝까지 다운로드해야 재생이 원활하지만 네트워크 상태에 따라 지연이 발생합니다. 이는 사용자 경험을 해칠 수 있는 문제로 부각되었죠. 그래서 M3U8(HLS) 포맷을 선택하게 되었습니다. 그 이유는:

  • 세그먼트 로드: 영상이 작은 조각으로 나뉘어 필요한 부분만 불러와 빠른 재생이 가능합니다.
  • 어댑티브 스트리밍: 네트워크 상태에 따라 화질을 자동 조정해 끊김 없는 재생을 지원합니다.
  • 디스크 캐시: 로드된 세그먼트는 캐시되어 재시청 시 데이터 소모 없이 빠르게 재생됩니다.

이러한 장점 덕분에 MP4보다 훨씬 빠르고 안정적인 스트리밍 환경을 제공할 수 있었어요. 그래서 최종적으로 M3U8 형식을 채택했습니다.



테스트 환경

  • 네트워크: PC 환경에서 네트워크 쓰로틀링 적용 (3G/4G 시뮬레이션)
  • 디바이스: Chrome DevTools 기반 테스트
지표 MP4 M3U8 (HLS) 개선율
초기 재생 시간 2-5초 0.5-1.5초 60-70% 단축
네트워크 및 디바이스 환경에 따른 차이 있음
버퍼링 발생률 높음 (네트워크 변동 시) 낮음 UX 개선
네트워크 적응성 고정 비트레이트 동적 품질 조절 끊김 현상 최소화
메모리 사용량 전체 파일 버퍼링 세그먼트 단위 처리 메모리 최대로 절약 가능
CDN 캐싱 효율성 파일 단위 세그먼트 단위 분산 캐시 히트율 향상


AWS Media Converter를 활용한 MP4 -> M3U8 변환 과정

앞서 설명한 것처럼, 빠르고 안정적인 스트리밍 환경을 위해 M3U8(HLS) 포맷을 도입하게 되었습니다. 하지만 사용자들이 업로드하는 원본 영상은 대부분 MP4 형식이기 때문에, 이를 실시간 스트리밍에 최적화된 M3U8으로 변환하는 과정이 필수적이었습니다. 이를 자동화하고 효율적으로 처리하기 위해 AWS Media Converter를 도입하게 되었고, 전체 흐름은 다음과 같습니다.

  1. 영상 전처리: 네이티브 환경에서 영상의 상태에 따라 압축 및 인코딩을 진행합니다.
  2. 파일 업로드: 5MB 이상 크기의 파일을 분할한 후, Presigned URL을 사용해 S3에 업로드합니다.
  3. HLS 변환 트리거: 업로드 완료 시 Lambda가 트리거되어 AWS Media Converter를 활용한 HLS 변환을 수행합니다.

이렇게 하면 MP4 파일이 M3U8(HLS) 포맷으로 변환되어 스트리밍에 최적화됩니다!

변환이 완료되면 하나의 MP4 파일이 해상도별로 분리된 M3U8 플레이리스트로 생성됩니다. 예를 들어:

eb5b465246a94534b6686a08664dc55f_233647_240p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1318256,AVERAGE-BANDWIDTH=1088734,CODECS="avc1.64001e,mp4a.40.2",RESOLUTION=360x640,FRAME-RATE=30.000
eb5b465246a94534b6686a08664dc55f_233647_360p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2740288,AVERAGE-BANDWIDTH=2226457,CODECS="avc1.64001f,mp4a.40.2",RESOLUTION=480x854,FRAME-RATE=30.000
eb5b465246a94534b6686a08664dc55f_233647_480p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5130896,AVERAGE-BANDWIDTH=4306140,CODECS="avc1.64001f,mp4a.40.2",RESOLUTION=720x1280,FRAME-RATE=30.000
eb5b465246a94534b6686a08664dc55f_233647_720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=8619424,AVERAGE-BANDWIDTH=7202333,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1080x1920,FRAME-RATE=30.000
eb5b465246a94534b6686a08664dc55f_233647_1080p.m3u8

이렇게 생성된 M3U8 플레이리스트는 사용자의 네트워크 환경에 따라 적절한 해상도를 자동 선택하여 끊김 없는 스트리밍 경험을 제공합니다.


[변환 과정 흐름도]



업로드 페이지, 네이티브 vs 하이브리드

업로드 페이지를 구성하기 전에 웹과 네이티브 각각의 방식에 대한 한계와 장점을 고민했습니다.

1. 웹(Web) 기반 구현의 한계

웹 환경에서는 브라우저의 네트워크 자원과 실행 환경만으로 영상 인코딩 및 업로드를 처리해야 하는데, 다음과 같은 한계가 있었습니다.

  • 영상 인코딩 성능 제한:
    • FFmpeg.js 같은 WebAssembly 라이브러리는 CPU 사용률이 높고, 멀티스레딩 지원이 부족해 인코딩 속도가 느림.
    • 모바일 브라우저에서는 배터리 소모가 심하고, 일부 기기에서 인코딩이 원활하지 않음.
  • 대용량 파일 업로드 제한:
    • 네트워크 중단 시 자동 재시도 기능 부족, 업로드 실패 가능성 높음.
    • 백그라운드에서 업로드가 종료될 수 있어 안정적인 업로드 어려움.
    • 브라우저 메모리 제한으로 업로드 도중 중단될 가능성 있음.

2. 네이티브(Native) 전환 고려

웹 기반의 한계를 보완하기 위해, 우리는 영상을 네이티브 앱에서 처리하는 방안을 검토했습니다. 네이티브 환경에는 다음과 같은 장점이 있습니다.

  • 더 빠른 인코딩 성능:
    • iOS VideoToolbox, Android MediaCodec 활용해 GPU 가속 가능 → 빠르고 전력 효율적.
    • 웹은 CPU 연산만 사용 → 속도 느리고 배터리 소모 많음.
  • 안정적인 업로드:
    • 멀티파트 업로드 + 중단 후 재개 지원으로 대용량 파일도 안정적.
    • 백그라운드 업로드 지원으로 앱 종료 후에도 업로드 지속.
    • 네트워크 상태에 따라 속도 조절 가능.

3. 하이브리드(Hybrid) 선택

그러나 한 가지 문제점이 있었습니다. 셔터 커뮤니티의 서비스 특성상 UI 변경 및 A/B 테스트 등을 자주 수행해야 하다 보니, 100% 네이티브로 구현할 경우 배포와 업데이트에 있어 유연성이 떨어지는 아쉬움이 있었어요.

따라서, 네이티브의 강점과 웹의 유연성을 결합한 하이브리드 방식을 선택했습니다.

  • 영상 전처리(압축, 인코딩)는 네이티브에서 수행하여 성능을 확보하고,
  • 업로드 및 UI 관련 요소는 웹에서 처리하여 서비스 운영 및 업데이트를 원활하게 진행할 수 있도록 했습니다.

이렇게 함으로써 성능과 유연성을 모두 고려한 최적의 업로드 경험을 제공할 수 있었습니다.


숏폼 업로드 과정


스트리밍 구현은 HLS.js로

HLS.js 라이브러리는 HLS 기반 스트리밍을 웹에서 쉽게 구현할 수 있도록 도와줍니다. 이 라이브러리의 장점은 이렇습니다.

  1. 네이티브 HLS 미지원 브라우저에서도 재생 가능
    • Chrome, Firefox 등 기본적으로 HLS를 지원하지 않는 브라우저에서도 MSE를 활용해 HLS 스트리밍이 가능합니다.
  2. 세밀한 화질 제어 및 어댑티브 스트리밍 최적화
    • 기본적인 HLS 어댑티브 스트리밍 외에도, 개발자가 화질 전환 로직을 직접 조정할 수 있습니다.
    • 특정 네트워크 조건에서 화질 선택을 미세하게 튜닝 가능.
  3. 실시간 이벤트 핸들링 및 오류 복구 기능
    • 네트워크 끊김, 버퍼링 문제 등을 감지해 자동으로 복구하는 기능을 제공합니다.
    • 특정 오류 발생 시 커스텀 복구 로직을 적용할 수 있습니다.
  4. 디버깅 및 개발 편의성
    • hls.js는 다양한 디버깅 로그를 제공해 문제 해결이 용이합니다.
    • 개발자가 재생 상태를 세밀하게 제어할 수 있도록 다양한 API를 제공합니다.

숏폼 스트리밍 예시



숏폼 콘텐츠, 문제 해결의 여정


숏폼 콘텐츠를 구현하면서 예상했던 문제부터, 예상 못한 다양한 이슈까지 마주했습니다. 그중에서도 특히 고민이 많았던 몇 가지 이슈와 해결 과정을 공유해 보려고 합니다.

iOS에서 스트리밍이 안 된다니!

HLS.js를 사용해 HLS 스트리밍을 구현했지만, iOS 15~16 버전에서 정상적으로 재생되지 않는 문제가 발생했습니다.

처음에는 해당 OS 버전에서도 MSE가 지원된다고 명시되어 있어 예상치 못한 문제였습니다. 하지만, 실제 테스트 결과 일부 iOS 환경에서는 MSE 기반 재생이 원활하게 동작하지 않는다는 사실을 확인했습니다.

원인

iOS의 MSE 지원이 공식적으로 명시되어 있음에도 불구하고, 특정 버전에서 정상적으로 동작하지 않는 이유는 다음과 같습니다.

  1. MSE 지원이 불완전하거나 제한적
    • iOS의 MSE는 기존 데스크톱 브라우저와 완전히 동일하게 구현되지 않았으며, 일부 기능이 제한적이거나 특정 환경에서 예외적으로 동작합니다.
  2. 사파리의 네이티브 HLS 우선 정책
    • iOS 사파리는 자체적으로 HLS를 지원하며, 네이티브 HLS를 기본적으로 사용하려는 경향이 있습니다.

해결: 네이티브 HLS, 고마워!

이 문제를 해결하기 위해 iOS 환경에서는 사파리의 네이티브 HLS를 활용하도록 분기 처리를 추가했습니다.

  • 일반적인 브라우저(Chrome, Firefox 등) → HLS.js를 사용하여 MSE 기반으로 재생
  • iOS 사파리(특정 버전 포함) → 네이티브 HLS를 활용해 직접 재생

이렇게 구현함으로써 iOS에서도 안정적인 HLS 스트리밍을 제공할 수 있었습니다



Android, 색상을 왜 그렇게 뽑아?

Android 기기로 영상 스트리밍 테스트 중, 밝은 영상 일부에 백화(화이트아웃) 현상이 발생했습니다. 영상이 제대로 표현되지 않아 원인을 조사한 결과, 다음과 같은 사실을 확인할 수 있었습니다.

원인

  1. HDR 영상 촬영 증가: 최신 디바이스는 Dolby Vision(HDR) 촬영을 지원하며, 특히 iOS는 기본적으로 HDR로 촬영됩니다.
  2. Android 기기의 색상 표현 한계: HDR은 SDR보다 넓은 색상 범위를 가지지만, Android 기기에서는 완벽히 지원되지 않아 색상이 정상적으로 노출되지 않을 수 있습니다.

초기 접근 : HDR → SDR 변환 

초기에는 이 문제를 해결하기 위해, HDR 영상을 SDR로 변환하는 방식을 채택했습니다.

  • AWS MediaConvert와 Lambda에서 FFmpeg을 활용하여 업로드된 HDR 영상을 SDR로 변환

이렇게 인코딩 파이프라인을 개선한 결과, Android 기기에서도 색상 왜곡 없이 영상을 정상적으로 표시할 수 있었습니다. 하지만 변환 시간이 길어, 영상의 퀄리티나 해상도(크기)에 따라 인코딩 소요 시간이 달라지고, 일부 영상은 5분 이상 걸리는 경우도 발생하며 사용자 경험에 부정적인 영향을 줄 수 있었습니다.


해결: 클라이언트 기반의 동적 톤 조정

최종적으로는 AWS MediaConvert 인코딩 과정에서 영상의 HDR 여부만 사전 판별한 뒤, Android 기기에서는 해당 정보를 기반으로 클라이언트 측에서 동적으로 톤을 보정하는 방식으로 전환했습니다.

이를 통해 SDR로 영상 타입 자체를 변환하지 않더라도, 디바이스 특성에 맞춰 색상을 최적화할 수 있었고, 추가적인 인코딩 과정 없이도 영상의 화이트아웃 현상을 효과적으로 완화할 수 있었습니다.


[톤 조정 전, 후 비교✨]




숏폼 콘텐츠, 마치면서..


숏폼 콘텐츠 도입부터 스트리밍 최적화, 디바이스 이슈 대응까지 쉽지 않은 과정이었지만, 결국 사용자 경험을 최우선으로 두며 하나씩 풀어낼 수 있었습니다.

특히 기술적으로는 M3U8(HLS) 포맷 도입을 통해 보다 빠른 영상 로딩 속도를 제공할 수 있었고, 세그먼트 단위 캐싱 구조를 활용해 CDN 캐싱 효율성 또한 크게 향상되었습니다. 이러한 기술적 기반 위에서, 실제 서비스 내 활성 사용자 수(AU)는 약 21% 증가, 콘텐츠 기반 전환율도 5% 개선되는 등 비즈니스 측면에서도 의미 있는 성과를 확인할 수 있었습니다.

물론, 아직도 해결해야 할 과제들이 남아있습니다. 페이지 렌더링 최적화, 콘텐츠 반복 노출 최소화를 위한 정렬 로직 개선, 숏폼 컴포넌트 공통화 등 더 나은 서비스 경험을 위해 계속 고민하고 있습니다.

앞으로도 이러한 고민을 지속하며, 더 나은 서비스 경험을 제공할 수 있도록 끊임없이 개선해 나가겠습니다. 셔터의 다음 변화도 기대해 주세요. 🙇‍♀️

m3u8HLSCommunity
올리브영 테크 블로그 작성 HLS 기반 숏폼 스트리밍 구현기: iOS/Android 호환성 대응 사례
💜
뽀야미 |
Front-end Engineer
흘러가듯 개발하고 싶은 프론트엔드 개발자입니다 〰️