在經歷了很多痛苦和痛苦之後,我終於設法使它工作。
我需要提供一個至少爲kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms
鍵值的CFDictionaryRef。這個鍵的值也必須是一個CFDictionaryRef。對於H264的類型,這是在CMVideoFormatDescriptionCreateFromH264ParameterSets
內部創建的,看起來像這樣:
avcC = <014d401e ffe10016 674d401e 9a660a0f ff350101 01400000 fa000013 88010100 0468ee3c 80>
然而,對於MPEG4類型,您需要自己創建這個。最終的結果應該是這樣的:
esds = <00000000 038081e6 00000003 8081e611 00000000 00000000 058081e5 060102>
我們創造這仍然是模糊的,以我的方式,但它在某種程度上工作。我受到this link的啓發。這是代碼:
- (CMFormatDescriptionRef)createFormatDescriptorFromMPEG4Message:(MessageContainer *)message {
CMVideoFormatDescriptionRef mediaDescriptor = NULL;
NSData *esdsData = [self newESDSFromData:message.frameData];
CFMutableDictionaryRef esdsDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(esdsDictionary, CFSTR("esds"), (__bridge const void *)(esdsData));
NSDictionary *dictionary = @{(__bridge NSString *)kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms : (__bridge NSDictionary *)esdsDictionary};
OSStatus status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault,
self.mediaCodec,
message.frameSize.width,
message.frameSize.height,
(__bridge CFDictionaryRef)dictionary,
&mediaDescriptor);
if (status) {
NSLog(@"CMVideoFormatDesciprionCreate failed with %zd", status);
}
return mediaDescriptor;
}
- (NSData *)newESDSFromData:(NSData *)data {
NSInteger dataLength = data.length;
int full_size = 3 + 5 + 13 + 5 + dataLength + 3;
// ES_DescrTag data + DecoderConfigDescrTag + data + DecSpecificInfoTag + size + SLConfigDescriptor
int config_size = 13 + 5 + dataLength;
int padding = 12;
int8_t *esdsInfo = calloc(full_size + padding, sizeof(int8_t));
//Version
esdsInfo[0] = 0;
//Flags
esdsInfo[1] = 0;
esdsInfo[2] = 0;
esdsInfo[3] = 0;
//ES_DescrTag
esdsInfo[4] |= 0x03;
[self addMPEG4DescriptionLength:full_size
toPointer:esdsInfo + 5];
//esid
esdsInfo[8] = 0;
esdsInfo[9] = 0;
//Stream priority
esdsInfo[10] = 0;
//DecoderConfigDescrTag
esdsInfo[11] = 0x03;
[self addMPEG4DescriptionLength:config_size
toPointer:esdsInfo + 12];
//Stream Type
esdsInfo[15] = 0x11;
//Buffer Size
esdsInfo[16] = 0;
esdsInfo[17] = 0;
//Max bitrate
esdsInfo[18] = 0;
esdsInfo[19] = 0;
esdsInfo[20] = 0;
//Avg bitrate
esdsInfo[21] = 0;
esdsInfo[22] = 0;
esdsInfo[23] = 0;
//< DecSpecificInfoTag
esdsInfo[24] |= 0x05;
[self addMPEG4DescriptionLength:dataLength
toPointer:esdsInfo + 25];
//SLConfigDescrTag
esdsInfo[28] = 0x06;
//Length
esdsInfo[29] = 0x01;
esdsInfo[30] = 0x02;
NSData *esdsData = [NSData dataWithBytes:esdsInfo length:31 * sizeof(int8_t)];
free(esdsInfo);
return esdsData;
}
- (void)addMPEG4DescriptionLength:(NSInteger)length
toPointer:(int8_t *)ptr {
for (int i = 3; i >= 0; i--) {
uint8_t b = (length >> (i * 7)) & 0x7F;
if (i != 0) {
b |= 0x80;
}
ptr[3 - i] = b;
}
}
消息容器是一個簡單的包裝圍繞從服務器接收到的數據:
@interface MessageContainer : NSObject
@property (nonatomic) CGSize frameSize;
@property (nonatomic) NSData *frameData;
@end
凡frameSize
是幀(從服務器分別接收到的)的尺寸和數據本身就是frameData
。
哦,它有助於我用快速解碼ios上的mpeg4,但只有第一幀!成功解碼第一幀後,我總是收到錯誤-12911 kVTVideoDecoderMalfunctionErr。你知道我有什麼可能是錯的嗎? – JULIIncognito
我很高興它有幫助。可悲的是,自從這個項目通過以來,我一直在努力,所以我不能真正幫助你。你可以嘗試爲每一幀創建'CFDictionaryRef',看看是否有效。然後,從那裏開始,找出可能出錯的地方。注意:我只需要在第一幀(這是一個關鍵幀)中執行此操作。 –
是的,這是要點:)我已經做到了每一幀,我的壞。現在它工作完美!謝謝 – JULIIncognito