AVAssetWriterInput的readyForMoreMediaData是否在后台线程中更新?如果readyForMoreMediaData为NO,我可以在主线程中阻塞并等待直到该值变为YES吗?
我通过将数据推送到 AVAssetWriterInput 来使用它(即不使用 requestMediaDataWhenReadyOnQueue),并且我设置了 ExpectsMediaDataInRealTime,并且 99.9% 的时间我可以在其上调用appendSampleBuffer(或appendPixelBuffer),速度与我的应用程序生成帧的速度一样快。
除非您在 AVAssetWriter 会话中将设备 (iPhone 3GS) 置于睡眠状态 15 分钟左右,否则这种方法工作正常。唤醒设备后,appendPixelBuffer 有时会收到错误消息:“当readyForMoreMediaData 为NO 时,无法附加像素缓冲区”。因此我的问题是如何最好地响应readyForMoreMediaData=NO以及我是否可以像这样在主线程中稍等一下:
while ( ![assetWriterInput readyForMoreMediaData] )
{
Sleep for a few milliseconds
}
小心不要阻塞线程,这是我在不起作用之前所做的:
while (adaptor.assetWriterInput.readyForMoreMediaData == FALSE) {
[NSThread sleepForTimeInterval:0.1];
}
上述方法在我的iPad2上有时会失败。这样做反而解决了问题:
while (adaptor.assetWriterInput.readyForMoreMediaData == FALSE) {
NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
[[NSRunLoop currentRunLoop] runUntilDate:maxDate];
}
找不到类似的东西,所以我把它留在这里。 Swift 4 解决方案。 最好使用精确的技术来解决这个问题。 F.e.使用 NSCondition:
func startRecording() {
// start recording code goes here
readyForMediaCondition = NSCondition()
readyForMediaObservation = pixelBufferInput?.assetWriterInput.observe(\.isReadyForMoreMediaData, options: .new, changeHandler: { [weak self](_, change) in
guard let isReady = change.newValue else {
return
}
if isReady {
self?.readyForMediaCondition?.lock()
self?.readyForMediaCondition?.signal()
self?.readyForMediaCondition?.unlock()
}
})
}
下一个:
func grabFrame(time: CMTime? = nil) {
readyForMediaCondition?.lock()
while !pixelBufferInput!.assetWriterInput.isReadyForMoreMediaData {
readyForMediaCondition?.wait()
}
readyForMediaCondition?.unlock()
// append your framebuffer here
}
最后不要忘记使观察者失效
readyForMediaObservation?.invalidate()
int waitTime = 300;
while (weakSelf.input.readyForMoreMediaData == NO) {
NSLog(@"readyForMoreMediaData is NO");
NSTimeInterval waitIntervale = 0.001 * waitTime;
NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:waitIntervale];
[[NSRunLoop currentRunLoop] runUntilDate:maxDate];
waitTime += 200; // add 200ms every time
}
轮询不是明智的解决方案。
您应该使用 requestMediaDataWhenReadyOnQueue
assetWriterInput.requestMediaDataWhenReady(on: serialQueue) { [weak self] in
guard let self = self else { return }
while self.assetWriterInput.isReadyForMoreMediaData {
// Copy the next sample buffer from source media.
guard let nextSampleBuffer = copyNextSampleBufferToWrite() else {
// Mark the input as finished.
self.assetWriterInput.markAsFinished()
break
}
// Append the sample buffer to the input.
self.assetWriterInput.append(nextSampleBuffer)
}
}