// 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 = -;
uint8_t *data = NULL;
uint8_t *pps = NULL;
uint8_t *sps = NULL;
int startCodeIndex = ;
int secondStartCodeIndex = ;
int thirdStartCodeIndex = ;
long blockLength = ;
CMSampleBufferRef sampleBuffer = NULL;
CMBlockBufferRef blockBuffer = NULL;
int nalu_type = (frame[startCodeIndex + ] & 0x1F);
if (nalu_type != && _formatDesc == NULL)
{
NSLog(@"Video error: Frame is not an I Frame and format description is null");
return -;
}
if (nalu_type == )
{
// NSLog(@"=================================================");
// for (int i = 0; i<frameSize; i++) {
// printf(" %x",frame[i]);
// }
for (int i = startCodeIndex + ; i < startCodeIndex + ; i++)
{
if (frame[i] == 0x00 && frame[i+] == 0x00 && frame[i+] == 0x00 && frame[i+] == 0x01)
{
secondStartCodeIndex = i;
_spsSize = secondStartCodeIndex;
break;
}
}
nalu_type = (frame[secondStartCodeIndex + ] & 0x1F);
}
if(nalu_type == )
{
for (int i = _spsSize + ; i < _spsSize + ; i++)
{
if (frame[i] == 0x00 && frame[i+] == 0x00 && frame[i+] == 0x00 && frame[i+] == 0x01)
{
thirdStartCodeIndex = i;
_ppsSize = thirdStartCodeIndex - _spsSize;
break;
}
}
sps = malloc(_spsSize - );
pps = malloc(_ppsSize - );
memcpy (sps, &frame[], _spsSize-);
memcpy (pps, &frame[_spsSize+], _ppsSize-);
uint8_t* parameterSetPointers[] = {sps, pps};
size_t parameterSetSizes[] = {_spsSize-, _ppsSize-};
status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, ,
(const uint8_t *const*)parameterSetPointers,
parameterSetSizes, ,
&_formatDesc);
if(status != noErr){
NSLog(@"MVideoFormatDescriptionCreateFromH264ParameterSets ERROR type: %d", (int)status);
}
nalu_type = (frame[thirdStartCodeIndex + ] & 0x1F);
}
if(nalu_type == )
{
int offset = _spsSize + _ppsSize;
blockLength = frameSize - offset;
data = malloc(blockLength);
data = memcpy(data, &frame[offset], blockLength);
uint32_t dataLength32 = htonl (blockLength - );
memcpy (data, &dataLength32, sizeof (uint32_t));
status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
blockLength,
kCFAllocatorNull, NULL,
,
blockLength,
, &blockBuffer);
if(status != noErr){
NSLog(@"I Frame: CMBlockBufferCreateWithMemoryBlock Error type: %d", (int)status);
}
}
if (nalu_type == )
{
blockLength = frameSize;
data = malloc(blockLength);
data = memcpy(data, &frame[], blockLength);
uint32_t dataLength32 = htonl (blockLength - );
memcpy (data, &dataLength32, sizeof (uint32_t));
status = CMBlockBufferCreateWithMemoryBlock(NULL, data,
blockLength,
kCFAllocatorNull, NULL,
,
blockLength,
, &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, , , NULL, ,
&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, );
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 ;
}
@end