AVAssetWriterInput 和readyForMoreMediaData

问题描述 投票:0回答:4

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
}
iphone ios4 iphone-sdk-3.0 avfoundation avassetwriter
4个回答
4
投票

小心不要阻塞线程,这是我在不起作用之前所做的:

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];
}

3
投票

找不到类似的东西,所以我把它留在这里。 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()

1
投票
        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
        }

0
投票

轮询不是明智的解决方案。

您应该使用 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.