gpt4 book ai didi

iphone - 在视频之间快速切换的正确方法

转载 作者:可可西里 更新时间:2023-11-01 03:08:39 25 4
gpt4 key购买 nike

我正在创建一个基于外部事件显示特定视频的应用程序,这可能需要播放视频快速更改 - 每秒一次或更多。但是,视频之间不能有间隙或滞后。

最好的方法是什么?只有四个视频,每个大约两兆字节。

我正在考虑创建四个 MPMoviePlayerControllers,并将它们的 View 添加到主视图但隐藏,并通过暂停和隐藏当前视频进行切换,然后取消隐藏并播放下一个视频。有没有更优雅的解决方案?

编辑

这里有一些关于我的确切情况的更多信息:

  • 不同的视频帧共享大部分相同的像素 - 因此在切换过程中帧停留是可以的,但出现黑帧则不行。
  • 每个视频只有十秒左右,而且只有四个视频。一般的状态转移是1<->2<->3<->4->1。
  • 视频播放应与同步 AVAudioRecorder 录制兼容。据我所知,MPMoviePlayerController 不兼容。

最佳答案

您需要设置和预缓冲所有视频流以避免打嗝,所以我认为您的多个 MPMoviePlayerController 解决方案并不过分。

但是,该特定解决方案可能存在问题,因为每个电影播放器​​都有自己的 UI。 UI 彼此不同步,因此一个可能会显示控制栏,另一个则不会;一个可能处于全屏模式等。在它们之间切换会导致视觉不连续。

既然听起来您的视频切换不一定是用户启动的,我猜您不太关心标准视频播放器 UI。

我建议深入底层,AV Foundation。理论上,您可以为每个视频创建一个 AVPlayerItem。这是一个没有 UI 开销的流管理对象,因此非常适合您正在做的事情。然后您可以——同样,理论上——创建一个 AVPlayer 和一个 AVPlayerLayer 来处理显示。当您想从一个 AVPlayerItem 流切换到另一个时,您可以调用 AVPlayer 的 replaceCurrentItemWithPlayerItem: 消息来换出数据流。

我做了一点test project (GitHub) 来验证这一点,不幸的是,直接的解决方案并不完美。没有视频流故障,但在从 AVPlayer 到 AVPlayer 的转换中,表示层似乎以适合下一部电影的大小短暂地闪现上一部电影的最后一帧。它似乎有助于为每部电影分配单独的 AVPlayer 对象,并在它们之间切换到一个恒定的播放器层。似乎仍然有瞬间闪过的背景,但至少这是一个微妙的缺陷。这是代码的要点:

@interface ViewController : UIViewController
{
NSMutableArray *players;
AVPlayerLayer *playerLayer;
}

@property (nonatomic) IBOutlet UIView *videoView;

- (IBAction) selectVideo:(id)sender;

@end

@implementation ViewController

@synthesize videoView;

- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *videoTitles = [NSArray arrayWithObjects:@"Ultimate Dog Tease",
@"Backin Up", @"Herman Cain", nil];
players = [NSMutableArray array];
for (NSString *title in videoTitles) {
AVPlayerItem *player = [AVPlayer playerWithURL:[[NSBundle mainBundle]
URLForResource:title withExtension:@"mp4"]];
[player addObserver:self forKeyPath:@"status" options:0 context:nil];
[players addObject:player];
}
playerLayer = [AVPlayerLayer playerLayerWithPlayer:[players objectAtIndex:0]];
playerLayer.frame = self.videoView.layer.bounds;
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[self.videoView.layer addSublayer:playerLayer];
}

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
[object removeObserver:self forKeyPath:@"status"];
for (AVPlayer *player in players) {
if (player.status != AVPlayerStatusReadyToPlay) {
return;
}
}
// All videos are ready to go
[self playItemAtIndex:0];
}

- (void) playItemAtIndex:(NSUInteger)idx
{
AVPlayer *newPlayer = [players objectAtIndex:idx];
if (newPlayer != playerLayer.player) {
[playerLayer.player pause];
playerLayer.player = newPlayer;
}
[newPlayer play];
}

- (IBAction) selectVideo:(id)sender
{
[self playItemAtIndex:((UILabel *)sender).tag];
}

@end

一半的代码只是为了观察播放器的状态,并确保在所有视频都被缓冲之前不会开始播放。

分配三个独立的 AVPlayerLayers(除了三个 AVPlayer)可以防止任何类型的闪烁。不幸的是,连接到未显示的 AVPlayerLayer 的 AVPlayer 似乎假定它不需要维护视频缓冲区。层之间的每次切换都会产生短暂的视频断断续续。所以这不好。

使用 AV Foundation 时需要注意的几件事是:

1) AVPlayer 对象没有对循环播放的内置支持。您必须观察当前视频的结尾并手动寻找时间为零。

2) 除了视频帧之外根本没有任何 UI,但我再次猜测这可能对您来说实际上是一个优势。

关于iphone - 在视频之间快速切换的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9608265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com