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.

Community
  • 1
  • 1
Sarreph
  • 1,986
  • 2
  • 19
  • 41
  • Can you elaborate what the problem in using GPUImage on tvOS is? From what I've seen, all the dependencies are supported on tvOS. – thomers Nov 05 '15 at 16:42
  • I have used `AVPlayerlooper` and my video is looping seamlessly. Found out about AVLooper in this answer: https://stackoverflow.com/a/38271221/7698092 – Awais Fayyaz Aug 31 '22 at 09:52

4 Answers4

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()
}
m.etka
  • 405
  • 4
  • 10
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.

Satoshi Nakajima
  • 1,863
  • 18
  • 29
  • Many thanks for your reply — as my footage is 1080p m4v (roughly 350 frames), this approach is taking up too much memory... – Sarreph Oct 29 '15 at 15:12
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.

MoDJ
  • 4,309
  • 2
  • 30
  • 65
  • 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! – Sarreph Oct 29 '15 at 15:08
  • 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. – MoDJ Oct 29 '15 at 21:43
  • 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: https://github.com/mdejong/H264SeamlessLooping – MoDJ Apr 14 '16 at 18:51
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)
        }
    }
whatever0010011
  • 455
  • 4
  • 11
  • Thanks for this. I got this working but still have the same delay. Did it remove the delay for you? – Nabha Cosley Feb 08 '16 at 06:12
  • 2
    If it helps anyone: This same pattern (with a few additions) is implemented in iOS / tvOS 10 with AVPlayerLooper: http://stackoverflow.com/a/38271221/192120 – Nabha Cosley Jul 08 '16 at 16:16