VTDecompressionSessionInvalidate線程卡死掛起導致的解碼問題

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類型爲3131: Unspecified (non-VCL)是不是還沒用的類型嗎,我也不知道怎麼會收到這個,還是數據源錯誤,打包成CMSampleBufferVideoToolBox也就出問題了,在接收到nalutype的時候,過濾掉了31類型,解決了這個bug,如果你也有遇到這種問題,看看是不是nalutype的問題吧,或者數據源不對。

發現使用AVSampleBufferDisplayerlayer的時候,也有同樣的現象

CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES);
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);
CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue);

相關文章:

  1. VTDecompressionSessionInvalidate hangs on iOS 11
    大概意思就是傳入的CMSampleBuffer裏面的數量爲空,他判斷下數量不爲空再傳入。即上面CMItemCount count = CMSampleBufferGetNumSamples(sampleBuffer);的代碼
  2. VTDecompressionSessionDecodeFrame hangs during applicationDidEnterBackground
    再者就是VTDecompressionSessionInvalidate放在另一個線程,不卡死當前線程,也是治標不治本

學習不斷,有錯誤請指出,如果對你有幫助,請點個👍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章