AVAssetWriter-设置自定义帧率

时间:2019-01-30 07:26:52

标签: ios swift avassetwriter avkit avassetwriterinput

我正在使用AVAssetWriter使用委托从ARSession写入视频帧。

func session(_ session: ARSession, didUpdate frame: ARFrame)

请参阅下面的用于写入图像的代码。

如何根据需要设置自定义帧频,例如24、30或60等。

在输出设置中,AVVideoExpectedSourceFrameRateKey的值是30。但是,我们给它指定的值是什么,用VLC播放器检查->媒体信息->编解码器详细信息

时,始终将“帧频”设为60。

我应该进行哪些更改以设置所需的帧频?预先感谢。

func writeImage(_ image: CVPixelBuffer, thisTimestamp: TimeInterval) {

        guard let videoDirector = videoWriter else { return }

        serialQueue.async(execute: {

            let scale = CMTimeScale(NSEC_PER_SEC)

            if (!self.seenTimestamps.contains(thisTimestamp)) {

                self.seenTimestamps.append(thisTimestamp)
                let pts = CMTime(value: CMTimeValue((thisTimestamp) * Double(scale)),
                                 timescale: scale)
                var timingInfo = CMSampleTimingInfo(duration: kCMTimeInvalid,
                                                    presentationTimeStamp: pts,
                                                    decodeTimeStamp: kCMTimeInvalid)

                var vidInfo:CMVideoFormatDescription! = nil
                CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, image, &vidInfo)

                var sampleBuffer:CMSampleBuffer! = nil
                CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, image, true, nil, nil, vidInfo, &timingInfo, &sampleBuffer)

                let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!

                if self.videoWriterInput == nil {

                    let width = CVPixelBufferGetWidth(imageBuffer)
                    let height = CVPixelBufferGetHeight(imageBuffer)


                    let numPixels: Double = Double(width * height);
                    let bitsPerPixel = 11.4;
                    let bitsPerSecond = Int(numPixels * bitsPerPixel)

                    // add video input
                    let outputSettings: [String: Any] = [
                        AVVideoCodecKey : AVVideoCodecType.h264,
                        AVVideoWidthKey : width,
                        AVVideoHeightKey : height,
                        AVVideoCompressionPropertiesKey : [
                            AVVideoExpectedSourceFrameRateKey: 30,
                            AVVideoAverageBitRateKey : bitsPerSecond,
                            AVVideoMaxKeyFrameIntervalKey : 1
                        ]
                    ]
                    self.videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: outputSettings)
                    self.videoWriterInput?.expectsMediaDataInRealTime = true
                    guard let input = self.videoWriterInput else { return }

                    if videoDirector.canAdd(input) {
                        videoDirector.add(input)
                    }
                    videoDirector.startWriting()
                }

                let writable = self.canWrite()
                if writable, self.sessionAtSourceTime == nil {
                    let timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
                    self.sessionAtSourceTime = timeStamp
                    videoDirector.startSession(atSourceTime: timeStamp)
                }

                if self.videoWriterInput?.isReadyForMoreMediaData == true {
                    let appendResult = self.videoWriterInput?.append(sampleBuffer)
                    if appendResult == false {
                        printDebug("writer status: \(videoDirector.status.rawValue)")
                        printDebug("writer error: \(videoDirector.error.debugDescription)")
                    }
                }
            }
        })
    }
    func canWrite() -> Bool {
        return isRecording && videoWriter?.status == .writing
    }

1 个答案:

答案 0 :(得分:0)

从Apple支持部门回复:

如果要使用AVAssetWriter实际更改电影的帧速率,则必须在写入每个视频帧时正确设置它们的时间戳。

一种方法是使用AVAssetWriterInputPixelBufferAdaptor对象。例如,您使用AVAssetWriterInputPixelBufferAdaptor将打包为CVPixelBuffer对象的视频样本附加到单个AVAssetWriterInput对象。

初始化代码如下:

Id  |  Name      | 
------------------
101 |  Health    |
102 |  Education |
103 |  Sport     |
104 |  Family    |
105 |  Culture   |

...

[dictionary setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString*) kCVPixelBufferPixelFormatTypeKey];

然后,要为新电影指定某个回放帧速率(例如15 fps),则应将时间戳记(表示为CMTime结构)指定为相隔1/15秒。这是一个代码段:

AVAssetWriterInputPixelBufferAdaptor *avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:dictionary];

另一种替代方法是使用CMSampleBufferCreateCopyWithNewTiming对缓冲区重新计时,然后将其传递给AVAssetWriter。这是一个粗略的轮廓:

CMTime frameTime = CMTimeMake(1, 15);
result = [avAdaptor appendPixelBuffer:buffer withPresentationTime:frameTime];

//////////

我尝试使用“ CMSampleBufferCreateCopyWithNewTiming”。 FPS设置正确。但是得到了慢动作输出。以下是我的代码。

CMSampleTimingInfo sampleTimingInfo = {0};
CMSampleBufferRef newBuffer = NULL;

CMSampleBufferGetSampleTimingInfo(existingSampleBuffer, 0, &sampleTimingInfo);

sampleTimingInfo.duration = CMTimeMake(1, 30) // Specify new frame rate.
sampleTimingInfo.presentationTimeStamp =          CMTimeAdd(previousPresentationTimeStamp, sampleTimingInfo.duration);
previousPresentationTimeStamp = sampleTimingInfo.presentationTimeStamp;

OSStatus status = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, existingSampleBuffer, 1, &sampleTimingInfo, &newBuffer);

if (status == noErr) {
/* Write your newBuffer here */
}