[ios] iOS AVPlayer 시작 지연을 줄이는 방법

아래 질문에 대한 참고 : 모든 자산은 장치에서 로컬이며 네트워크 스트리밍이 발생하지 않습니다. 비디오에는 오디오 트랙이 포함되어 있습니다.

문제의 비디오 클립을 시작하려면 최소한의 지연으로 비디오 파일을 재생해야하는 iOS 응용 프로그램에서 작업 중입니다. 불행히도 우리는 실제로 시작해야 할 때까지 특정 비디오 클립이 다음에 무엇인지 알 수 없습니다. 구체적으로 : 하나의 비디오 클립이 재생 될 때 (대략) 10 개의 비디오 클립의 다음 세트가 무엇인지 알 수 있지만 다음 클립을 ‘즉시’재생할 때까지 정확히 어떤 클립인지 알 수 없습니다.

실제 시작 지연을 확인하기 위해 제가 한 것은 addBoundaryTimeObserverForTimes비디오 플레이어 를 호출 하는 것입니다. 1 밀리 초의 시간을두고 비디오가 실제로 재생되기 시작한시기를 확인하고 해당 타임 스탬프의 차이를 재생을 시작할 자산을 나타내는 코드입니다.

지금까지 본 것에서 AVAsset로딩 조합을 사용하고 AVPlayerItem준비가되면 생성 한 다음 AVPlayerStatusReadyToPlay플레이를 호출하기 전에 대기하는 것이 시작하는 데 1 ~ 3 초가 걸리는 경향이 있음을 알았습니다. 클립.

나는 그 이후로 거의 동등하다고 생각하는 것으로 전환했습니다. 전화를 걸고 플레이를 [AVPlayerItem playerItemWithURL:]기다리고 AVPlayerItemStatusReadyToPlay있습니다. 거의 동일한 성능.

내가 관찰 한 한 가지는 첫 번째 AVPlayer 항목로드가 나머지 항목보다 느리다는 것입니다. 한 가지 아이디어는 첫 번째 비디오를 재생하기 전에 짧거나 비어있는 자산으로 AVPlayer를 미리 비행하는 것입니다. [ 처음 소리가 재생 될 때 AVAudioPlayer의 느린 시작

가능한 한 비디오 시작 시간을 줄이고 실험 할 아이디어가 있지만 도움이 될 수있는 모든 사람의 지침을 받고 싶습니다.

업데이트 : 아래 아이디어 7, 구현시 약 500ms의 스위칭 시간이 발생합니다. 이것은 개선 된 것이지만 이것을 더 빨리 얻는 것이 좋을 것입니다.

아이디어 1 : N AVPlayers 사용 (작동하지 않음)

~ 10 개의 AVPPlayer개체를 사용하고 ~ 10 개의 클립을 모두 시작 및 일시 중지하고, 어떤 클립이 정말 필요한지 알고 나면 올바른 항목으로 전환하고 일시 중지를 해제합니다.AVPlayer 하고 다음주기를 위해 다시 시작합니다.

AVPlayer'siOS에서 약 4 개의 활성 제한이 있음을 읽었으므로 이것이 작동하지 않는다고 생각합니다 . 여기 StackOverflow에서 누군가가 이것에 대해 물어 보았고 , 4 개의 AVPlayer 제한에 대해 알아 냈습니다 : fast-switching-between-videos-using-avfoundation

아이디어 2 : AVQueuePlayer 사용 (작동하지 않음)

10 개를 AVPlayerItems넣는 AVQueuePlayer것이 원활한 시작을 위해 모두 미리로드 될 것이라고 생각하지 않습니다 . AVQueuePlayer대기열이며 대기열에있는 다음 동영상 만 즉시 재생할 수 있도록 준비합니다. 나는 그것을 시작할 시간이 될 때까지 ~ 10 개의 비디오 중 어떤 것을 재생하고 싶은지 모르겠다. ios-avplayer-video-preloading

아이디어 3 : AVPlayerItems백그라운드에서 로드, 재생 및 유지 (아직 100 % 확실하지는 않지만 좋지 않음)

백그라운드에서 각 비디오 클립의 첫 번째 초를로드 및 재생하고 (비디오 및 오디오 출력 억제) 각각에 대한 참조를 유지하고 AVPlayerItem어떤 항목에 대해 재생해야하는지 알 때 이점이 있는지 살펴보고 있습니다. 진짜로 바꾸고 배경 AVPlayer를 활성으로 바꿉니다. 헹구고 반복하십시오.

이론은 최근에 재생 된 AVPlayer/AVPlayerItem의가 후속 재생을 더 빠르게 할 수 있도록 준비된 리소스를 여전히 보유 할 수 있다는 것입니다. 지금까지 이것의 이점을 보지 못했지만 AVPlayerLayer배경에 대한 설정이 정확 하지 않을 수 있습니다 . 나는 이것이 내가 본 것에서 정말로 개선 될 것 같지 않다.

아이디어 4 : 다른 파일 형식을 사용하세요.로드가 더 빠른 파일 형식일까요?

현재 .m4v (비디오 -MPEG4) H.264 형식을 사용하고 있습니다. H.264에는 다양한 코덱 옵션이 있으므로 일부 옵션이 다른 옵션보다 빠르게 검색 될 수 있습니다. 파일 크기를 더 작게 만드는 고급 설정을 사용하면 검색 시간이 늘어나지 만 다른 방식으로가는 옵션은 찾지 못했습니다.

아이디어 5 : 무손실 비디오 형식 + AVQueuePlayer의 조합

로드 속도가 빠르지 만 파일 크기가 제정신이 아닐 수있는 비디오 형식이있는 경우 한 가지 아이디어는 각 비디오 클립의 처음 10 초를 부풀어도로드 속도가 빠른 버전으로 미리 준비하는 것입니다. H.264로 인코딩 된 자산을 사용합니다. AVQueuePlayer를 사용하고 압축되지 않은 파일 형식에 처음 10 초를 추가하고 최대 10 초의 준비 / 사전로드 시간을 가져 오는 H.264 형식의 파일을 추가합니다. 그래서 저는 두 세계 모두에서 ‘최고’를 얻었습니다. 시작 시간이 빠르지 만 더 컴팩트 한 형식의 이점도 있습니다.

아이디어 6 : 비표준 AVPlayer 사용 / 직접 작성 / 다른 사람 사용

내 필요를 감안할 때 AVPlayer를 사용할 수 없지만 AVAssetReader에 의존하고 처음 몇 초 동안 디코딩 (아마도 원시 파일을 디스크에 기록)하고 재생시 원시 형식을 사용하여 재생해야합니다. 뒤로 빨리. 나에게는 거대한 프로젝트처럼 보이며 순진하게 진행하면 불분명하거나 더 잘 작동하지 않을 것입니다. 디코딩되고 압축되지 않은 각 비디오 프레임은 2.25MB입니다. 순진하게 말해서, 비디오에 대해 ~ 30fps로 가면 ~ 60MB / s의 디스크에서 읽기 요구 사항으로 끝날 것입니다. 이는 아마도 불가능하거나 밀어 붙일 것입니다. 분명히 우리는 어느 정도의 이미지 압축 (아마도 PVRTC를 통한 기본 openGL / es 압축 형식)을 수행해야합니다 …하지만 그건 미친 짓입니다. 제가 사용할 수있는 도서관이있을 수 있을까요?

아이디어 7 : 모든 것을 단일 영화 자산으로 결합하고 seekToTime

위의 일부보다 쉬울 수있는 한 가지 아이디어는 모든 것을 단일 영화로 결합하고 seekToTime을 사용하는 것입니다. 문제는 우리가 모든 곳을 뛰어 다니는 것입니다. 본질적으로 영화에 무작위로 액세스합니다. 나는 이것이 실제로 잘 될 것이라고 생각합니다 : avplayer-movie-playing-lag-in-ios5

어떤 접근 방식이 가장 좋을 것이라고 생각하십니까? 지금까지 지연을 줄이는 측면에서 그렇게 많은 진전을 이루지 못했습니다.



답변

iOS 10.x 이상의 경우 AVPlayer 시작 지연을 줄이기 위해 설정
avplayer.automaticallyWaitsToMinimizeStalling = false;
했습니다. 이것은 다른 결과를 초래할 수 있지만 아직 그것들을 치지 않았습니다.

https://stackoverflow.com/a/50598525/9620547 에서 아이디어를 얻었습니다.


답변

자산을 생성 한 후에는 준비되지 않을 수 있으며, 영화 길이와 같은 계산을 수행 할 수 있습니다. 파일에 영화의 모든 메타 데이터가 포함되어 있는지 확인하십시오.


답변

옵션 # 7을 먼저 시도하여 작동 할 수 있는지 확인해야합니다. 탐색 시간이 클립 사이를 원활하게 전환 할 수있을만큼 빠르지 않을 수 있기 때문에 실제로 필요에 맞지 않을 것이라고 생각합니다. 시도했지만 실패하면 옵션 4/6을 수행하고이 목적을 위해 특별히 설계된 iOS 라이브러리를 살펴보고 AVAnimator에서 빠른 Google 검색을 수행하여 자세한 내용을 확인하는 것이 좋습니다. 내 라이브러리를 사용하면 원활한 루프를 구현하고 한 클립에서 다른 클립으로 전환 할 수 있습니다. 비디오를 미리 파일로 디코딩해야하므로 매우 빠릅니다. 귀하의 경우에는 시작하기 전에 10 개의 비디오 클립이 모두 파일로 디코딩되지만 전환이 빠릅니다.


답변

과거에 이와 같은 작업을 수행하지 않고 귀하의 생각과 경험을 바탕으로 7과 1의 조합을 시도해 보겠습니다. 10 개의 후속 동영상 중 처음 몇 초 동안 AVPlayer 하나를 미리로드합니다. 그러면 데이터가 적기 때문에 건너 뛰기가 더 빠르고 안정적 ​​일 수 있습니다. 선택한 곡을 재생하는 동안 백그라운드에서 선택한 나머지 후속 비디오를 위해 AVPlayer를 준비 할 충분한 시간이 있습니다. 시작이 끝나면 준비된 AVPlayer로 전환합니다. 따라서 전체적으로 주어진 시간에 최대 2 개의 AVPlayer를로드 할 수 있습니다.

물론 재생을 방해하지 않을 정도로 매끄럽게 전환 할 수 있는지는 모르겠습니다.

(가능하다면 이것을 주석으로 추가했을 것입니다.)

최고, 피터


답변

문제를 올바르게 이해했다면 잠시 알림을 받으면 오디오 트랙을로드해야하는 연속 동영상이 하나있는 것 같습니다.

그렇다면 BASS를 살펴 보는 것이 좋습니다. . BASS는 iOS에서 AudioUnits 프레임 워크의 저수준 API에 (상대적으로) 쉽게 액세스 할 수있는 AVPlayer와 매우 유사한 오디오 라이브러리입니다. 당신에게 어떤 의미가 있습니까? 이는 약간의 버퍼 조작으로 (필요하지 않을 수도 있으며, 원하는 지연 시간에 따라 다름) 즉시 음악 재생을 시작할 수 있음을 의미합니다.

그러나 제한 사항은 비디오로 확장됩니다. 제가 말했듯이 오디오 라이브러리이므로 모든 비디오 조작은 여전히 ​​AVPlayer로 수행해야합니다. 그러나 사용-seekToTime:toleranfeBefore:toleranceAfter: 하면 필요한 모든 옵션을 미리 적용하는 한 비디오 내에서 빠른 검색을 얻을 수 있습니다.

여러 장치에서 동기화하는 경우 (응용 프로그램에서 제안 할 수 있음) 의견을 남겨 주시면 기꺼이 답변을 수정할 수 있습니다.

추신 : BASS는 C와 같은 형식이기 때문에 처음에는 벅차게 보일지 모르지만 실제로 사용하기가 정말 쉽습니다.


답변

다음은 도움이 될 수있는 AVAsset 클래스에서 제공하는 몇 가지 속성 및 메서드입니다.

- (void)_pu_setCachedDuration:(id)arg1;
- (id)pu_cachedDuration;
- (struct
 {
   long long x1;
   int x2;
   unsigned int x3;
   long long x4;
})pu_duration;
- (void)pu_loadDurationWithCompletionHandler:(id /* block */)arg1;


답변