Spa*_*Dog 10 avfoundation ios avassetwriter
让我看看我是否理解正确.
在目前最先进的硬件上,iOS允许我以下列fps进行录制:30,60,120和240.
但这些fps表现不同.如果我以30或60 fps拍摄,我希望通过这些fps拍摄创建的视频文件分别以30和60 fps播放.
但是如果我以120或240 fps的速度拍摄,我希望以这些fps拍摄的视频文件以30 fps的速度播放,否则我将看不到慢动作.
几个问题:
我正在创建像这样的AVAssetWriter输入......
NSDictionary *videoCompressionSettings = @{AVVideoCodecKey : AVVideoCodecH264,
AVVideoWidthKey : @(videoWidth),
AVVideoHeightKey : @(videoHeight),
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(bitsPerSecond),
AVVideoMaxKeyFrameIntervalKey : @(1)}
};
_assetWriterVideoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoCompressionSettings];
Run Code Online (Sandbox Code Playgroud)
并没有明显的方法来控制它.
注意:我尝试了不同的数字1
.我试过1.0/fps
,我试过fps
,我已经删除了密钥.没有不同.
这就是我设置`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];
Run Code Online (Sandbox Code Playgroud)
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");
}
}
Run Code Online (Sandbox Code Playgroud)
我把整个东西以240 fps的速度拍摄.这些是附加帧的呈现时间.
time ======= 113594.311510508
time ======= 113594.324011508
time ======= 113594.328178716
time ======= 113594.340679424
time ======= 113594.344846383
Run Code Online (Sandbox Code Playgroud)
如果你在它们之间进行一些计算,你会发现帧速率约为240 fps.因此,帧以正确的时间存储.
但是,当我观看视频时,动作不是慢动作,快速时间表示视频是30 fps.
注意:此应用程序从相机抓取帧,帧进入CIF过滤器,这些过滤器的结果将转换回样本缓冲区,该缓冲区存储到文件并显示在屏幕上.
我正在到达这里,但我认为这是你出错的地方。将您的视频捕获视为一个管道。
(1) Capture buffer -> (2) Do Something With buffer -> (3) Write buffer as frames in video.
Run Code Online (Sandbox Code Playgroud)
听起来您已经成功完成了 (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)}
};
Run Code Online (Sandbox Code Playgroud)
再扩展一点——你不能严格控制或同步你的相机捕捉到输出/播放速率,时间只是不能那样工作,也不是那么精确,当然处理管道会增加开销。当您捕获帧时,它们带有时间戳,您已经看到了,但在写入/压缩阶段,它仅使用生成为合成指定的输出所需的帧。
它是双向的,您只能捕获 30 FPS 并以 240 FPS 的速度输出,视频会显示正常,您只会有很多帧“丢失”并被算法填充。你甚至可以每秒只输出 1 帧并以 30FPS 播放,两者是相互独立的(我捕捉的速度与每秒呈现多少帧和呈现的内容)
至于如何以不同的速度播放,您只需要调整播放速度 - 根据需要放慢速度。
如果您正确设置了时基 (frameDuration),它将始终以“正常”播放 - 您告诉它“以每秒 X 帧的速度播放”,当然,您的眼睛可能会注意到差异(几乎可以肯定低 FPS 和高 FPS),并且屏幕可能不会刷新那么高(超过 60FPS),但无论如何视频都会以“正常”的 1 倍速度为其时基。通过减慢视频速度,如果我的时基是 120,我将它减慢到 0.5 倍,我知道可以有效地看到 60FPS,并且一秒钟的播放需要两秒钟。
您可以通过在 AVPlayer https://developer.apple.com/reference/avfoundation/avplayer上设置 rate 属性来控制播放速度
归档时间: |
|
查看次数: |
3464 次 |
最近记录: |