gpt4 book ai didi

ios - 如何控制 AVAssetWriter 以正确的 FPS 写入

转载 作者:技术小花猫 更新时间:2023-10-29 11:24:09 26 4
gpt4 key购买 nike

让我看看我是否理解正确。

在目前最先进的硬件上,iOS 允许我以以下 fps 进行录制:30、60、120 和 240。

但是这些 fps 的行为不同。如果我以 30 或 60 fps 拍摄,我希望以这些 fps 拍摄创建的视频文件分别以 30 和 60 fps 播放。

但如果我以 120 或 240 fps 拍摄,我希望以这些 fps 拍摄创建的视频文件以 30 fps 播放,否则我将看不到慢动作。

几个问题:

  1. 我说得对吗?
  2. 有没有办法分别以 120 或 240 fps 的帧率拍摄并分别以 120 和 240 fps 的帧率播放?我的意思是在没有慢动作的情况下以 fps 播放视频?
  3. 写入文件时如何控制帧率?

我正在像这样创建 AVAssetWriter 输入...

  NSDictionary *videoCompressionSettings = @{AVVideoCodecKey                  : AVVideoCodecH264,
AVVideoWidthKey : @(videoWidth),
AVVideoHeightKey : @(videoHeight),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
AVVideoMaxKeyFrameIntervalKey : @(1)}
};

_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];

并且没有明显的方法来控制它。

注意:我在 1 所在的位置尝试了不同的数字。我试过 1.0/fps,我试过 fps,我已经删除了 key 。没有区别。

这就是我设置 `AVAssetWriter 的方式:

  AVAssetWriter *newAssetWriter = [[AVAssetWriter alloc] initWithURL:_movieURL fileType:AVFileTypeQuickTimeMovie
error:&error];

_assetWriter = newAssetWriter;
_assetWriter.shouldOptimizeForNetworkUse = NO;

CGFloat videoWidth = size.width;
CGFloat videoHeight = size.height;

NSUInteger numPixels = videoWidth * videoHeight;
NSUInteger bitsPerSecond;

// Assume that lower-than-SD resolutions are intended for streaming, and use a lower bitrate
// if ( numPixels < (640 * 480) )
// bitsPerPixel = 4.05; // This bitrate matches the quality produced by AVCaptureSessionPresetMedium or Low.
// else
NSUInteger bitsPerPixel = 11.4; // This bitrate matches the quality produced by AVCaptureSessionPresetHigh.

bitsPerSecond = numPixels * bitsPerPixel;

NSDictionary *videoCompressionSettings = @{AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(videoWidth),
AVVideoHeightKey : @(videoHeight),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond)}
};

if (![_assetWriter canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo]) {
NSLog(@"Couldn't add asset writer video input.");
return;
}

_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoCompressionSettings
sourceFormatHint:formatDescription];
_assetWriterVideoInput.expectsMediaDataInRealTime = YES;

NSDictionary *adaptorDict = @{
(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
(id)kCVPixelBufferWidthKey : @(videoWidth),
(id)kCVPixelBufferHeightKey : @(videoHeight)
};

_pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
initWithAssetWriterInput:_assetWriterVideoInput
sourcePixelBufferAttributes:adaptorDict];


// Add asset writer input to asset writer
if (![_assetWriter canAddInput:_assetWriterVideoInput]) {
return;
}

[_assetWriter addInput:_assetWriterVideoInput];

captureOutput 方法非常简单。我从过滤器中获取图像并使用以下方法将其写入文件:

if (videoJustStartWriting)
[_assetWriter startSessionAtSourceTime:presentationTime];

CVPixelBufferRef renderedOutputPixelBuffer = NULL;
OSStatus err = CVPixelBufferPoolCreatePixelBuffer(nil,
_pixelBufferAdaptor.pixelBufferPool,
&renderedOutputPixelBuffer);

if (err) return; // NSLog(@"Cannot obtain a pixel buffer from the buffer pool");

//_ciContext is a metal context
[_ciContext render:finalImage
toCVPixelBuffer:renderedOutputPixelBuffer
bounds:[finalImage extent]
colorSpace:_sDeviceRgbColorSpace];

[self writeVideoPixelBuffer:renderedOutputPixelBuffer
withInitialTime:presentationTime];


- (void)writeVideoPixelBuffer:(CVPixelBufferRef)pixelBuffer withInitialTime:(CMTime)presentationTime
{

if ( _assetWriter.status == AVAssetWriterStatusUnknown ) {
// If the asset writer status is unknown, implies writing hasn't started yet, hence start writing with start time as the buffer's presentation timestamp
if ([_assetWriter startWriting]) {
[_assetWriter startSessionAtSourceTime:presentationTime];
}
}

if ( _assetWriter.status == AVAssetWriterStatusWriting ) {
// If the asset writer status is writing, append sample buffer to its corresponding asset writer input

if (_assetWriterVideoInput.readyForMoreMediaData) {
if (![_pixelBufferAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:presentationTime]) {
NSLog(@"error", [_assetWriter.error localizedFailureReason]);
}
}
}

if ( _assetWriter.status == AVAssetWriterStatusFailed ) {
NSLog(@"failed");
}

}

我将整件事以 240 fps 的速度拍摄。这些是附加帧的呈现时间。

time ======= 113594.311510508
time ======= 113594.324011508
time ======= 113594.328178716
time ======= 113594.340679424
time ======= 113594.344846383

如果您对它们进行一些计算,您会发现帧速率约为 240 fps。因此,帧以正确的时间存储。

但是当我看视频时,运动不是慢动作,而是快时间说视频是 30 fps。

注意:此应用从相机抓取帧,帧进入 CIFilters,这些过滤器的结果被转换回存储到文件并显示在屏幕上的样本缓冲区。

最佳答案

我到了这里,但我认为这是你出错的地方。将您的视频捕获视为管道。

(1) Capture buffer -> (2) Do Something With buffer -> (3) Write buffer as frames in video.

听起来您已经成功完成了 (1) 和 (2),您获得缓冲区的速度足够快并且正在处理它们,以便您可以将它们作为帧出售。

几乎可以肯定问题出在 (3) 写入视频帧中。

https://developer.apple.com/reference/avfoundation/avmutablevideocomposition

检查您的 AVMutableComposition 中的 frameDuration 设置,您需要像 CMTime(1, 60)//60FPS 或 CMTime(1, 240)//240FPS 这样的东西来获得您想要的(告诉视频写入这么多帧并以此速率编码)。

使用 AVAssetWriter,原理完全相同,但您将帧速率设置为 AVAssetWriterInput outputSettings 中的一个属性,添加了 AVVideoExpectedSourceFrameRateKey。

NSDictionary *videoCompressionSettings = @{AVVideoCodecKey                  : AVVideoCodecH264,
AVVideoWidthKey : @(videoWidth),
AVVideoHeightKey : @(videoHeight),
AVVideoExpectedSourceFrameRateKey : @(60),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
AVVideoMaxKeyFrameIntervalKey : @(1)}
};

进一步扩展 - 您无法严格控制或同步您的相机捕捉到输出/回放速率,时间不能那样工作,也不那么准确,当然还有处理管道增加开销。当您捕获帧时,它们带有时间戳,您已经看到了这一点,但在写入/压缩阶段,它仅使用它需要的帧来生成为合成指定的输出。

它是双向的,你可以只捕获 30 FPS 并以 240 FPS 输出,视频会显示正常,你只是有很多帧“丢失”并被算法填充。你甚至可以每秒只输出 1 帧并以 30FPS 播放,这两者是相互独立的(我捕获的速度与每秒显示的帧数和呈现的内容的速度)

至于如何以不同的速度播放它,你只需要调整播放速度 - 根据需要减慢它。

如果您正确设置了时基 (frameDuration),它将始终“正常”播放 - 您告诉它“播放是每秒 X 帧”,当然,您的眼睛可能会注意到差异(几乎可以肯定在低 FPS 和高 FPS 之间),并且屏幕可能不会刷新那么高(高于 60FPS),但无论视频将以其时基的“正常”1X 速度。通过放慢视频速度,如果我的时基是 120,我将它减慢到 0.5 倍,我知道有效地看到 60FPS,一秒的播放需要两秒。

您可以通过设置 AVPlayer 的速率属性来控制播放速度 https://developer.apple.com/reference/avfoundation/avplayer

关于ios - 如何控制 AVAssetWriter 以正确的 FPS 写入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43365266/

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