在目前最先进的硬件上,iOS允许我以下列fps进行录制:30,60,120和240.
但这些fps表现不同.如果我以30或60 fps拍摄,我希望通过这些fps拍摄创建的视频文件分别以30和60 fps播放.
但是如果我以120或240 fps的速度拍摄,我希望以这些fps拍摄的视频文件以30 fps的速度播放,否则我将看不到慢动作.
几个问题:
>我是对的吗?
>有没有办法以120或240 fps的速度分别以120和240 fps的速度进行拍摄?我的意思是在没有慢动作的情况下拍摄视频的fps?
>我在编写文件时如何控制该帧速率?
我正在创建这样的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,我已经删除了密钥.没有不同.
这就是我设置`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,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.311510508time ======= 113594.324011508time ======= 113594.328178716time ======= 113594.340679424time ======= 113594.344846383
如果你在它们之间进行一些计算,你会发现帧速率约为240 fps.因此帧以正确的时间存储.
但是,当我观看视频时,动作不是慢动作,快速时间表示视频是30 fps.
注意:此应用程序从相机抓取帧,帧进入CIF过滤器,这些过滤器的结果将转换回存储到文件并显示在屏幕上的样本缓冲区.
解决方法 我到达这里,但我认为这是你出错的地方.将您的视频捕获视为管道.(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,它的原理完全相同,但您将帧速率设置为AVAsetWriterinput outputSettings中添加AVVIDeoExpectedSourceFrameRateKey的属性.
NSDictionary *vIDeoCompressionSettings = @{AVVIDeoCodecKey : AVVIDeoCodecH264,AVVIDeoExpectedSourceFrameRateKey : @(60),AVVIDeoMaxKeyFrameIntervalKey : @(1)} };
要进一步扩展 – 你不能严格控制或同步你的摄像头捕获精确到输出/播放速率,时间只是不这样工作,并不是那么精确,当然处理管道增加了开销.当您捕获帧时,它们会被标记为时间戳,但是在写入/压缩阶段,它只使用它所需的帧来生成为合成指定的输出.
它有两种方式,你只能捕获30 FPS并以240 FPS写出,视频显示正常,你只需要很多帧“丢失”并被算法填充.你甚至可以每秒只卖1帧,然后以30FPS回放,两者相互分开(我多快捕捉到多少帧和我每秒出现的帧数)
至于如何以不同的速度播放它,你只需要调整播放速度 – 根据需要减慢播放速度.
如果你已经正确设置时基(frameDuration),它将始终播放“正常” – 你告诉它“回放是每秒X帧”,当然,你的眼睛可能会注意到差异(几乎可以肯定)低FPS和高FPS),屏幕可能无法刷新到那么高(60FPS以上),但无论视频的时基是多少都是“正常”的1倍速.通过减慢视频速度,如果我的时基为120,我将其减慢到.5x,我知道有效地看到60FPS,一秒钟的播放需要两秒钟.
您可以通过在AVPlayer https://developer.apple.com/reference/avfoundation/avplayer上设置rate属性来控制播放速度
总结以上是内存溢出为你收集整理的ios – 如何控制AVAssetWriter以正确的FPS写入全部内容,希望文章能够帮你解决ios – 如何控制AVAssetWriter以正确的FPS写入所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)