문제해결


'일반 텍스트 HTTP 트래픽은 허용되지 않음' 오류 해결

이 오류는 네트워크 보안 구성에서 허용하지 않지만 앱이 일반 텍스트 HTTP 트래픽 (즉, https://이 아닌 http://)을 요청하는 경우 발생합니다. 앱에서 Android 9 (API 수준 28) 이상을 타겟팅하는 경우 기본 구성에 의해 일반 텍스트 HTTP 트래픽이 사용 중지됩니다.

앱에서 일반 텍스트 HTTP 트래픽으로 작업해야 하는 경우 이를 허용하는 네트워크 보안 구성을 사용해야 합니다. 자세한 내용은 Android의 네트워크 보안 문서를 참고하세요. 모든 일반 텍스트 HTTP 트래픽을 사용 설정하려면 android:usesCleartextTraffic="true"를 앱 AndroidManifest.xmlapplication 요소에 추가하기만 하면 됩니다.

ExoPlayer 데모 앱은 기본 네트워크 보안 구성을 사용하므로 일반 텍스트 HTTP 트래픽을 허용하지 않습니다. 위의 안내에 따라 사용 설정할 수 있습니다.

'SSLHandshakeException', 'CertPathValidatorException', 'ERR_CERT_AUTHORITY_INVALID' 오류 수정

SSLHandshakeException, CertPathValidatorException, ERR_CERT_AUTHORITY_INVALID는 모두 서버의 SSL 인증서에 문제가 있음을 나타냅니다. 이러한 오류는 ExoPlayer와 관련이 없습니다. 자세한 내용은 Android의 SSL 문서를 참조하세요.

일부 미디어 파일을 찾을 수 없는 이유는 무엇인가요?

기본적으로 ExoPlayer는 미디어에서의 탐색을 지원하지 않습니다. 이 경우 정확한 탐색 작업을 실행하는 유일한 방법은 플레이어가 전체 파일을 스캔하고 색인을 생성하는 것입니다. ExoPlayer는 이러한 파일을 탐색 불가능하다고 간주합니다. 대부분의 최신 미디어 컨테이너 형식은 탐색을 위한 메타데이터 (예: 샘플 색인)를 포함하거나, 잘 정의된 탐색 알고리즘 (예: Ogg의 보간된 바이섹션 검색)을 포함하거나, 콘텐츠가 일정한 비트 전송률임을 나타냅니다. 이러한 경우 효율적인 탐색 작업이 가능하며 ExoPlayer에서 지원됩니다.

탐색이 필요하지만 검색하지 않는 미디어가 있는 경우 더 적절한 컨테이너 형식을 사용하도록 콘텐츠를 변환하는 것이 좋습니다. MP3, ADTS, AMR 파일의 경우 여기에 설명된 대로 파일의 비트 전송률이 일정하다는 가정하에 탐색을 사용 설정할 수도 있습니다.

일부 MP3 파일에서 찾기가 정확하지 않은 이유는 무엇인가요?

가변 비트 전송률 (VBR) MP3 파일은 정확한 탐색을 필요로 하는 사용 사례에 본질적으로 적합하지 않습니다. 여기에는 다음과 같은 두 가지 이유가 있습니다.

  1. 정확한 탐색의 경우 컨테이너 형식을 사용하면 헤더에 정밀한 바이트 간 매핑을 제공하는 것이 이상적입니다. 이 매핑을 통해 플레이어는 요청된 탐색 시간을 상응하는 바이트 오프셋에 매핑하고 이 오프셋에서 미디어 요청, 파싱, 재생을 시작할 수 있습니다. MP3에서 이 매핑을 지정하는 데 사용할 수 있는 헤더 (예: XING 헤더)는 안타깝게도 종종 제대로 작동하지 않습니다.
  2. 정확한 시간-바이트 매핑 (또는 시간-바이트 간 매핑)을 제공하지 않는 컨테이너 형식의 경우에도 컨테이너가 스트림에 절대 샘플 타임스탬프를 포함하고 있다면 정확한 탐색을 수행할 수 있습니다. 이 경우 플레이어는 탐색 시간을 상응하는 바이트 오프셋의 최적 추측에 매핑하고, 해당 오프셋에서 미디어 요청을 시작하고, 첫 번째 절대 샘플 타임스탬프를 파싱하고, 올바른 샘플을 찾을 때까지 미디어에 가이드 바이너리 검색을 효과적으로 실행할 수 있습니다. 안타깝게도 MP3는 스트림에 절대 샘플 타임스탬프를 포함하지 않으므로 이 접근 방식은 불가능합니다.

이러한 이유로 VBR MP3 파일로 정확한 탐색을 실행하는 유일한 방법은 전체 파일을 스캔하고 플레이어에서 바이트 간 매핑을 수동으로 빌드하는 것입니다. 이 전략은 FLAG_ENABLE_INDEX_SEEKING를 사용하여 사용 설정할 수 있으며 setMp3ExtractorFlags를 사용하여 DefaultExtractorsFactory에서 설정할 수 있습니다. 특히 사용자가 재생을 시작한 직후 스트림의 끝 근처를 탐색하려고 하는 경우, 플레이어가 전체 스트림을 다운로드하고 색인을 생성한 후에 탐색해야 하는 경우 대용량 MP3 파일로 잘 확장되지 않습니다. ExoPlayer에서는 정확성보다 속도를 높이기 위해 최적화하기로 했으므로 FLAG_ENABLE_INDEX_SEEKING는 기본적으로 사용 중지됩니다.

재생 중인 미디어를 제어하는 경우 MP4와 같이 더 적절한 컨테이너 형식을 사용하는 것이 좋습니다. Google에서는 MP3가 미디어 형식으로 가장 적합한 사용 사례를 알고 있지 않습니다.

동영상에서 찾기가 느린 이유는 무엇인가요?

플레이어가 동영상에서 새 재생 위치를 찾을 때 다음 두 가지 작업을 실행해야 합니다.

  1. 새 재생 위치에 상응하는 데이터를 버퍼에 로드합니다(이 데이터가 이미 버퍼링된 경우 필요하지 않을 수 있음).
  2. 대부분의 동영상 압축 형식에서 사용되는 프레임 내 코딩으로 인해 동영상 디코더를 플러시하고 새 재생 위치 전에 I-프레임 (키프레임)에서 디코딩을 시작합니다. 탐색이 정확하도록 하려면 (즉, 탐색 위치에서 정확하게 재생이 시작됨) 앞의 I-프레임과 탐색 위치 사이의 모든 프레임을 디코딩하고 즉시 삭제해야 합니다 (화면에 표시되지 않음).

(1)에 의해 발생하는 지연 시간은 플레이어가 메모리에 버퍼링하는 데이터의 양을 늘리거나 데이터를 디스크에 미리 캐시하여 완화할 수 있습니다.

(2)에 의해 발생하는 지연 시간은 ExoPlayer.setSeekParameters를 사용하여 탐색의 정확성을 낮추거나 I-프레임이 더 자주 발생하도록 동영상을 다시 인코딩하여 (출력 파일이 더 커짐) 완화할 수 있습니다.

일부 MPEG-TS 파일이 재생되지 않는 이유는 무엇인가요?

일부 MPEG-TS 파일은 액세스 단위 구분 기호 (AUD)를 포함하지 않습니다. 기본적으로 ExoPlayer는 AUD를 사용하여 프레임 경계를 저렴하게 감지합니다. 마찬가지로 일부 MPEG-TS 파일에는 IDR 키프레임이 포함되지 않습니다. 기본적으로 ExoPlayer에서 고려하는 유일한 키프레임 유형입니다.

ExoPlayer는 AUD 또는 IDR 키프레임이 없는 MPEG-TS 파일을 재생하라는 메시지가 표시될 때 버퍼링 상태에서 멈춘 것처럼 보입니다. 이러한 파일을 재생해야 한다면 FLAG_DETECT_ACCESS_UNITSFLAG_ALLOW_NON_IDR_KEYFRAMES를 각각 사용하면 됩니다. 이러한 플래그는 setTsExtractorFlags를 사용하여 DefaultExtractorsFactory에서 설정하거나 생성자를 사용하여 DefaultHlsExtractorFactory에서 설정할 수 있습니다. FLAG_DETECT_ACCESS_UNITS를 사용하면 AUD 기반 프레임 경계 감지에 비해 계산 비용이 많이 드는 것 외에 부작용은 없습니다. FLAG_ALLOW_NON_IDR_KEYFRAMES를 사용하면 일부 MPEG-TS 파일을 재생할 때 재생 시작 시점과 탐색 직후 일시적으로 시각적 손상이 발생할 수 있습니다.

일부 MPEG-TS 파일에서 자막을 찾을 수 없는 이유는 무엇인가요?

일부 MPEG-TS 파일은 CEA-608 트랙을 포함하지만 컨테이너 메타데이터에서 이를 선언하지 않으므로 ExoPlayer에서 감지할 수 없습니다. MPEG-TS 스트림에서 자막을 식별하는 데 사용할 수 있는 접근성 채널을 포함하여 예상되는 자막 형식의 목록을 DefaultExtractorsFactory에 제공하여 자막 트랙을 수동으로 지정할 수 있습니다.

Kotlin

val extractorsFactory =
  DefaultExtractorsFactory()
    .setTsSubtitleFormats(
      listOf(
        Format.Builder()
          .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
          .setAccessibilityChannel(accessibilityChannel)
          // Set other subtitle format info, such as language.
          .build()
      )
    )
val player: Player =
  ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, extractorsFactory)).build()

Java

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory()
        .setTsSubtitleFormats(
            ImmutableList.of(
                new Format.Builder()
                    .setSampleMimeType(MimeTypes.APPLICATION_CEA608)
                    .setAccessibilityChannel(accessibilityChannel)
                    // Set other subtitle format info, such as language.
                    .build()));
Player player =
    new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, extractorsFactory))
        .build();

일부 MP4/FMP4 파일이 잘못 재생되는 이유는 무엇인가요?

일부 MP4/FMP4 파일에는 샘플 목록을 건너뛰거나 이동하거나 반복하여 미디어 타임라인을 다시 작성하는 편집 목록이 포함되어 있습니다. ExoPlayer는 수정 목록 적용을 부분적으로 지원합니다. 예를 들어 동기화 샘플에서 시작되는 샘플 그룹을 지연시키거나 반복할 수 있지만 동기화 샘플에서 시작되지 않는 수정의 오디오 샘플이나 프리롤 미디어를 자르지는 않습니다.

미디어의 일부가 예기치 않게 누락되거나 반복되는 경우 Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS 또는 FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS를 설정해 보세요. 그러면 추출기가 수정 목록을 완전히 무시합니다. 이는 setMp4ExtractorFlags 또는 setFragmentedMp4ExtractorFlags를 사용하여 DefaultExtractorsFactory에서 설정할 수 있습니다.

일부 스트림이 HTTP 응답 코드 301 또는 302와 함께 실패하는 이유는 무엇인가요?

HTTP 응답 코드 301과 302는 모두 리디렉션을 나타냅니다. 간략한 설명은 위키백과에서 확인할 수 있습니다. ExoPlayer가 요청을 하고 상태 코드 301 또는 302의 응답을 수신하면 일반적으로 리디렉션을 따르고 정상적으로 재생을 시작합니다. 이것이 기본적으로 발생하지 않는 한 가지 경우는 교차 프로토콜 리디렉션입니다. 교차 프로토콜 리디렉션은 HTTPS에서 HTTP로 또는 그 반대 방향으로 (또는 드물게 다른 프로토콜 쌍 간에) 리디렉션되는 리디렉션입니다. 다음과 같이 wget 명령줄 도구를 사용하여 URL이 교차 프로토콜 리디렉션을 유발하는지 테스트할 수 있습니다.

wget "https://yourserver.com/test.mp3" 2>&1  | grep Location

출력은 다음과 같이 표시됩니다.

Location: https://second.com/test.mp3 [following]
Location: http://third.com/test.mp3 [following]

이 예에는 두 개의 리디렉션이 있습니다. 첫 번째 리디렉션은 https://yourserver.com/test.mp3에서 https://second.com/test.mp3로 이동합니다. 둘 다 HTTPS이므로 교차 프로토콜 리디렉션이 아닙니다. 두 번째 리디렉션은 https://second.com/test.mp3에서 http://third.com/test.mp3로의 리디렉션입니다. 이는 HTTPS에서 HTTP로 리디렉션되고 교차 프로토콜 리디렉션도 마찬가지입니다. ExoPlayer는 기본 구성에서 이 리디렉션을 따르지 않습니다. 즉, 재생이 실패합니다.

필요한 경우 애플리케이션에서 사용되는 DefaultHttpDataSource.Factory 인스턴스를 인스턴스화할 때 교차 프로토콜 리디렉션을 따르도록 ExoPlayer를 구성할 수 있습니다. 여기에서 네트워크 스택 선택 및 구성에 대해 알아보세요.

일부 스트림이 UnrecognizedInputFormatException으로 실패하는 이유는 무엇인가요?

이 질문은 다음 형식의 재생 실패와 관련이 있습니다.

UnrecognizedInputFormatException: None of the available extractors
(MatroskaExtractor, FragmentedMp4Extractor, ...) could read the stream.

이러한 실패에는 두 가지 원인이 있을 수 있습니다. 가장 일반적인 원인은 DASH (mpd), HLS (m3u8) 또는 SmoothStreaming (ism, isml) 콘텐츠를 재생하려고 하지만 플레이어가 이를 프로그레시브 스트림으로 재생하기 때문입니다. 이러한 스트림을 재생하려면 각 ExoPlayer 모듈에 종속되어야 합니다. 스트림 URI가 표준 파일 확장자로 끝나지 않는 경우 MimeTypes.APPLICATION_MPD, MimeTypes.APPLICATION_M3U8 또는 MimeTypes.APPLICATION_SSMediaItem.BuildersetMimeType에 전달하여 스트림 유형을 명시적으로 지정할 수도 있습니다.

드물게 발생하는 두 번째 이유는 ExoPlayer가 재생하려는 미디어의 컨테이너 형식을 지원하지 않기 때문입니다. 이 경우 실패는 의도한 대로 작동하는 것입니다. 하지만 컨테이너 형식 및 테스트 스트림의 세부정보를 포함하여 Issue Tracker에 기능 요청을 제출해도 됩니다. 새 기능 요청을 제출하기 전에 기존 기능 요청을 검색하세요.

일부 기기에서 setPlaybackParameters가 제대로 작동하지 않는 이유는 무엇인가요?

Android M 이하에서 앱의 디버그 빌드를 실행하면 setPlaybackParameters API를 사용할 때 성능이 끊기고 아티팩트가 들리며 CPU 사용률이 높을 수 있습니다. 이러한 버전의 Android에서 실행되는 디버그 빌드에서는 이 API에 중요한 최적화가 사용 중지되기 때문입니다.

이 문제는 디버그 빌드에만 영향을 미친다는 점에 유의해야 합니다. 최적화가 항상 사용 설정되는 출시 빌드에는 영향을 미치지 않습니다. 따라서 최종 사용자에게 제공하는 버전은 이 문제의 영향을 받지 않습니다.

'플레이어가 잘못된 스레드에서 액세스되었습니다' 오류의 의미는 무엇인가요?

시작하기 페이지에서 대화목록 관련 참고사항을 참조하세요.

'예상치 못한 상태 표시줄: ICY 200 OK'를 해결하려면 어떻게 해야 하나요?

이 문제는 서버 응답에 HTTP를 준수하는 상태 줄이 아닌 ICY 상태 표시줄을 포함하는 경우 발생할 수 있습니다. ICY 상태 표시줄은 지원 중단되었으므로 사용해서는 안 됩니다. 따라서 서버를 제어하는 경우 HTTP 준수 응답을 제공하도록 업데이트해야 합니다. 이 작업을 수행할 수 없는 경우 ICY 상태 줄을 올바르게 처리할 수 있으므로 ExoPlayer OkHttp 라이브러리를 사용하면 문제가 해결됩니다.

재생 중인 스트림이 라이브 스트림인지 여부를 쿼리하려면 어떻게 해야 하나요?

플레이어의 isCurrentWindowLive 메서드를 쿼리할 수 있습니다. 또한 isCurrentWindowDynamic를 확인하여 기간이 동적인지(즉, 시간이 지남에 따라 계속 업데이트되는지) 확인할 수 있습니다.

앱이 백그라운드에서 재생될 때 오디오를 계속 재생하려면 어떻게 해야 하나요?

앱이 백그라운드에 있을 때 오디오를 계속 재생하려면 다음 단계를 따르세요.

  1. 실행 중인 포그라운드 서비스가 있어야 합니다. 이렇게 하면 시스템에서 리소스를 확보하기 위해 프로세스를 종료하지 않습니다.
  2. WifiLockWakeLock를 보유해야 합니다. 이렇게 하면 시스템에서 WiFi 무선 및 CPU를 켜진 상태로 유지합니다. ExoPlayer를 사용하는 경우 setWakeMode를 호출하여 쉽게 할 수 있습니다. 그러면 필요한 잠금을 올바른 시간에 자동으로 획득하고 해제합니다.

setWakeMode를 사용하지 않는 경우 잠금을 해제하고 오디오가 더 이상 재생되지 않는 즉시 서비스를 중지하는 것이 중요합니다.

ExoPlayer는 내 콘텐츠를 지원하는데 ExoPlayer Cast 라이브러리는 지원하지 않는 이유는 무엇인가요?

재생하려는 콘텐츠가 CORS가 사용 설정되지 않았을 수 있습니다. Cast 프레임워크에서 콘텐츠를 재생하려면 CORS가 사용 설정되어 있어야 합니다.

콘텐츠 재생이 실패하는데 오류가 표시되지 않는 이유는 무엇인가요?

콘텐츠를 재생하는 기기에서 특정 미디어 샘플 형식을 지원하지 않을 수 있습니다. 이는 EventLogger를 플레이어에 리스너로 추가하고 Logcat에서 다음과 유사한 줄을 찾아 쉽게 확인할 수 있습니다.

[ ] Track:x, id=x, mimeType=mime/type, ... , supported=NO_UNSUPPORTED_TYPE

NO_UNSUPPORTED_TYPE는 기기가 mimeType에 의해 지정된 미디어 샘플 형식을 디코딩할 수 없음을 의미합니다. 지원되는 샘플 형식에 관한 자세한 내용은 Android 미디어 형식 문서를 참고하세요. 디코딩 라이브러리를 로드하여 재생에 사용하려면 어떻게 해야 하나요?도 유용할 수 있습니다.

디코딩 라이브러리를 로드하여 재생에 사용하려면 어떻게 해야 하나요?

  • 대부분의 디코더 라이브러리에는 종속 항목을 확인하고 빌드하는 수동 단계가 있으므로 관련 라이브러리에 대한 README의 단계를 따랐는지 확인하세요. 예를 들어 ExoPlayer FFmpeg 라이브러리의 경우 재생하려는 모든 형식에 관해 디코더를 사용 설정하기 위해 구성 플래그를 전달하는 것을 포함하여 library/decoder_ffmpeg/README.md의 안내를 따라야 합니다.
  • 네이티브 코드가 있는 라이브러리의 경우 README에 지정된 대로 올바른 버전의 Android NDK를 사용하고 구성 및 빌드 중에 발생하는 오류가 있는지 확인합니다. README의 단계를 따른 후 지원되는 각 아키텍처에 대한 라이브러리 경로의 libs 하위 디렉터리에 .so 파일이 표시됩니다.
  • 데모 애플리케이션에서 라이브러리를 사용해 재생해 보려면 번들 디코더 사용 설정을 참고하세요. 내 앱에서 라이브러리를 사용하는 방법은 라이브러리의 README를 참조하세요.
  • DefaultRenderersFactory를 사용하는 경우 디코더가 로드될 때 Logcat에 'Loaded FfmpegAudioRenderer'와 같은 정보 수준 로그 줄이 표시됩니다. 이러한 속성이 없으면 애플리케이션에 디코딩 라이브러리의 종속 항목이 있는지 확인합니다.
  • Logcat의 LibraryLoader에 경고 수준 로그가 표시되면 라이브러리의 네이티브 구성요소를 로드할 수 없음을 나타냅니다. 이 경우 라이브러리의 README에 있는 단계를 올바르게 따랐는지, 안내를 따르는 동안 오류가 출력되지 않았는지 확인하세요.

디코딩 라이브러리를 사용하는 데 여전히 문제가 발생하는 경우 Media3 Issue Tracker에서 최근의 관련 문제를 확인하세요. 라이브러리의 네이티브 부분 빌드와 관련된 새로운 문제를 신고해야 하는 경우 README 안내를 실행하여 문제를 진단할 수 있도록 전체 명령줄 출력을 포함하세요.

ExoPlayer로 YouTube 동영상을 직접 재생할 수 있나요?

아니요. ExoPlayer는 YouTube에서 https://www.youtube.com/watch?v=... 형식의 URL과 같은 동영상을 재생할 수 없습니다. 대신 Android에서 YouTube 동영상을 재생하는 공식적인 방법인 YouTube iFrame Player API를 사용해야 합니다.

동영상 재생이 끊김

예를 들어 콘텐츠 비트 전송률 또는 해상도가 기기 기능을 초과하는 경우 기기가 콘텐츠를 충분히 빠르게 디코딩하지 못할 수 있습니다. 이러한 기기에서 좋은 성능을 얻기 위해 품질이 낮은 콘텐츠를 사용해야 할 수도 있습니다.

Android 6.0 (API 수준 23)~Android 11 (API 수준 30) 이상의 Android 버전을 실행하는 기기에서 동영상 끊김이 발생하는 경우, 특히 DRM으로 보호되는 콘텐츠나 고속 프레임 콘텐츠를 재생할 때 비동기 버퍼 큐를 사용 설정해 보세요.