QGMP4Parser.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. // QGMP4Parser.m
  2. // Tencent is pleased to support the open source community by making vap available.
  3. //
  4. // Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  5. //
  6. // Licensed under the MIT License (the "License"); you may not use this file except in
  7. // compliance with the License. You may obtain a copy of the License at
  8. //
  9. // http://opensource.org/licenses/MIT
  10. //
  11. // Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. // either express or implied. See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #import "QGMP4Parser.h"
  16. #import "QGVAPLogger.h"
  17. #pragma mark - mp4 parser
  18. @interface QGMP4Parser() {
  19. QGMp4BoxDataFetcher _boxDataFetcher;
  20. }
  21. @property (nonatomic, strong) NSString *filePath;
  22. @end
  23. @implementation QGMP4Parser
  24. #pragma mark -- life cycle
  25. - (instancetype)initWithFilePath:(NSString *)filePath {
  26. if (self = [super init]) {
  27. _filePath = filePath;
  28. _fileHandle = [NSFileHandle fileHandleForReadingAtPath:_filePath];
  29. __weak __typeof(self) weakSelf = self;
  30. _boxDataFetcher = ^NSData *(QGMP4Box *box) {return [weakSelf readDataForBox:box];};
  31. }
  32. return self;
  33. }
  34. - (void)dealloc {
  35. [_fileHandle closeFile];
  36. }
  37. #pragma mark -- methods
  38. - (void)parse {
  39. if (!_filePath || !_fileHandle) {
  40. return ;
  41. }
  42. unsigned long long fileSize = [_fileHandle seekToEndOfFile];
  43. [_fileHandle seekToFileOffset:0];
  44. _rootBox = [QGMP4BoxFactory createBoxForType:QGMP4BoxType_unknown startIndex:0 length:fileSize];
  45. NSMutableArray *BFSQueue = [NSMutableArray new];
  46. [BFSQueue addObject:_rootBox];
  47. QGMP4Box *calBox = _rootBox;
  48. //长度包含包含类型码长度+本身长度
  49. while ((calBox = [BFSQueue firstObject])) {
  50. [BFSQueue removeObjectAtIndex:0];
  51. if (calBox.length <= 2*(kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes)) {
  52. //长度限制
  53. continue ;
  54. }
  55. unsigned long long offset = 0;
  56. unsigned long long length = 0;
  57. QGMP4BoxType type = QGMP4BoxType_unknown;
  58. //第一个子box
  59. offset = calBox.superBox ? (calBox.startIndexInBytes + kQGBoxSizeLengthInBytes + kQGBoxTypeLengthInBytes) : 0;
  60. //avcbox特殊处理
  61. if (calBox.type == QGMP4BoxType_avc1 || calBox.type == QGMP4BoxType_hvc1 || calBox.type == QGMP4BoxType_stsd) {
  62. unsigned long long avcOffset = calBox.startIndexInBytes+kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes;
  63. unsigned long long avcEdge = calBox.startIndexInBytes+calBox.length-kQGBoxSizeLengthInBytes-kQGBoxTypeLengthInBytes;
  64. unsigned long long avcLength = 0;
  65. QGMP4BoxType avcType = QGMP4BoxType_unknown;
  66. for (; avcOffset < avcEdge; avcOffset++) {
  67. readBoxTypeAndLength(_fileHandle, avcOffset, &avcType, &avcLength);
  68. if (avcType == QGMP4BoxType_avc1 || avcType == QGMP4BoxType_avcC || avcType == QGMP4BoxType_hvc1 || avcType == QGMP4BoxType_hvcC) {
  69. QGMP4Box *avcBox = [QGMP4BoxFactory createBoxForType:avcType startIndex:avcOffset length:avcLength];
  70. if (!calBox.subBoxes) {
  71. calBox.subBoxes = [NSMutableArray new];
  72. }
  73. [calBox.subBoxes addObject:avcBox];
  74. avcBox.superBox = calBox;
  75. [BFSQueue addObject:avcBox];
  76. offset = (avcBox.startIndexInBytes+avcBox.length);
  77. [self didParseBox:avcBox];
  78. break ;
  79. }
  80. }
  81. }
  82. do {
  83. //判断是否会越界
  84. if ((offset+kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes)>(calBox.startIndexInBytes+calBox.length)) {
  85. break ;
  86. }
  87. readBoxTypeAndLength(_fileHandle, offset, &type, &length);
  88. if ((offset+length)>(calBox.startIndexInBytes+calBox.length)) {
  89. //reach to super box end or not a box
  90. break ;
  91. }
  92. if (![QGMP4BoxFactory isTypeValueValid:type] && (offset == (calBox.startIndexInBytes + kQGBoxSizeLengthInBytes + kQGBoxTypeLengthInBytes))) {
  93. //目前的策略是
  94. break ;
  95. }
  96. QGMP4Box *subBox = [QGMP4BoxFactory createBoxForType:type startIndex:offset length:length];
  97. subBox.superBox = calBox;
  98. if (!calBox.subBoxes) {
  99. calBox.subBoxes = [NSMutableArray new];
  100. }
  101. //加入box节点
  102. [calBox.subBoxes addObject:subBox];
  103. //进入广度优先遍历队列
  104. [BFSQueue addObject:subBox];
  105. [self didParseBox:subBox];
  106. //继续兄弟box
  107. offset += length;
  108. } while(1);
  109. }
  110. [self didFinisheParseFile];
  111. }
  112. - (NSData *)readDataForBox:(QGMP4Box *)box {
  113. if (!box) {
  114. return nil;
  115. }
  116. [_fileHandle seekToFileOffset:box.startIndexInBytes];
  117. return [_fileHandle readDataOfLength:(NSUInteger)box.length];
  118. }
  119. - (NSInteger)readValue:(const char*)bytes length:(NSInteger)length {
  120. NSInteger value = 0;
  121. for (int i = 0; i < length; i++) {
  122. value += (bytes[i]&0xff)<<((length-i-1)*8);
  123. }
  124. return value;
  125. }
  126. #pragma mark -- private methods
  127. - (void)didParseBox:(QGMP4Box *)box {
  128. if ([box respondsToSelector:@selector(boxDidParsed:)]) {
  129. [box boxDidParsed:_boxDataFetcher];
  130. }
  131. if ([self.delegate respondsToSelector:@selector(didParseMP4Box:parser:)]) {
  132. [self.delegate didParseMP4Box:box parser:self];
  133. }
  134. }
  135. - (void)didFinisheParseFile {
  136. if ([self.delegate respondsToSelector:@selector(MP4FileDidFinishParse:)]) {
  137. [self.delegate MP4FileDidFinishParse:self];
  138. }
  139. }
  140. void readBoxTypeAndLength(NSFileHandle *fileHandle, unsigned long long offset, QGMP4BoxType *type, unsigned long long *length) {
  141. [fileHandle seekToFileOffset:offset];
  142. NSData *data = [fileHandle readDataOfLength:kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes];
  143. const char *bytes = data.bytes;
  144. *length = ((bytes[0]&0xff)<<24)+((bytes[1]&0xff)<<16)+((bytes[2]&0xff)<<8)+(bytes[3]&0xff);
  145. *type = ((bytes[4]&0xff)<<24)+((bytes[5]&0xff)<<16)+((bytes[6]&0xff)<<8)+(bytes[7]&0xff);
  146. }
  147. @end
  148. #pragma mark - parser proxy
  149. @interface QGMP4ParserProxy() <QGMP4ParserDelegate> {
  150. QGMP4Parser *_parser;
  151. }
  152. @end
  153. @implementation QGMP4ParserProxy
  154. - (instancetype)initWithFilePath:(NSString *)filePath {
  155. if (self = [super init]) {
  156. _parser = [[QGMP4Parser alloc] initWithFilePath:filePath];
  157. _parser.delegate = self;
  158. }
  159. return self;
  160. }
  161. - (NSInteger)picWidth {
  162. if (_picWidth == 0) {
  163. _picWidth = [self readPicWidth];
  164. }
  165. return _picWidth;
  166. }
  167. - (NSInteger)picHeight {
  168. if (_picHeight == 0) {
  169. _picHeight = [self readPicHeight];
  170. }
  171. return _picHeight;
  172. }
  173. - (NSInteger)fps {
  174. if (_fps == 0) {
  175. if (self.videoSamples.count == 0) {
  176. return 0;
  177. }
  178. _fps = lround(self.videoSamples.count/self.duration);
  179. }
  180. return _fps;
  181. }
  182. - (double)duration {
  183. if (_duration == 0) {
  184. _duration = [self readDuration];
  185. }
  186. return _duration;
  187. }
  188. - (NSArray *)videoSamples {
  189. if (_videoSamples) {
  190. return _videoSamples;
  191. }
  192. NSMutableArray *videoSamples = [NSMutableArray new];
  193. uint64_t tmp = 0;
  194. QGMP4SttsBox *sttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stts];
  195. QGMP4StszBox *stszBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsz];
  196. QGMP4StscBox *stscBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsc];
  197. QGMP4StcoBox *stcoBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stco];
  198. QGMP4CttsBox *cttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_ctts];
  199. uint32_t stscEntryIndex = 0;
  200. uint32_t stscEntrySampleIndex = 0;
  201. uint32_t stscEntrySampleOffset = 0;
  202. uint32_t sttsEntryIndex = 0;
  203. uint32_t sttsEntrySampleIndex = 0;
  204. uint32_t stcoChunkLogicIndex = 0;
  205. for (int i = 0; i < stszBox.sampleCount; ++i) {
  206. if (stscEntryIndex >= stscBox.entries.count ||
  207. sttsEntryIndex >= sttsBox.entries.count ||
  208. stcoChunkLogicIndex >= stcoBox.chunkOffsets.count) {
  209. break;
  210. }
  211. QGStscEntry *stscEntry = stscBox.entries[stscEntryIndex];
  212. QGSttsEntry *sttsEntry = sttsBox.entries[sttsEntryIndex];
  213. uint32_t sampleOffset = [stcoBox.chunkOffsets[stcoChunkLogicIndex] unsignedIntValue] + stscEntrySampleOffset;
  214. uint32_t ctts = 0;
  215. if (i < cttsBox.compositionOffsets.count) {
  216. ctts = [cttsBox.compositionOffsets[i] unsignedIntValue];
  217. }
  218. QGMP4Sample *sample = [QGMP4Sample new];
  219. sample.codecType = QGMP4CodecTypeVideo;
  220. sample.sampleIndex = i;
  221. sample.chunkIndex = stcoChunkLogicIndex;
  222. sample.sampleDelta = sttsEntry.sampleDelta;
  223. sample.sampleSize = [stszBox.sampleSizes[i] unsignedIntValue];
  224. sample.pts = tmp + ctts;
  225. sample.streamOffset = sampleOffset;
  226. [videoSamples addObject:sample];
  227. stscEntrySampleOffset += sample.sampleSize;
  228. tmp += sample.sampleDelta;
  229. stscEntrySampleIndex++;
  230. if (stscEntrySampleIndex >= stscEntry.samplesPerChunk) {
  231. if (stcoChunkLogicIndex + 1 < stcoBox.chunkOffsets.count) {
  232. stcoChunkLogicIndex++;
  233. }
  234. stscEntrySampleIndex = 0;
  235. stscEntrySampleOffset = 0;
  236. }
  237. sttsEntrySampleIndex++;
  238. if (sttsEntrySampleIndex >= sttsEntry.sampleCount) {
  239. sttsEntrySampleIndex = 0;
  240. if (sttsEntryIndex + 1 < sttsBox.entries.count) {
  241. sttsEntryIndex++;
  242. }
  243. }
  244. if (stscEntryIndex + 1 < stscBox.entries.count) {
  245. if (stcoChunkLogicIndex >= stscBox.entries[stscEntryIndex + 1].firstChunk - 1) {
  246. stscEntryIndex++;
  247. }
  248. }
  249. }
  250. _videoSamples = videoSamples;
  251. return _videoSamples;
  252. }
  253. - (NSArray *)videoSyncSampleIndexes {
  254. QGMP4StssBox *stssBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stss];
  255. return stssBox.syncSamples;
  256. }
  257. /**
  258. 调用该方法才会解析mp4文件并得到必要信息。
  259. */
  260. - (void)parse {
  261. [_parser parse];
  262. _rootBox = _parser.rootBox;
  263. // 解析视频解码配置信息
  264. [self parseVideoDecoderConfigRecord];
  265. }
  266. #pragma mark - Private
  267. - (void)parseVideoDecoderConfigRecord {
  268. if (self.videoCodecID == QGMP4VideoStreamCodecIDH264) {
  269. [self parseAvccDecoderConfigRecord];
  270. } else if (self.videoCodecID == QGMP4VideoStreamCodecIDH265) {
  271. [self parseHvccDecoderConfigRecord];
  272. }
  273. }
  274. - (void)parseAvccDecoderConfigRecord {
  275. self.spsData = [self parseAvccSPSData];
  276. self.ppsData = [self parseAvccPPSData];
  277. }
  278. - (void)parseHvccDecoderConfigRecord {
  279. NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_hvcC]];
  280. if (extraData.length <= 8) {
  281. return;
  282. }
  283. const char *bytes = extraData.bytes;
  284. int index = 30; // 21 + 4 + 4
  285. //int lengthSize = ((bytes[index++] & 0xff) & 0x03) + 1;
  286. int arrayNum = bytes[index++] & 0xff;
  287. // sps pps vps 种类数量
  288. for (int i = 0; i < arrayNum; i++) {
  289. int value = bytes[index++] & 0xff;
  290. int naluType = value & 0x3F;
  291. // sps pps vps 各自的数量
  292. int naluNum = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
  293. index += 2;
  294. for (int j = 0; j < naluNum; j++) {
  295. int naluLength = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
  296. index += 2;
  297. NSData *paramData = [NSData dataWithBytes:&bytes[index] length:naluLength];
  298. if (naluType == 32) {
  299. // vps
  300. self.vpsData = paramData;
  301. } else if (naluType == 33) {
  302. // sps
  303. self.spsData = paramData;
  304. } else if (naluType == 34) {
  305. // pps
  306. self.ppsData = paramData;
  307. }
  308. index += naluLength;
  309. }
  310. }
  311. }
  312. - (NSData *)parseAvccSPSData {
  313. //boxsize(32)+boxtype(32)+prefix(40)+预留(3)+spsCount(5)+spssize(16)+...+ppscount(8)+ppssize(16)+...
  314. NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_avcC]];
  315. if (extraData.length <= 8) {
  316. return nil;
  317. }
  318. const char *bytes = extraData.bytes;
  319. //sps数量 默认一个暂无使用
  320. //NSInteger spsCount = bytes[13]&0x1f;
  321. NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
  322. NSInteger naluType = (uint8_t)bytes[16]&0x1F;
  323. if (spsLength + 16 > extraData.length || naluType != 7) {
  324. return nil;
  325. }
  326. NSData *spsData = [NSData dataWithBytes:&bytes[16] length:spsLength];
  327. return spsData;
  328. }
  329. - (NSData *)parseAvccPPSData {
  330. NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_avcC]];
  331. if (extraData.length <= 8) {
  332. return nil;
  333. }
  334. const char *bytes = extraData.bytes;
  335. NSInteger spsCount = bytes[13]&0x1f;
  336. NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
  337. NSInteger prefixLength = 16 + spsLength;
  338. while (--spsCount > 0) {
  339. if (prefixLength+2 >= extraData.length) {
  340. return nil;
  341. }
  342. NSInteger nextSpsLength = ((bytes[prefixLength]&0xff)<<8)+bytes[prefixLength+1]&0xff;
  343. prefixLength += nextSpsLength;
  344. }
  345. //默认1个
  346. // NSInteger ppsCount = bytes[prefixLength]&0xff;
  347. if (prefixLength+3 >= extraData.length) {
  348. return nil;
  349. }
  350. NSInteger ppsLength = ((bytes[prefixLength+1]&0xff)<<8)+(bytes[prefixLength+2]&0xff);
  351. NSInteger naluType = (uint8_t)bytes[prefixLength+3]&0x1F;
  352. if (naluType != 8 || (ppsLength+prefixLength+3) > extraData.length) {
  353. return nil;
  354. }
  355. NSData *ppsData = [NSData dataWithBytes:&bytes[prefixLength+3] length:ppsLength];
  356. return ppsData;
  357. }
  358. - (NSInteger)readPicWidth {
  359. if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
  360. return 0;
  361. }
  362. QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
  363. NSInteger sizeIndex = 32;
  364. NSUInteger readLength = 2;
  365. QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
  366. [_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
  367. NSData *widthData = [_parser.fileHandle readDataOfLength:readLength];
  368. if (widthData.length < readLength) {
  369. return 0;
  370. }
  371. const char *bytes = widthData.bytes;
  372. NSInteger width = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
  373. return width;
  374. }
  375. - (NSInteger)readPicHeight {
  376. if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
  377. return 0;
  378. }
  379. QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
  380. NSInteger sizeIndex = 34;
  381. NSUInteger readLength = 2;
  382. QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
  383. [_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
  384. NSData *heightData = [_parser.fileHandle readDataOfLength:readLength];
  385. if (heightData.length < readLength) {
  386. return 0;
  387. }
  388. const char *bytes = heightData.bytes;
  389. NSInteger height = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
  390. return height;
  391. }
  392. - (double)readDuration {
  393. QGMP4MvhdBox *mdhdBox = [self.rootBox subBoxOfType:QGMP4BoxType_mvhd];
  394. NSData *mvhdData = [_parser readDataForBox:mdhdBox];
  395. const char *bytes = mvhdData.bytes;
  396. NSInteger version = READ32BIT(&bytes[8]);
  397. NSInteger timescaleIndex = 20;
  398. NSInteger timescaleLength = 4;
  399. NSInteger durationIndex = 24;
  400. NSInteger durationLength = 4;
  401. if (version == 1) {
  402. timescaleIndex = 28;
  403. durationIndex = 32;
  404. durationLength = 8;
  405. }
  406. NSInteger scale = [_parser readValue:&bytes[timescaleIndex] length:timescaleLength];
  407. NSInteger duration = [_parser readValue:&bytes[durationIndex] length:durationLength];
  408. if (scale == 0) {
  409. return 0;
  410. }
  411. double result = duration/(double)scale;
  412. return result;
  413. }
  414. - (NSData *)readPacketOfSample:(NSInteger)sampleIndex {
  415. if (sampleIndex >= self.videoSamples.count) {
  416. VAP_Error(kQGVAPModuleCommon, @"readPacketOfSample beyond bounds!:%@ > %@", @(sampleIndex), @(self.videoSamples.count-1));
  417. return nil;
  418. }
  419. QGMP4Sample *videoSample = self.videoSamples[sampleIndex];
  420. NSInteger currentSampleSize = videoSample.sampleSize;
  421. [_parser.fileHandle seekToFileOffset:videoSample.streamOffset];
  422. // 当视频文件有问题时,sampleIndex还没有到最后,sampleIndex < self.videoSamples.count(总帧数)时,readDataOfLength长度可能为0Bytes
  423. NSData *packetData = [_parser.fileHandle readDataOfLength:currentSampleSize];
  424. return packetData;
  425. }
  426. - (NSData *)readDataOfBox:(QGMP4Box *)box length:(NSInteger)length offset:(NSInteger)offset {
  427. if (length <= 0 || offset + length > box.length) {
  428. return nil;
  429. }
  430. [_parser.fileHandle seekToFileOffset:box.startIndexInBytes+offset];
  431. NSData *data = [_parser.fileHandle readDataOfLength:length];
  432. return data;
  433. }
  434. #pragma mark -- delegate
  435. - (void)MP4FileDidFinishParse:(QGMP4Parser *)parser {
  436. }
  437. - (void)didParseMP4Box:(QGMP4Box *)box parser:(QGMP4Parser *)parser {
  438. switch (box.type) {
  439. case QGMP4BoxType_hdlr: {
  440. QGMP4TrackType trackType = ((QGMP4HdlrBox*)box).trackType;
  441. QGMP4TrackBox *trackBox = (QGMP4TrackBox*)[box superBoxOfType:QGMP4BoxType_trak];
  442. switch (trackType) {
  443. case QGMP4TrackType_Video:
  444. self.videoTrackBox = trackBox;
  445. break;
  446. case QGMP4TrackType_Audio:
  447. self.audioTrackBox = trackBox;
  448. break;
  449. default:
  450. break;
  451. }
  452. } break;
  453. case QGMP4BoxType_avc1: {
  454. self.videoCodecID = QGMP4VideoStreamCodecIDH264;
  455. } break;
  456. case QGMP4BoxType_hvc1: {
  457. self.videoCodecID = QGMP4VideoStreamCodecIDH265;
  458. } break;
  459. default:
  460. break;
  461. }
  462. }
  463. @end