148

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 には重大な制限があるため、使用していません。一度に複数のビデオ ストリームを再生できるようにしたい。

4

20 に答える 20

283

プレイヤーが終了すると通知を受け取ることができます。小切手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)
    }
}

Swift 4+

@objc func playerItemDidReachEnd(notification: Notification) {
    if let playerItem = notification.object as? AVPlayerItem {
        playerItem.seek(to: CMTime.zero, completionHandler: nil)
    }
}
于 2011-03-19T22:29:29.120 に答える
78

それが役立つ場合、iOS / tvOS 10 には、ビデオのシームレスなループを作成するために使用できる新しい AVPlayerLooper() があります (Swift):

player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()    

これは、WWDC 2016 の「Advances in AVFoundation Playback」で発表されました: https://developer.apple.com/videos/play/wwdc2016/503/

このコードを使用しても、Apple にバグ レポートを提出し、次の応答を得るまで問題が発生しました。

ムービーの長さがオーディオ/ビデオ トラックよりも長いムービー ファイルが問題です。FigPlayer_File は、オーディオ トラックの編集がムービーの長さよりも短いため、ギャップレス トランジションを無効にしています (15.682 対 15.787)。

ムービーの長さとトラックの長さが同じになるようにムービー ファイルを修正するか、AVPlayerLooper の時間範囲パラメーターを使用する必要があります (時間範囲を 0 からオーディオ トラックの長さに設定します)。

Premiere は、ビデオとはわずかに異なる長さのオーディオ トラックを含むファイルをエクスポートしていたことが判明しました。私の場合、オーディオを完全に削除しても問題はなく、問題は解決しました。

于 2016-07-08T16:12:52.103 に答える
28

スウィフトでは:

プレーヤーが終了したときに通知を受け取ることができます... 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)
    }
}

Swift3

NotificationCenter.default.addObserver(self,
    selector: #selector(PlaylistViewController.playerItemDidReachEnd),
     name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
     object: avPlayer?.currentItem)

これにより、ムービーが巻き戻されます。

プレーヤーをリリースするときは、通知を登録解除することを忘れないでください。

于 2015-05-01T20:45:40.040 に答える
21

一時停止の問題を防ぐために私がやったことは次のとおりです。

迅速:

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必要ないので使用しませんでした。

于 2014-10-16T10:08:37.380 に答える
3

AVQueuePlayer を使用して動画をシームレスにループすることをお勧めします。通知オブザーバーを追加する

AVPlayerItemDidPlayToEndTimeNotification

そのセレクターで、ビデオをループします

AVPlayerItem *video = [[AVPlayerItem alloc] initWithURL:videoURL];
[self.player insertItem:video afterItem:nil];
[self.player play];
于 2014-04-03T17:35:17.033 に答える
3

ビデオが巻き戻されるときのギャップを避けるために、コンポジションで同じアセットの複数のコピーを使用するとうまくいきました。ここで見つけました: 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];
于 2014-12-17T12:24:33.163 に答える
0

ビデオを 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;
    }

実装ファイル内のView Controllerのインターフェース宣言で:

id _notificationToken;

試してみる前に、これが稼働していることを確認する必要がありますか? このサンプル アプリをダウンロードして実行します。

https://developer.apple.com/library/prerelease/ios/samplecode/AVBasicVideoOutput/Listings/AVBasicVideoOutput_APLViewController_m.html#//apple_ref/doc/uid/DTS40013109-AVBasicVideoOutput_APLViewController_m-DontLinkElementID_8

このコードを使用する私のアプリでは、ビデオの最後と最初の間に一時停止はまったくありません。実際、ビデオによっては、タイムコード表示を保存して、ビデオが最初にあることを再び伝える方法がありません。

于 2016-01-26T01:16:25.383 に答える
-1

コードの下で AVPlayerViewController を使用してください。

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

すべてのコントロールが表示されます。お役に立てば幸いです

于 2016-05-03T10:00:11.793 に答える