Looping AVPlayer seamlessly
Asked Answered
B

4

7

There has been some discussion before about how to loop an AVPlayer's video item, but no 'solution' is seamless enough to provide lag-less looping of a video.

I am developing a tvOS app that has a high-quality 10 second clip of 'scenery' in the background of one of its views, and simply restarting its AVPlayer the 'standard' way (subscribing to NSNotification to catch it) is too jumpy not to notice and detract from user experience.

It seems as though the only way to achieve a truly seamless loop is to manually manage frames, at a lower-level (in OpenGL)...

Despite best efforts to read up on this, and as a novice in manipulating video pipelines, I have not come close enough to a comprehensible solution.

I am aware that external libraries exist to be able to perform this behaviour more easily; most notably GPUImage. However, the app I am developing is for tvOS and therefore has difficulty using quite a lot of the 3rd party iOS libraries in existence, GPUImage included. Another library I have come across is AVAnimator, which provides great functionality for light-weight animation videos, but not for dense, high-quality video clips of source footage encoded in .H264.

The closest I have come so far is Apple's own AVCustomEdit source code, however this primarily deals with static production of a 'transition' that, while seamless, is too complex for me to be able to discern how to make it perform simple looping functionality.

If anybody can chip in with experience of manipulating AVPlayer at a lower level, i.e. with image processing/buffers (or iOS development that doesn't rest on external libraries), I would be incredibly interested to know how I could make a start.

Barde answered 22/10, 2015 at 16:21 Comment(2)
Can you elaborate what the problem in using GPUImage on tvOS is? From what I've seen, all the dependencies are supported on tvOS.Meuser
I have used AVPlayerlooper and my video is looping seamlessly. Found out about AVLooper in this answer: https://mcmap.net/q/139080/-looping-a-video-with-avfoundation-avplayerColonic
C
16

I had the same problem when streaming a video. After playing for the first time, there was a black screen when loading the video for second time. I got rid of the black screen by seeking video to 5ms ahead. It made nearly a seamless video loop. (Swift 2.1)

// Create player here..
let player = AVPlayer(URL: videoURL)

// Add notification block
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player.currentItem, queue: nil)
{ notification in
   let t1 = CMTimeMake(5, 100);
   player.seekToTime(t1)
   player.play()
}
Chelsae answered 16/3, 2016 at 15:1 Comment(0)
I
0

If the video is very short (a few seconds), you can probably extract each frame as CGImage and use CAKeyframeAnimation to animate it. I am using this technique to play GIF images on my app and the animation is very smooth.

Ionize answered 24/10, 2015 at 22:58 Comment(1)
Many thanks for your reply — as my footage is 1080p m4v (roughly 350 frames), this approach is taking up too much memory...Barde
B
0

You mention that you looked at AVAnimator, but did you see my blog post on this specific subject of seamless looping? I specifically built seamless looping logic in because it could not be done properly with AVPlayer and the H.264 hardware.

Backsight answered 25/10, 2015 at 22:36 Comment(3)
Thanks for replying! I did indeed read your blogpost, and was by no means attempting to bring down your amazing library, but I just could not get it to work with a high-quality 10 second clip of footage that is 30MB when encoded as H.264. I spent many hours trying to create an .mvid file that was smaller than 100MB (was 1GB or more), and when trying to directly import H.264 like in your walking clip example, the app would essentially crash from processing... Is there a way to use AVAnimator with 1080p m4v footage that doesn't result in huge Apple Animation format files? Thanks!Barde
Well, over 1 GB of video data is going to be a whole lot of IO and CPU processing time. It would be possible to process that much data on the CPU, but it might not actually be the "best" approach considering the load time involved. There are new classes in the 3.0 release called AVAnimatorOpenGLView and AVAssetFrameDecoder that can make use of a hardware optimized render path that uses CoreVideo under the covers, but honestly, even that will likely not work for your full HD video source. What you may need to consider is a custom solution to generate a long H.264 that loops say 10 or 20 times.Backsight
So, I ended up thinking of a way to implement seamless H.264 looping at full HD sizes of 1920x1080. This example shows how the new VideoToolbox hardware encoder and decoder APIs can be used to generate keyframes from the original .mp4 and use those to display a seamless looping animation at 24BPP. It takes a little time to transcode the frames, but then it loops without a glitch. Enjoy: github.com/mdejong/H264SeamlessLoopingBacksight
I
0

I use two AVPlayerItems with the same AVAsset in an AVQueuePlayer and switch the items:

 weak var w = self
 NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: nil, queue: nil) { (notification) -> Void in
        let queuePlayer = w!.playerController.player! as! AVQueuePlayer
        if(queuePlayer.currentItem == playerItem1) {
            queuePlayer.insertItem(playerItem2, afterItem: nil)
            playerItem1.seekToTime(kCMTimeZero)
        } else {
            queuePlayer.insertItem(playerItem1, afterItem: nil)
            playerItem2.seekToTime(kCMTimeZero)
        }
    }
Insignificant answered 1/12, 2015 at 21:29 Comment(2)
Thanks for this. I got this working but still have the same delay. Did it remove the delay for you?Straus
If it helps anyone: This same pattern (with a few additions) is implemented in iOS / tvOS 10 with AVPlayerLooper: https://mcmap.net/q/139080/-looping-a-video-with-avfoundation-avplayerStraus

© 2022 - 2024 — McMap. All rights reserved.