0

I'm adding a subclassed CALayer onto video, and exporting using AVAssetExportSession, but am stumped on getting CABasicAnimation to work for a custom property. I started out with this approach: Core animation callback for progress

There's a "progress" property, that I scale from 0 to 1 using CABasicAnimation to match the timing of the video. On-screen, in a playerView with an AVSynchronizedLayer, "progress" gets updated, and everything is hunky dory. It works exactly as I'd expect.

On export, however, the CABasicAnimation for the progress parameter does not seem to update. I can set different "from" values for the animation, and the "progress" value is set to that for the first frame that gets rendered -- but never changes after that. I've checked the CALayer, as well as the model and presentation layers, and they all have the initial "from" value, each time a frame gets rendered.

If I attach other CABasicAnimation objects to my layer (e.g. scaling, position), they work as expected.

My overall flow goes a bit like this

  • AVMutableComposition gets created, with audio and video tracks inserted
  • Build a layer view hierarchy, attaching CABasicAnimation objects. One animation is for the "progress" parameter, and that's where the trouble is.
  • AVVideoCompositionCoreAnimationTool is created, to connect the video with the CA layers
  • AVAssetExportSession generates the video

Parameters related to stock animation key paths seem to be fine. The key path for "progress" does not seem to update. I'm suspecting that AVSynchronizedLayer does something for the on-screen updates, and that's not happening for the session export -- but I'm stumped as to what it is that I need to do.

My CALayer subclass implements needsDisplayForKey, and it does get checked for the "progress" key before the render starts -- so I think that the CABasicAnimation, and the rendering pipeline, are aware that "progress" should change.

    + (BOOL)needsDisplayForKey:(NSString*)key {
      if ([key isEqualToString:@"progress"])
        return YES;
      return [super needsDisplayForKey:key];
    }

My working theory is that AVVideoCompositionCoreAnimationTool sees the basic animation for my "progress" key path, sets things to the start value at the beginning of a render, and then does not update as the render goes along. And the reason it doesn't update? Because I'm dense, and have totally missed doing something important.

If there's an example along the lines of adding a time code overlay, that would great to look at. I don't think what I'm doing is that exotic, it works great on-screen, but I'm clearly missing some trick with the video export.

--

An update; still no progress on getting CABasicAnimation to work as expected for custom properties, and when exporting video to a file. There seems to be a lot of layer copying/remapping/etc, happening behind the scenes, and I'm sure I'm doing something wrong.

I've got a work-around now that gets the job done, but is a hack. I create an integer frame count property for the view object, and increment it each time the view gets redrawn. The video export is at 30 frames per second, so all I need to do to find out "when" the frame is, is to divide by the frame rate. As far as I can tell, the individual frames are rendered in a "timing perfect" universe, and then compression gets applied, so the actual playback rate may vary.

  • I'm struggling with the same issue. Have you ever find a real fix for that? – msmialko Oct 20 '21 at 11:42
  • No luck. I've put this on the back burner, because I had been making zero progress on it. The hack of counting frames is not great, but I don't have anything better. The infuriating thing is that there must be a correct way to do it that works -- and I'm guessing it's simple and clean. – Patrick H Madden Oct 21 '21 at 12:35
  • Ouch :< I submitted a Bug report to Apple. Will see if they respond. And perhaps I'll have a chance to ask about that during upcoming Tech Talks. – msmialko Oct 22 '21 at 10:27

0 Answers0