VideoToolBox解碼時,VTDecompressionSessionDecodeFrame
返回錯誤12902,kVTParameterErr = -12902
即參數錯誤,然後在VTDecompressionSessionInvalidate
的時候,就發現線程卡死掛起了
同樣操作VTDecompressionSessionWaitForAsynchronousFrames
也是一樣的,VTDecompressionSessionInvalidate
裏面也操作了VTDecompressionSessionWaitForAsynchronousFrames
CMItemCount count = CMSampleBufferGetNumSamples(sampleBuffer);
if (count > 0) {
//解碼
//向視頻解碼器提示使用低功耗模式是可以的
uint32_t decoder_flags = 0;
decoder_flags |= kVTDecodeFrame_EnableAsynchronousDecompression;
decoder_flags |= kVTDecodeFrame_1xRealTimePlayback;
//異步解碼
VTDecodeInfoFlags flagOut = kVTDecodeInfo_Asynchronous;
NSDate* currentTime = [NSDate date];
status = VTDecompressionSessionDecodeFrame(_decompressionSession, sampleBuffer, decoder_flags,
(void*)CFBridgingRetain(currentTime), &flagOut);
if (status == kVTInvalidSessionErr) {
GSLog(@"Video hard decode InvalidSessionErr status = %d ,nalutype : %d", (int)status,nalu_type);
} else if (status == kVTVideoDecoderBadDataErr) {
GSLog(@"Video hard decode BadData status = %d ,nalutype : %d", (int)status,nalu_type);
} else if (status != noErr) {
GSLog(@"Video hard decode failed status = %d , nalutype : %d", (int)status,nalu_type);
}
CFBridgingRelease((__bridge CFTypeRef _Nullable)(currentTime));
}else {
GSLog(@"sampleBuffer items == 0");
}
然後釋放的時候就卡死了
VTDecompressionSessionInvalidate(oldsession);
CFRelease(oldsession);
這裏附上IJKPlayer
的寫法
if (context->vt_session) {
VTDecompressionSessionWaitForAsynchronousFrames(context->vt_session);
VTDecompressionSessionInvalidate(context->vt_session);
CFRelease(context->vt_session);
context->vt_session = NULL;
}
這裏防止卡死我把它放在另一個線程去做了
if (self->_decompressionSession) {
VTDecompressionSessionRef oldsession = self->_decompressionSession;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//爲防止sesssion在invalidate卡死線程的casem,我們在另外一個線程去執行,就算卡死也不會影響我們的解碼線程或者主線程
NSLog(@"Video Decompression Invalidate session BEGIN");
VTDecompressionSessionInvalidate(oldsession);
CFRelease(oldsession);
NSLog(@"Video Decompression Invalidate session DONE");
});
self->_decompressionSession = NULL;
}
這是相關的堆棧,拷貝的別人的
Apple could fix the bug of VTDecompressionSessionInvalidate API. Here is the stack:
0 libsystem_kernel.dylib 0x0000000184905150 __psynch_cvwait + 8
1 libsystem_pthread.dylib 0x0000000184a1ad40 _pthread_cond_wait$VARIANT$mp + 640
2 CoreMedia 0x0000000187ec44f8 WaitOnCondition + 16
3 CoreMedia 0x0000000187ec4440 FigSemaphoreWaitRelative + 168
4 ************ 0x000000018840b0d8 VTDecompressionSessionRemote_WaitForAsynchronousFrames + 120
5 ************ 0x000000018840aeb8 VTDecompressionSessionRemote_Invalidate + 88
6 ************ 0x00000001883b1e44 VTDecompressionSessionInvalidate + 52
7 XXXXX 0x0000000102a21094 -[hw264decoder releasedecoder] + 3641492 (XXXXXX.m:221)
追根溯源發現收到的naluType
類型爲31
,31: Unspecified (non-VCL)
是不是還沒用的類型嗎,我也不知道怎麼會收到這個,還是數據源錯誤,打包成CMSampleBuffer
給VideoToolBox
也就出問題了,在接收到nalutype
的時候,過濾掉了31
類型,解決了這個bug,如果你也有遇到這種問題,看看是不是nalutype的問題吧,或者數據源不對。
發現使用AVSampleBufferDisplayerlayer
的時候,也有同樣的現象
CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);
相關文章:
- VTDecompressionSessionInvalidate hangs on iOS 11
大概意思就是傳入的CMSampleBuffer裏面的數量爲空,他判斷下數量不爲空再傳入。即上面CMItemCount count = CMSampleBufferGetNumSamples(sampleBuffer);
的代碼 - VTDecompressionSessionDecodeFrame hangs during applicationDidEnterBackground
再者就是VTDecompressionSessionInvalidate放在另一個線程,不卡死當前線程,也是治標不治本
學習不斷,有錯誤請指出,如果對你有幫助,請點個👍