在NSWindow上交换QTMovieView会导致闪烁

时间:2012-03-06 23:07:00

标签: cocoa synchronization quicktime qtkit

我想做的是:

  • 在一个屏幕上播放一部快速电影(prores或pjpg)(带音频)
  • 在另一个屏幕上播放另一个奴隶快速电影(prores或pjpg),与主人同步
  • 当我向左或向右按​​,循环播放不同的奴隶电影

这就是我所做的:

  • 为每个屏幕创建一个NSWindow
  • 创建一个QTMovies数组(实际上是每个屏幕的数组数组)
  • 创建一个QTMovieViews数组(实际上是每个屏幕的数组数组)
  • 通常扮演大师QTMovie
  • 设置NSTimer以从主电影时间更新当前从属电影时间
  • 如果按下某个键,则将窗口的内容视图交换到新的QTMovieView

我的完整代码位于http://codepad.org/gDsJLPAy

这一切都有效,但是当我切换视频时,我得到了切换到的视频旧帧的单帧闪光。即如果我运行应用程序50帧并切换到SlaveVideo2,我会看到SlaveVideo2帧0,然后它立即跳转到SlaveVideo2帧50并继续像往常一样。如果在20帧之后我切换回SlaveVideo1,我会看到SlaveVideo1帧50的一瞥,然后它跳转到SlaveVideo1帧70并继续照常进行。

我疯狂地试图解决这个问题。我尝试了各种刷新,显示方法但无济于事。关于如何解决这个问题的任何想法?

P.S。您可以在timerFireMethod中看到如果我一直更新所有从属电影(而不仅仅是活动电影),我就不会得到闪烁。显然这不是一个解决方案,因为我不断寻找大量的视频,这些视频太沉重而且没必要!

P.P.S。我已经尝试在Quartz Composer中重新创建设置,我得到了完全相同的问题。

我在10.7.3

1 个答案:

答案 0 :(得分:0)

为了档案,我会在这里发表我的结论。

我找不到这个问题的直接解决方案。如果从属电影暂停,当我使其视图处于活动状态时 - 即使我稍早开始播放电影 - 在变为可见时它首先显示旧帧。我找到的解决方法是始终保持电影播放(这很糟糕)。

然而我发现了这个 https://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieInternals/MTTimeSpace/B-Chapter/2MovieTimeandSpace.html

并通过在主电影上调用GetMovieTimeBase,并将SetTimeBaseMasterTimeBase应用于从属电影,它允许两部电影在后端同步播放,而无需手动使它们保持同步。因此整个同步代码可以简化为:

-(void)setLayerIndex:(int)i {
    // make sure target index is within bounds
    if(i<0) i=[[movies objectAtIndex:1] count]-1;
    else if(i>[[movies objectAtIndex:1] count]-1) i=0;

    // pause all slave views
    [[viewers objectAtIndex:1] makeObjectsPerformSelector:@selector(pause:) withObject:self];

    // save current index
    currentLayerIndex = i;

    // sync frame of new slave movie
    [[self currentSlaveMovie] setCurrentTime:[masterMovie currentTime]];

    // set windows view to QTView
    [[windows objectAtIndex:1] setContentView:[self currentSlaveView]];

    // set timebase of slave to timebase of master
    TimeBase masterTimeBase = GetMovieTimeBase([masterMovie quickTimeMovie]);
    TimeValue masterTimeScale = GetMovieTimeScale([masterMovie quickTimeMovie]);
    TimeRecord slaveZero;
    TimeValue slaveZeroTV = GetTimeBaseStartTime(masterTimeBase, masterTimeScale, &slaveZero); 
    SetMovieMasterTimeBase([[self currentSlaveMovie] quickTimeMovie], masterTimeBase, &slaveZero);    

    // play master movie
    [masterViewer play:self];

    // play slave movie
    [[self currentSlaveView] play:self];

}