CMTime 和 AVFoundation 中单帧的移动

发布于 2024-11-16 16:51:07 字数 665 浏览 2 评论 0原文

我正在尝试使用 AVFoundation 播放视频。我使用以下代码作为将播放前进一帧的按钮。

它间歇性地工作,在某些执行中它会做正确的事情并前进一帧,但大多数时候我必须按按钮 3 或 4 次才能前进一帧。

这让我认为这是某种精度问题,但我无法弄清楚它是什么。每次运行时,新的 CMTime 似乎都会提前相同的量。

我的另一个理论是,这可能是由于 currentTime 没有以我的帧速率设置为精确的帧边界(由搜索视频引起)造成的。但我不知道如何以我的帧速率“捕捉”到最近的帧。

AVAssetTrack *videoTrack = ...;
Float64 frameRate = [videoTrack nominalFrameRate];

CMTime currentTime = [self.playerItem currentTime];
CMTime oneFrame = CMTimeMakeWithSeconds(1.0 / frameRate, currentTime.timescale);
CMTime added = CMTimeAdd(currentTime, oneFrame);

[self.player seekToTime:added toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

感谢您的帮助!

I'm attempting to play a video with AVFoundation. I am using the following code for a button that advances the playback by one frame.

It works intermittently, on some executions it will do the right thing and advance one frame, but most times I will have to press the button 3 or 4 times before it will advance a frame.

This makes me think it is some kind of precision issue, but I can't figure out what it is. Each time it is run the new CMTime appears to be advancing by the same amount.

My other theory is that it could be caused by the currentTime not being set to an exact frame boundary at my frame rate (caused by seeking through the video). But I don't know how to "snap" to the nearest frame at my frame rate.

AVAssetTrack *videoTrack = ...;
Float64 frameRate = [videoTrack nominalFrameRate];

CMTime currentTime = [self.playerItem currentTime];
CMTime oneFrame = CMTimeMakeWithSeconds(1.0 / frameRate, currentTime.timescale);
CMTime added = CMTimeAdd(currentTime, oneFrame);

[self.player seekToTime:added toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

Thanks for your help!

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

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

发布评论

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

评论(2

请持续率性 2024-11-23 16:51:07

这不是很明显(因为奇怪的是它只在 AVPlayerItem 中可用,而不是 AVPlayer),但如果 AVPlayerItem 对于 canStepForward/canStepBackward 返回 YES,那么你可以调用 stepByCount:(NSInteger)stepCount:< /code> 向前或向后移动一定数量的帧。

It isn't very obvious (since strangely it's only available in AVPlayerItem rather than AVPlayer) but if the AVPlayerItem returns YES for canStepForward/canStepBackward then you can call stepByCount:(NSInteger)stepCount: to move forwards or backwards by a certain number of frames.

夏天碎花小短裙 2024-11-23 16:51:07

您的问题的答案在第二行代码中,您从nominalFrameRate 中删除了“nominal”。

您的代码假设视频中的帧速率是恒定的。这是不正确的。

视频可以具有恒定的 fps,但并非必须如此。例如,如果您在可变的照明条件下使用手机拍摄电影,则帧曝光时间可能会发生变化,并且帧速率也会发生相反变化。

要“捕捉”到帧边界,您需要使用 AVAssetReader 来逐步浏览各个帧。每个帧都标有演示时间戳(即“t”),但如果您正在步进,那么这并不重要,除非您正在更新位置标记。

The answer to your question is in the second line of code where you remove the "nominal" from nominalFrameRate.

Your code assumes that the frame rate in your video is constant. This is incorrect.

A video can have a constant fps, but it doesn't have to. E.g. if you shoot a film with your phone in variable lighting conditions then the frame exposure time can change and your frame rate will vary inversely.

To "snap" to frame boundaries, you need to use an AVAssetReader to step through the individual frames. Each frame is tagged with a Presentation Time Stamp (its "t"), but if you're stepping that doesn't matter so much, unless you're updating a position marker.

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