使用 AVFoundation 在视频之间快速切换

发布于 2024-12-04 09:44:35 字数 2180 浏览 0 评论 0原文

我正在编写一个应用程序,用户可以在其中录制最多 6 个视频剪辑,每个视频剪辑的持续时间为 2 秒。录制视频剪辑后,用户可以使用 6 个按钮播放它们 - 每个剪辑一个。然后,用户可以通过在 6 个剪辑之间切换来录制电影。问题是,当用户按下按钮时,我需要在 6 个剪辑之间进行近乎瞬时的切换 - 否则播放剪辑的错觉就会丢失 - 该功能有点类似于 App Store 中名为 CamBox 的应用程序。

我首先尝试在每次用户按下按钮时使用 AVPlayer 中 AvPlayerItem 中的 AVAsset 初始化每个剪辑。播放器的输出指向我主视图中的 AVPlayerLayer。问题在于加载和开始播放所需的时间相当长,这意味着当用户快速连续按下按钮时视频会出现滞后。

我决定尝试使用 5 个 AVPlayer 和 5 个 AVPlayerLayers 预加载所有剪辑。 5 个 PlayerLayers 被插入到我的主视图中,当用户按下按钮时,当前播放的 AVPlayer 会暂停并快退,并且当前可见的 AVPlayerLayer 会被隐藏。新的 AVPlayer 启动并显示相应的 AVPlayerLayer。它工作得很好,比我的第一个解决方案快得多,虽然不是即时的,但问题是我只能预加载 4 个剪辑,这意味着当用户按下播放最后两个剪辑的按钮时,它会滞后很长时间。下面是我预加载剪辑的代码

-(void)loadVideos
{
  layers = [[NSMutableArray alloc] initWithCapacity:6];
  players = [[NSMutableArray alloc] initWithCapacity:6];

  for(int i = 1; i < 7; i++)
  {
      NSURL* fileURL = [NSURL fileURLWithPath:[self getFileName:i]];        
      AVPlayerItem* avPlayerItem = [[[AVPlayerItem alloc] initWithURL:fileURL] autorelease];
      [avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil];   

      AVPlayer *avPlayer = [[[AVPlayer alloc] initWithPlayerItem:avPlayerItem] autorelease];

      [avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];   
      [avPlayer addObserver:self forKeyPath:@"currentItem" options:0 context:nil];   
      AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
      layer.frame = self.playerView.bounds;
      [playerView.layer addSublayer:layer];
      [layers addObject:layer];
      [players addObject:avPlayer];
      layer.hidden = YES;
  }    
}

6 个按钮的事件处理程序如下所示:

- (IBAction)takeBtnClicked:(id)sender {
int tag = ((UIButton*)sender).tag;
AVPlayer* player;
AVPlayerLayer* layer;
if (layerIndex > -1) {
    player = [players objectAtIndex:layerIndex];
    layer = [layers objectAtIndex:layerIndex];
    [player pause];
    layer.hidden = YES;
    [player seekToTime:kCMTimeZero];
}
layerIndex = tag-1;
player = [players objectAtIndex:layerIndex];
layer = [layers objectAtIndex:layerIndex];
[player play];
layer.hidden = NO;    
}

我很确定 4 个预加载视频剪辑的限制是硬件限制,但是还有什么其他选择吗?有人有什么想法吗? 提前致谢。

I'm writing an application where the user can record up to 6 video clips each with a duration of 2 seconds. When the video clips are recorded the user can play with them using 6 buttons - one for each clip. The user can then record a movie by switching between the 6 clips. The problem is that I need near instantaneous switching between the 6 clips when the user presses a button - otherwise the illusion of playing with the clips is lost - the functionality is somewhat similar to the app called CamBox in the App Store.

I first tried initializing every clip with and AVAsset in an AvPlayerItem in an AVPlayer every time the user pressed a button. The output of the player was directed at a an AVPlayerLayer in my main view. The problem is that the time it takes to load and start playing is quite long, meaning the the video lags when the user presses the buttons in rapid succession.

I the decided to try to preload all the clips using 5 AVPlayers and 5 AVPlayerLayers. The 5 PlayerLayers are inserted into my main view and when the user presses a button the currently playing AVPlayer is paused and rewound and the the currently visible AVPlayerLayer is hidden. The new AVPlayer is started and the corresponding AVPlayerLayer is shown. It works pretty ok being much faster than my first solution although not instantaneous but the problem is that I can only preload 4 clips meaning than when the user presses the button that play the last two the it lags big time. Below is my code to preload the clips

-(void)loadVideos
{
  layers = [[NSMutableArray alloc] initWithCapacity:6];
  players = [[NSMutableArray alloc] initWithCapacity:6];

  for(int i = 1; i < 7; i++)
  {
      NSURL* fileURL = [NSURL fileURLWithPath:[self getFileName:i]];        
      AVPlayerItem* avPlayerItem = [[[AVPlayerItem alloc] initWithURL:fileURL] autorelease];
      [avPlayerItem addObserver:self forKeyPath:@"status" options:0 context:nil];   

      AVPlayer *avPlayer = [[[AVPlayer alloc] initWithPlayerItem:avPlayerItem] autorelease];

      [avPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];   
      [avPlayer addObserver:self forKeyPath:@"currentItem" options:0 context:nil];   
      AVPlayerLayer* layer = [AVPlayerLayer playerLayerWithPlayer:avPlayer];
      layer.frame = self.playerView.bounds;
      [playerView.layer addSublayer:layer];
      [layers addObject:layer];
      [players addObject:avPlayer];
      layer.hidden = YES;
  }    
}

The event handler for the 6 buttons looks like this:

- (IBAction)takeBtnClicked:(id)sender {
int tag = ((UIButton*)sender).tag;
AVPlayer* player;
AVPlayerLayer* layer;
if (layerIndex > -1) {
    player = [players objectAtIndex:layerIndex];
    layer = [layers objectAtIndex:layerIndex];
    [player pause];
    layer.hidden = YES;
    [player seekToTime:kCMTimeZero];
}
layerIndex = tag-1;
player = [players objectAtIndex:layerIndex];
layer = [layers objectAtIndex:layerIndex];
[player play];
layer.hidden = NO;    
}

I'm prette sure that the limitation of 4 preloaded video clips is a hardware limitation, but what is the alternative. Does anybody have any ideas?
Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

谁的年少不轻狂 2024-12-11 09:44:35

请参阅我的答案 iphone-smooth-transition-from-一个视频到另一个,它展示了一个可用于实现此逻辑的库以及一个带有 3 个启动动画剪辑的按钮的示例应用程序。每个剪辑还具有相关的声音效果。

See my answer for iphone-smooth-transition-from-one-video-to-another, it shows a library you can use to implement this logic and an example app with 3 buttons that kick off animated clips. Each clip also has an associated sound effect.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文