开发者

AVAssetWriterInput and readyForMoreMediaData

Is AVAssetWriterInput's readyForMoreMediaData updated in a background thread? If readyForMoreMediaData is NO, can I block in the main thread and wait until the value changes to YES?

I'm using an AVAssetWriterInput by pushing data to it (i.e. without using requestMediaDataWhenReadyOnQueue) and I've set expectsMediaDataInRealTime,开发者_开发百科 and 99.9% of the time I can just call appendSampleBuffer (or appendPixelBuffer) on it as fast as my app can generate frames.

This works fine unless you put the device (iPhone 3GS) to sleep for 15 minutes or so in the middle of an AVAssetWriter session. After waking up the device, appendPixelBuffer sometimes gets an error saying, "A pixel buffer cannot be appended when readyForMoreMediaData is NO". Hence my question - how best to respond to readyForMoreMediaData=NO and if I can just wait a bit in the main thread like so:

while ( ![assetWriterInput readyForMoreMediaData] )
{
    Sleep for a few milliseconds
}


Be careful not to just block the thread, here is what I was doing before that was not working:

while (adaptor.assetWriterInput.readyForMoreMediaData == FALSE) {
  [NSThread sleepForTimeInterval:0.1];
}

The above approach would fail sometimes on my iPad2. Doing this instead fixed the problem:

while (adaptor.assetWriterInput.readyForMoreMediaData == FALSE) {
  NSDate *maxDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
  [[NSRunLoop currentRunLoop] runUntilDate:maxDate];
}


Don't find something similar, so I left it here. Swift 4 solution. Would better using precise technique to solve that problem. F.e. using 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()
        }
    })
}

Next:

func grabFrame(time: CMTime? = nil) {
    readyForMediaCondition?.lock()
    while !pixelBufferInput!.assetWriterInput.isReadyForMoreMediaData {
        readyForMediaCondition?.wait()
    }
    readyForMediaCondition?.unlock()

    // append your framebuffer here
}

Don't forget to invalidate observer in the end

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
        }


Polling is not the advisable solution.

You should be using requestMediaDataWhenReadyOnQueue

[writerInput requestMediaDataWhenReadyOnQueue:mediaInputQueue usingBlock:^{
    [writerInput appendSampleBuffer:nextBuffer];
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜