最近在做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);} |