// H264HWDecoder.m // H264EncoderDecoder // // Created by lujunjie on 2016/11/28. // Copyright © 2016年 陆俊杰. All rights reserved. // #import "H264HWDecoder.h" @implementation H264HWDecoder - (void)dealloc { if(self.decompressionSession != NULL){ VTDecompressionSessionInvalidate(self.decompressionSession); CFRelease(self.decompressionSession); self.decompressionSession=NULL; } } - (int)DecodeH264Frames:(unsigned char *)frame withLength:(int)frameSize { OSStatus status = -1; uint8_t *data = NULL; uint8_t *pps = NULL; uint8_t *sps = NULL; int startCodeIndex = 0; int secondStartCodeIndex = 0; int thirdStartCodeIndex = 0; long blockLength = 0; CMSampleBufferRef sampleBuffer = NULL; CMBlockBufferRef blockBuffer = NULL; int nalu_type = (frame[startCodeIndex + 4] & 0x1F); if (nalu_type != 7 && _formatDesc == NULL) { NSLog(@"Video error: Frame is not an I Frame and format description is null"); return -1; } if (nalu_type == 7) { // NSLog(@"================================================="); // for (int i = 0; i<frameSize; i++) { // printf(" %x",frame[i]); // } for (int i = startCodeIndex + 4; i < startCodeIndex + 256; i++) { if (frame[i] == 0x00 && frame[i+1] == 0x00 && frame[i+2] == 0x00 && frame[i+3] == 0x01) { secondStartCodeIndex = i; _spsSize = secondStartCodeIndex; break; } } nalu_type = (frame[secondStartCodeIndex + 4] & 0x1F); } if(nalu_type == 8) { for (int i = _spsSize + 4; i < _spsSize + 128; i++) { if (frame[i] == 0x00 && frame[i+1] == 0x00 && frame[i+2] == 0x00 && frame[i+3] == 0x01) { thirdStartCodeIndex = i; _ppsSize = thirdStartCodeIndex - _spsSize; break; } } sps = malloc(_spsSize - 4); pps = malloc(_ppsSize - 4); memcpy (sps, &frame[4], _spsSize-4); memcpy (pps, &frame[_spsSize+4], _ppsSize-4); uint8_t* parameterSetPointers[2] = {sps, pps}; size_t parameterSetSizes[2] = {_spsSize-4, _ppsSize-4}; status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, (const uint8_t *const*)parameterSetPointers, parameterSetSizes, 4, &_formatDesc); if(status != noErr){ NSLog(@"MVideoFormatDescriptionCreateFromH264ParameterSets ERROR type: %d", (int)status); } nalu_type = (frame[thirdStartCodeIndex + 4] & 0x1F); } if(nalu_type == 5 ) { int offset = _spsSize + _ppsSize; blockLength = frameSize - offset; data = malloc(blockLength); data = memcpy(data, &frame[offset], blockLength); uint32_t dataLength32 = htonl (blockLength - 4); memcpy (data, &dataLength32, sizeof (uint32_t)); status = CMBlockBufferCreateWithMemoryBlock(NULL, data, blockLength, kCFAllocatorNull, NULL, 0, blockLength, 0, &blockBuffer); if(status != noErr){ NSLog(@"I Frame: CMBlockBufferCreateWithMemoryBlock Error type: %d", (int)status); } } if (nalu_type == 1) { blockLength = frameSize; data = malloc(blockLength); data = memcpy(data, &frame[0], blockLength); uint32_t dataLength32 = htonl (blockLength - 4); memcpy (data, &dataLength32, sizeof (uint32_t)); status = CMBlockBufferCreateWithMemoryBlock(NULL, data, blockLength, kCFAllocatorNull, NULL, 0, blockLength, 0, &blockBuffer); if(status != noErr){ NSLog(@"P Frame: CMBlockBufferCreateWithMemoryBlock Error type: %d", (int)status); } } if(status == noErr) { const size_t sampleSize = blockLength; status = CMSampleBufferCreate(kCFAllocatorDefault, blockBuffer, true, NULL, NULL, _formatDesc, 1, 0, NULL, 1, &sampleSize, &sampleBuffer); if(status != noErr){ NSLog(@"CMSampleBufferCreate Error type: %d", (int)status); } } if(status == noErr) { CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, YES); CFMutableDictionaryRef dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(attachments, 0); CFDictionarySetValue(dict, kCMSampleAttachmentKey_DisplayImmediately, kCFBooleanTrue); if([self.updateDelegate respondsToSelector:@selector(updateDecodedSampleBuffer:)]){ [self.updateDelegate updateDecodedSampleBuffer:sampleBuffer]; } } if (data != NULL) { free (data); data = NULL; } if(sps != NULL) { free(sps); sps = NULL; } if(pps != NULL) { free(pps); pps = NULL; } return 0; } @end