문제 해결


'일반 텍스트 HTTP 트래픽이 허용되지 않음' 수정 오류

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

앱이 일반 텍스트 HTTP 트래픽으로 작업해야 하는 경우 허용하는 네트워크 보안 구성입니다. Android의 네트워크 보안 문서 참조하세요. 일반 텍스트 HTTP 트래픽을 모두 사용 설정하려면 앱의 application 요소에 android:usesCleartextTraffic="true" 추가 AndroidManifest.xml입니다.

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

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

SSLHandshakeException, CertPathValidatorExceptionERR_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 이는 다음을 사용하여 DefaultExtractorsFactory에서 설정할 수 있습니다. setMp3ExtractorFlags: 큰 MP3 파일에는 잘 맞지 않습니다. 특히 사용자가 곧 스트림의 끝부분 근처를 탐색하려고 하는 경우 플레이어가 다운로드될 때까지 기다려야 함 탐색을 수행하기 전에 전체 스트림의 색인을 생성했습니다. ExoPlayer에서 이 경우에는 정확성보다는 속도를 최적화하기로 결정했고 따라서 FLAG_ENABLE_INDEX_SEEKING가 기본적으로 사용 중지됩니다.

재생 중인 미디어를 제어하는 경우 적절한 컨테이너 형식(예: MP4)을 사용합니다 알려진 사용 사례가 없음 여기서 MP3가 미디어 형식에 가장 적합합니다.

내 동영상의 탐색 속도가 느린 이유는 무엇인가요?

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

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

(1)으로 인해 발생하는 지연 시간은 데이터를 디스크에 사전 캐싱하는 등의 경우에 사용할 수 있습니다.

(2)로 인해 발생하는 지연 시간은 ExoPlayer.setSeekParameters를 사용하거나 동영상을 다시 인코딩합니다. I-frame을 더 자주 사용할 수 있습니다. 이 경우 출력 파일이 더 커집니다.

일부 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가 이를 감지할 수 없습니다. 수동으로 원하는 자막 트랙을 접근성을 포함한 DefaultExtractorsFactory 자막 형식 MPEG-TS 스트림에서 식별하는 데 사용할 수 있는 채널은 다음과 같습니다.

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()

자바

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를 사용하여 DefaultExtractorsFactory 또는 setFragmentedMp4ExtractorFlags:

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

HTTP 응답 코드 301과 302는 모두 리디렉션을 나타냅니다. 간략한 설명 위키백과에서 찾을 수 있습니다. ExoPlayer가 요청을 하고 상태 코드 301 또는 302인 경우 일반적으로 평소처럼 재생을 시작합니다. 기본적으로 이 문제가 발생하지 않는 사례입니다. 교차 프로토콜 리디렉션을 위한 것입니다 교차 프로토콜 리디렉션은 그 반대의 경우도 가능합니다. 프로토콜)을 제공합니다. URL이 교차 프로토콜 리디렉션을 발생시키는지 여부를 테스트하려면 wget 명령줄 도구를 설치합니다.

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(으)로 리디렉션 교차 프로토콜 리디렉션입니다. ExoPlayer는 기본 구성에서 이 리디렉션을 따릅니다. 즉, 재생이 실패합니다.

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

일부 스트림이 UnAwareInputFormatException과 함께 실패하는 이유는 무엇인가요?

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

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_SS~setMimeTypeMediaItem.Builder 스트림 유형을 지정할 수 있습니다.

드문 두 번째 원인은 ExoPlayer가 컨테이너를 지원하지 않기 때문입니다. 지정할 수 있습니다. 이 경우 실패는 기능 요청을 제출할 수 있습니다. Issue Tracker를 통해 컨테이너 형식 및 테스트 스트림의 세부정보를 확인할 수 있습니다. 새 기능 요청을 제출하기 전에 기존 기능 요청을 검색해 보세요.

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

Android M 이하에서 앱의 디버그 빌드를 실행할 때 성능 저하, 오디오 아티팩트, 높은 CPU 사용률을 setPlaybackParameters API를 사용합니다. 최적화가 이 API에 중요한 기능은 있습니다.

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

'잘못된 스레드에서 플레이어가 액세스됨'은 어떻게 해야 하나요? 무엇을 의미할까요?

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

'예상치 못한 상태 줄: ICY 200 확인'을 해결하려면 어떻게 해야 하나요?

이 문제는 서버 응답에 ICY 상태 줄이 포함되어 있거나 HTTP를 준수하는 URL이 될 수 있습니다 ICY 상태 표시줄은 지원 중단되었으며 를 사용하면 안 됩니다. 따라서 서버를 제어하는 경우 HTTP 호환 응답을 전송합니다. 이 작업을 수행할 수 없는 경우 ExoPlayer OkHttp 라이브러리를 통해 ICY를 처리할 수 있으므로 문제가 해결됩니다. 확인합니다.

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

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

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

앱이 실행될 때 오디오를 계속 재생하려면 다음 단계를 따르세요. 배경:

  1. 실행 중인 포그라운드 서비스가 있어야 합니다. 이렇게 하면 프로세스를 중단하지 않고 리소스를 확보할 수 있습니다.
  2. WifiLockWakeLock을 보유해야 합니다. 이를 통해 시스템은 WiFi 라디오와 CPU를 켜진 상태로 유지합니다. 이 작업은 setWakeMode를 호출하여 ExoPlayer합니다. 이렇게 하면 자동으로 필요한 잠금을 획득하고 해제할 수 있습니다.

setWakeMode를 사용하지 않는 경우 잠금을 해제하고 서비스가 재개됩니다

ExoPlayer는 내 콘텐츠를 지원하지만 ExoPlayer Cast 라이브러리는 왜 지원하지 않나요?

재생하려는 콘텐츠가 CORS가 사용 설정됨. Cast 프레임워크를 사용하려면 콘텐츠가 있습니다.

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

콘텐츠를 재생 중인 기기에서 특정 미디어 샘플 형식을 지원해야 합니다. 이는 다음을 추가하여 쉽게 확인할 수 있습니다. EventLogger를 플레이어의 리스너로 호출하여 다음과 유사합니다.

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

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

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

  • 대부분의 디코더 라이브러리에는 종속 항목을 확인하고 빌드하는 수동 단계가 있으므로 관련 라이브러리에 대한 README의 단계를 따르세요. 예를 들어 ExoPlayer FFmpeg 라이브러리의 경우 library/decoder_ffmpeg/README.md에 구성 플래그를 사용하여 재생하려는 모든 형식에 디코더를 사용 설정해야 합니다.
  • 네이티브 코드가 있는 라이브러리의 경우 올바른 최신 버전의 Android NDK를 다운받고 발생하는 오류에 대해 자세히 알아보겠습니다. .so가 표시됩니다. 파일은 각 객체의 라이브러리 경로의 libs 하위 디렉터리에 표시됩니다. 지원되는 아키텍처를 검토하세요.
  • 데모 애플리케이션에서 라이브러리를 사용하여 재생해 보려면 다음을 참조하세요. 번들 디코더 사용 설정을 참조하세요. 이 모듈의 안내를 따르세요.
  • DefaultRenderersFactory를 사용하는 경우 정보 수준이 표시됩니다. 'Loaded FfmpegAudioRenderer'와 같은 로그 줄 Logcat에 기록됩니다. 이 필드가 누락된 경우 애플리케이션에 인코딩합니다.
  • Logcat에서 LibraryLoader의 경고 수준 로그가 표시되면 는 라이브러리의 네이티브 구성 요소를 로드하지 못했음을 나타냅니다. 만약 라이브러리의 README에 있는 단계를 올바르게 따랐는지 확인합니다. 안내를 따르는 동안 오류가 출력되지 않았음을 확인합니다.

여전히 디코딩 라이브러리를 사용하는 데 문제가 있는 경우 Media3 Issue Tracker에서 관련 최근 문제를 확인합니다. 제출해야 하는 경우 라이브러리의 기본 부분 빌드와 관련되어 있습니다. README 명령어 실행에서 나오는 전체 명령줄 출력을 포함하여 문제를 진단할 수 있습니다

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

아니요, ExoPlayer는 양식의 URL과 같은 YouTube 동영상을 재생할 수 없습니다. https://www.youtube.com/watch?v=... 대신 YouTube IFrame Player API 이는 Android에서 YouTube 동영상을 재생할 수 있는 공식적인 방법입니다.

동영상 재생이 끊김

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

Android 버전을 실행하는 기기에서 동영상 끊김 현상이 발생하는 경우 Android 6.0 (API 수준 23)부터 Android 11 (API 수준 30)까지 특히 DRM으로 보호되거나 고속 프레임이 적용되는 콘텐츠를 재생할 때 비동기 버퍼 큐를 사용 설정합니다.

불안정한 API 린트 오류

Media3은 API 노출 영역의 하위 집합에 관한 바이너리 호환성을 보장합니다. 이 바이너리 호환성을 보장하지 않는 부분은 @UnstableApi 이 구분을 명확히 하기 위해 API 기호는 @OptIn로 주석이 지정되지 않는 한 린트 오류를 생성합니다.

@UnstableApi 주석은 API의 품질이나 성능에 관한 의미는 없으며 'API 고정' 상태가 아니라는 사실만 암시합니다.

불안정한 API 린트 오류를 처리하는 방법에는 두 가지가 있습니다.

  • 동일한 결과를 얻는 안정적인 API를 사용하도록 전환합니다.
  • 다음과 같이 불안정한 API를 계속 사용하고 사용에 @OptIn로 주석을 추가합니다. 나중에 설명하겠습니다
@OptIn 주석을 추가합니다.

Android 스튜디오를 사용하면 다음과 같이 주석을 추가할 수 있습니다.

<ph type="x-smartling-placeholder">
</ph> 스크린샷: 수신 동의 주석을 추가하는 방법
그림 2: Android 스튜디오에서 @androidx.annotations.OptIn 주석 추가

Kotlin에서 특정 사용 사이트에 수동으로 주석을 달 수도 있습니다.

import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi

@OptIn(UnstableApi::class)
fun functionUsingUnstableApi() { ... }

Java에서도 다음과 같습니다.

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

@OptIn(markerClass = UnstableApi.class)
private void methodUsingUnstableApis() { ... }

package-info.java 파일을 추가하여 전체 패키지를 선택할 수 있습니다.

@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;

import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

프로젝트 전체에서 특정 린트 오류를 억제하여 전체 프로젝트를 선택할 수 있습니다. lint.xml 파일:

 <?xml version="1.0" encoding="utf-8"?>
 <lint>
   <issue id="UnsafeOptInUsageError">
     <option name="opt-in" value="androidx.media3.common.util.UnstableApi" />
   </issue>
 </lint>

사용해서는 안 되는 kotlin.OptIn 주석도 있습니다. 그것은 androidx.annotation.OptIn 주석을 사용하는 것이 중요합니다.