2023-07-04-ios-ying-bianh265xie-wen-jian-he-xin-dai-ma

69 阅读1分钟

最近在做WebRTC支持H265的工作,第一步首先是要编码出H265码流,整理下iOS硬编码回调里写H265文件核心代码:

`
// VideoToolbox 硬编回调- (void)frameWasEncoded:(OSStatus)status                  flags:(VTEncodeInfoFlags)infoFlags           sampleBuffer:(CMSampleBufferRef)sampleBuffer      codecSpecificInfo:(id)codecSpecificInfo                  width:(int32_t)width                 height:(int32_t)height           renderTimeMs:(int64_t)renderTimeMs              timestamp:(uint32_t)timestamp               rotation:(RTCVideoRotation)rotation {    // encode error    if(status != noErr) {        NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil];        NSLog(@"H264: H265 vtH265CallBack failed with %@", error);        NSLog(@"XDXHardwareEncoder : H265 encode frame failured! %s" ,error.debugDescription.UTF8String);        return;    }    if (!CMSampleBufferDataIsReady(sampleBuffer)) {        NSLog(@"didCompressH265 data is not ready ");        return;    }    if (infoFlags == kVTEncodeInfo_FrameDropped) {        NSLog(@"%s with frame dropped.", __FUNCTION__);        return;    }    BOOL isKeyframe = false;    CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false);    if(attachments != NULL) {        CFDictionaryRef attachment =(CFDictionaryRef)CFArrayGetValueAtIndex(attachments, 0);        CFBooleanRef dependsOnOthers = (CFBooleanRef)CFDictionaryGetValue(attachment, kCMSampleAttachmentKey_DependsOnOthers);        isKeyframe = (dependsOnOthers == kCFBooleanFalse);    }    if(isKeyframe) {        CMFormatDescriptionRef format     = CMSampleBufferGetFormatDescription(sampleBuffer);        static uint8_t *vpsspsppsNALBuff  = NULL;        static size_t  vpsSize, spsSize, ppsSize;        size_t parmCount;        const uint8_t *vps, *sps, *pps;        CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 0, &vps, &vpsSize, &parmCount, 0);        CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 1, &sps, &spsSize, &parmCount, 0);        CMVideoFormatDescriptionGetHEVCParameterSetAtIndex(format, 2, &pps, &ppsSize, &parmCount, 0);        vpsspsppsNALBuff = (uint8_t*)malloc(vpsSize+4+spsSize+4+ppsSize+4);        memcpy(vpsspsppsNALBuff, "\x00\x00\x00\x01", 4);        memcpy(&vpsspsppsNALBuff[4], vps, vpsSize);        memcpy(&vpsspsppsNALBuff[4+vpsSize], "\x00\x00\x00\x01", 4);        memcpy(&vpsspsppsNALBuff[4+vpsSize+4], sps, spsSize);        memcpy(&vpsspsppsNALBuff[4+vpsSize+4+spsSize], "\x00\x00\x00\x01", 4);        memcpy(&vpsspsppsNALBuff[4+vpsSize+4+spsSize+4], pps, ppsSize);        NSLog(@"XDXHardwareEncoder : H265 vpsSize : %zu, spsSize : %zu, ppsSize : %zu",vpsSize,spsSize, ppsSize);                fwrite(vpsspsppsNALBuff, vpsSize+4+spsSize+4+ppsSize+4, 1, H265_test_file);    }    size_t   blockBufferLength;    uint8_t  *bufferDataPointer = NULL;    CMBlockBufferRef block = CMSampleBufferGetDataBuffer(sampleBuffer);    CMBlockBufferGetDataPointer(block, 0, NULL, &blockBufferLength, (char **)&bufferDataPointer);    size_t bufferOffset = 0;    size_t startCodeLength = 4;    char startCode[4] = {0x00, 0x00, 0x00, 0x01};    while (bufferOffset < blockBufferLength - startCodeLength) {        uint32_t NALUnitLength = 0;        memcpy(&NALUnitLength, bufferDataPointer+bufferOffset, startCodeLength);        NALUnitLength = CFSwapInt32BigToHost(NALUnitLength);        memcpy(bufferDataPointer+bufferOffset, startCode, startCodeLength);        bufferOffset += startCodeLength + NALUnitLength;    }    fwrite(bufferDataPointer, blockBufferLength, 1, H265_test_file);}

`