AVFoundation AVPlayer로 비디오를 루핑 하시겠습니까?
AVFoundation에서 비디오를 반복하는 비교적 쉬운 방법이 있습니까?
AVPlayer와 AVPlayerLayer를 다음과 같이 만들었습니다.
avPlayer = [[AVPlayer playerWithURL:videoUrl] retain];
avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];
avPlayerLayer.frame = contentView.layer.bounds;
[contentView.layer addSublayer: avPlayerLayer];
그런 다음 비디오를 다음과 같이 재생합니다.
[avPlayer play];
비디오는 정상적으로 재생되지만 끝에서 멈 춥니 다. MPMoviePlayerController를 사용하면 repeatMode
속성을 올바른 값으로 설정하기 만하면됩니다 . AVPlayer에 유사한 속성이없는 것 같습니다. 또한 영화가 끝났을 때 알려주는 콜백이 없어서 처음부터 다시 재생할 수 있습니다.
MPMoviePlayerController에는 몇 가지 심각한 제한이 있기 때문에 사용하지 않습니다. 여러 비디오 스트림을 한 번에 재생할 수 있기를 원합니다.
플레이어가 종료되면 알림을받을 수 있습니다. 검사AVPlayerItemDidPlayToEndTimeNotification
플레이어를 설정할 때 :
ObjC
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(playerItemDidReachEnd:)
name:AVPlayerItemDidPlayToEndTimeNotification
object:[avPlayer currentItem]];
이렇게하면 플레이어가 마지막에 일시 중지되지 않습니다.
알림에서 :
- (void)playerItemDidReachEnd:(NSNotification *)notification {
AVPlayerItem *p = [notification object];
[p seekToTime:kCMTimeZero];
}
영화를 되감습니다.
플레이어를 놓을 때 알림을 등록 취소하는 것을 잊지 마십시오.
빠른
avPlayer?.actionAtItemEnd = .none
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: avPlayer?.currentItem)
@objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: kCMTimeZero)
}
}
스위프트 4+
@objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: CMTime.zero, completionHandler: nil)
}
}
도움이된다면 iOS / tvOS 10에는 비디오의 매끄러운 반복 (Swift)을 만드는 데 사용할 수있는 새로운 AVPlayerLooper ()가 있습니다.
player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()
이것은 WWDC 2016에서 "AVFoundation 재생의 발전"에서 발표되었습니다 : https://developer.apple.com/videos/play/wwdc2016/503/
이 코드를 사용해도 Apple에 버그 보고서를 제출하고 다음과 같은 응답을 얻을 때까지 딸꾹질이있었습니다.
오디오 / 비디오 트랙보다 영화 지속 시간이 긴 영화 파일이 문제입니다. 오디오 플레이어 편집이 영화 재생 시간 (15.682 vs 15.787)보다 짧기 때문에 FigPlayer_File에서 끊김없는 전환을 비활성화하고 있습니다.
동영상 길이와 트랙 지속 시간이 동일한 길이를 갖도록 동영상 파일을 수정하거나 AVPlayerLooper의 시간 범위 매개 변수를 사용할 수 있습니다 (0에서 오디오 트랙의 지속 시간 설정)
Premiere에서 비디오와 길이가 약간 다른 오디오 트랙이있는 파일을 내보내고있는 것으로 나타났습니다. 필자의 경우 오디오를 완전히 제거하면 문제가 해결되었습니다.
에서 스위프트 :
플레이어가 종료되면 알림을받을 수 있습니다 ... AVPlayerItemDidPlayToEndTimeNotification 확인
플레이어를 설정할 때 :
avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "playerItemDidReachEnd:",
name: AVPlayerItemDidPlayToEndTimeNotification,
object: avPlayer.currentItem)
이렇게하면 플레이어가 마지막에 일시 중지되지 않습니다.
알림에서 :
func playerItemDidReachEnd(notification: NSNotification) {
if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem {
playerItem.seekToTime(kCMTimeZero)
}
}
스위프트 3
NotificationCenter.default.addObserver(self,
selector: #selector(PlaylistViewController.playerItemDidReachEnd),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: avPlayer?.currentItem)
영화를 되감습니다.
플레이어를 놓을 때 알림을 등록 취소하는 것을 잊지 마십시오.
다음은 일시 중지 딸꾹질 문제를 방지하기 위해 수행 한 작업입니다.
빠른:
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
object: nil,
queue: nil) { [weak self] note in
self?.avPlayer.seek(to: kCMTimeZero)
self?.avPlayer.play()
}
목표 C :
__weak typeof(self) weakSelf = self; // prevent memory cycle
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
[weakSelf.avPlayer seekToTime:kCMTimeZero];
[weakSelf.avPlayer play];
}];
참고 :avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone
필요 하지 않으므로 사용하지 않았습니다 .
AVQueuePlayer를 사용하여 비디오를 원활하게 반복하는 것이 좋습니다. 알림 관찰자 추가
AVPlayerItemDidPlayToEndTimeNotification
선택기에서 비디오를 반복
AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL];
[self.player insertItem:video afterItem:nil];
[self.player play];
비디오가 되 감길 때의 차이를 피하기 위해 컴포지션에 동일한 자산의 여러 사본을 사용하면 나에게 효과적이었습니다. 나는 그것을 여기에서 발견했다 : www.developers-life.com/avplayer-looping-video-without-hiccupdelays.html (링크가 죽었다).
AVURLAsset *tAsset = [AVURLAsset assetWithURL:tURL];
CMTimeRange tEditRange = CMTimeRangeMake(CMTimeMake(0, 1), CMTimeMake(tAsset.duration.value, tAsset.duration.timescale));
AVMutableComposition *tComposition = [[[AVMutableComposition alloc] init] autorelease];
for (int i = 0; i < 100; i++) { // Insert some copies.
[tComposition insertTimeRange:tEditRange ofAsset:tAsset atTime:tComposition.duration error:nil];
}
AVPlayerItem *tAVPlayerItem = [[AVPlayerItem alloc] initWithAsset:tComposition];
AVPlayer *tAVPlayer = [[AVPlayer alloc] initWithPlayerItem:tAVPlayerItem];
스위프트 3 & 4
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.avPlayer?.currentItem, queue: .main) { _ in
self.avPlayer?.seek(to: kCMTimeZero)
self.avPlayer?.play()
}
이것은 딸꾹질 문제없이 저에게 효과적이었습니다. 점은 seekToTime 메소드를 호출하기 전에 플레이어 를 일시 중지 시키는 것입니다.
init AVPlayer
let url = NSBundle.mainBundle().URLForResource("loop", withExtension: "mp4") let playerItem = AVPlayerItem(URL: url!) self.backgroundPlayer = AVPlayer(playerItem: playerItem) let playerLayer = AVPlayerLayer(player: self.backgroundPlayer) playerLayer.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) self.layer.addSublayer(playerLayer) self.backgroundPlayer!.actionAtItemEnd = .None self.backgroundPlayer!.play()
알림 등록
NSNotificationCenter.defaultCenter().addObserver(self, selector: "videoLoop", name: AVPlayerItemDidPlayToEndTimeNotification, object: self.backgroundPlayer!.currentItem)
videoLoop 기능
func videoLoop() { self.backgroundPlayer?.pause() self.backgroundPlayer?.currentItem?.seekToTime(kCMTimeZero) self.backgroundPlayer?.play() }
비디오를 AVPlayer에로드 한 후 (물론 AVPlayerItem을 통해) :
[self addDidPlayToEndTimeNotificationForPlayerItem:item];
addDidPlayToEndTimeNotificationForPlayerItem 메소드 :
- (void)addDidPlayToEndTimeNotificationForPlayerItem:(AVPlayerItem *)item
{
if (_notificationToken)
_notificationToken = nil;
/*
Setting actionAtItemEnd to None prevents the movie from getting paused at item end. A very simplistic, and not gapless, looped playback.
*/
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
_notificationToken = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:item queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// Simple item playback rewind.
[[_player currentItem] seekToTime:kCMTimeZero];
}];
}
viewWillDisappear 메소드에서 :
if (_notificationToken) {
[[NSNotificationCenter defaultCenter] removeObserver:_notificationToken name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
_notificationToken = nil;
}
In your view controller's interface declaration within the implementation file:
id _notificationToken;
Need to see this up-and-running before you try? Download and run this sample app:
In my app, which uses this very code, there is no pause whatsoever between the end of the video and the beginning. In fact, depending on the video, there's no way for me to tell the video is at the beginning again, save the timecode display.
you can add a AVPlayerItemDidPlayToEndTimeNotification observer and replay video from start in selector, code like below
//add observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification
object:_aniPlayer.currentItem];
-(void)playbackFinished:(NSNotification *)notification{
[_aniPlayer seekToTime:CMTimeMake(0, 1)];//replay from start
[_aniPlayer play];
}
my solution in objective-c wth AVQueuePlayer - it seems you have to duplicate the AVPlayerItem and upon finishing playback of first element instantly add another copy. "Kind of" makes sense and works for me without any hiccup
NSURL *videoLoopUrl;
// as [[NSBundle mainBundle] URLForResource:@"assets/yourVideo" withExtension:@"mp4"]];
AVQueuePlayer *_loopVideoPlayer;
+(void) nextVideoInstance:(NSNotification*)notif
{
AVPlayerItem *currItem = [AVPlayerItem playerItemWithURL: videoLoopUrl];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(nextVideoInstance:)
name:AVPlayerItemDidPlayToEndTimeNotification
object: currItem];
[_loopVideoPlayer insertItem:currItem afterItem:nil];
[_loopVideoPlayer advanceToNextItem];
}
+(void) initVideoPlayer {
videoCopy1 = [AVPlayerItem playerItemWithURL: videoLoopUrl];
videoCopy2 = [AVPlayerItem playerItemWithURL: videoLoopUrl];
NSArray <AVPlayerItem *> *dummyArray = [NSArray arrayWithObjects: videoCopy1, videoCopy2, nil];
_loopVideoPlayer = [AVQueuePlayer queuePlayerWithItems: dummyArray];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(nextVideoInstance:)
name: AVPlayerItemDidPlayToEndTimeNotification
object: videoCopy1];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(nextVideoInstance:)
name: AVPlayerItemDidPlayToEndTimeNotification
object: videoCopy2];
}
https://gist.github.com/neonm3/06c3b5c911fdd3ca7c7800dccf7202ad
The following is working for me in WKWebView in swift 4.1 The main part of the WKWebView in WKwebviewConfiguration
wkwebView.navigationDelegate = self
wkwebView.allowsBackForwardNavigationGestures = true
self.wkwebView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
wkwebView = WKWebView(frame: wkwebView.frame, configuration: config)
self.view.addSubview(wkwebView)
self.wkwebView.load(NSURLRequest(url: URL(string: self.getUrl())!) as URLRequest)
What I did is to make it loop playing, like my code below:
[player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0)
queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds([playerItem duration]);
if (current >= total) {
[[self.player currentItem] seekToTime:kCMTimeZero];
[self.player play];
}
}];
Swift 4.2 in Xcode 10.1.
Yes, there is a relatively easy way of looping a video in AVKit
/AVFoundation
using AVQueuePlayer()
, Key-Value Observation (KVO) technique and a token for it.
This definitely works for a bunch of H.264/HEVC videos with a minimal burden for CPU.
Here's a code:
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
private let player = AVQueuePlayer()
let clips = ["01", "02", "03", "04", "05", "06", "07"]
private var token: NSKeyValueObservation?
var avPlayerView = AVPlayerViewController()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
self.addAllVideosToPlayer()
present(avPlayerView, animated: true, completion: { self.player.play() })
}
func addAllVideosToPlayer() {
avPlayerView.player = player
for clip in clips {
let urlPath = Bundle.main.path(forResource: clip, ofType: "m4v")!
let url = URL(fileURLWithPath: urlPath)
let playerItem = AVPlayerItem(url: url)
player.insert(playerItem, after: player.items().last)
token = player.observe(\.currentItem) { [weak self] player, _ in
if self!.player.items().count == 1 { self?.addAllVideosToPlayer() }
}
}
}
}
use AVPlayerViewController below code, its working for me
let type : String! = "mp4"
let targetURL : String? = NSBundle.mainBundle().pathForResource("Official Apple MacBook Air Video YouTube", ofType: "mp4")
let videoURL = NSURL(fileURLWithPath:targetURL!)
let player = AVPlayer(URL: videoURL)
let playerController = AVPlayerViewController()
playerController.player = player
self.addChildViewController(playerController)
self.playView.addSubview(playerController.view)
playerController.view.frame = playView.bounds
player.play()
All controls to be showed, hope its helpful
/* "numberOfLoops" is the number of times that the sound will return to the beginning upon reaching the end.
A value of zero means to play the sound just once.
A value of one will result in playing the sound twice, and so on..
Any negative number will loop indefinitely until stopped.
*/
@property NSInteger numberOfLoops;
This property is already defined inside AVAudioPlayer
. Hope this can help you. I'm using Xcode 6.3.
참고URL : https://stackoverflow.com/questions/5361145/looping-a-video-with-avfoundation-avplayer
'IT story' 카테고리의 다른 글
`\ n`을 사용하여 HTML에서 줄 바꿈 (0) | 2020.06.22 |
---|---|
CSV / XLS를 JSON으로 변환 하시겠습니까? (0) | 2020.06.22 |
파이썬 : json.loads는 'u'로 시작하는 항목을 반환합니다. (0) | 2020.06.22 |
XML에서 RecyclerView app : layoutManager =“”를 설정하는 방법은 무엇입니까? (0) | 2020.06.22 |
mongodb에서 .bson 파일 형식을 가져 오는 방법 (0) | 2020.06.21 |