QGMP4Parser.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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. unsigned long long dataConvertToUInt64(NSData *data) {
  141. unsigned long long largeSize = 0;
  142. if (data.length < 8) {
  143. return largeSize;
  144. }
  145. const char *bytes = data.bytes;
  146. for (int i = 0; i < 8; i++) {
  147. largeSize += ((bytes[i]&0xff) << (8 - i - 1) * 8);
  148. }
  149. return largeSize;
  150. }
  151. void readBoxTypeAndLength(NSFileHandle *fileHandle, unsigned long long offset, QGMP4BoxType *type, unsigned long long *length) {
  152. [fileHandle seekToFileOffset:offset];
  153. NSData *data = [fileHandle readDataOfLength:kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes];
  154. const char *bytes = data.bytes;
  155. *length = ((bytes[0]&0xff)<<24)+((bytes[1]&0xff)<<16)+((bytes[2]&0xff)<<8)+(bytes[3]&0xff);
  156. *type = ((bytes[4]&0xff)<<24)+((bytes[5]&0xff)<<16)+((bytes[6]&0xff)<<8)+(bytes[7]&0xff);
  157. if (*length == kQGBoxLargeSizeFlagLengthInBytes) {
  158. [fileHandle seekToFileOffset:offset + kQGBoxSizeLengthInBytes + kQGBoxTypeLengthInBytes];
  159. NSData *largeSizeData = [fileHandle readDataOfLength:kQGBoxLargeSizeLengthInBytes];
  160. *length = dataConvertToUInt64(largeSizeData);
  161. }
  162. }
  163. @end
  164. #pragma mark - parser proxy
  165. @interface QGMP4ParserProxy() <QGMP4ParserDelegate> {
  166. QGMP4Parser *_parser;
  167. }
  168. @end
  169. @implementation QGMP4ParserProxy
  170. - (instancetype)initWithFilePath:(NSString *)filePath {
  171. if (self = [super init]) {
  172. _parser = [[QGMP4Parser alloc] initWithFilePath:filePath];
  173. _parser.delegate = self;
  174. }
  175. return self;
  176. }
  177. - (NSInteger)picWidth {
  178. if (_picWidth == 0) {
  179. _picWidth = [self readPicWidth];
  180. }
  181. return _picWidth;
  182. }
  183. - (NSInteger)picHeight {
  184. if (_picHeight == 0) {
  185. _picHeight = [self readPicHeight];
  186. }
  187. return _picHeight;
  188. }
  189. - (NSInteger)fps {
  190. if (_fps == 0) {
  191. if (self.videoSamples.count == 0) {
  192. return 0;
  193. }
  194. _fps = lround(self.videoSamples.count/self.duration);
  195. }
  196. return _fps;
  197. }
  198. - (double)duration {
  199. if (_duration == 0) {
  200. _duration = [self readDuration];
  201. }
  202. return _duration;
  203. }
  204. - (NSArray *)videoSamples {
  205. if (_videoSamples) {
  206. return _videoSamples;
  207. }
  208. NSMutableArray *videoSamples = [NSMutableArray new];
  209. uint64_t tmp = 0;
  210. QGMP4SttsBox *sttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stts];
  211. QGMP4StszBox *stszBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsz];
  212. QGMP4StscBox *stscBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsc];
  213. QGMP4StcoBox *stcoBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stco];
  214. QGMP4CttsBox *cttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_ctts];
  215. uint32_t stscEntryIndex = 0;
  216. uint32_t stscEntrySampleIndex = 0;
  217. uint32_t stscEntrySampleOffset = 0;
  218. uint32_t sttsEntryIndex = 0;
  219. uint32_t sttsEntrySampleIndex = 0;
  220. uint32_t stcoChunkLogicIndex = 0;
  221. for (int i = 0; i < stszBox.sampleCount; ++i) {
  222. if (stscEntryIndex >= stscBox.entries.count ||
  223. sttsEntryIndex >= sttsBox.entries.count ||
  224. stcoChunkLogicIndex >= stcoBox.chunkOffsets.count) {
  225. break;
  226. }
  227. QGStscEntry *stscEntry = stscBox.entries[stscEntryIndex];
  228. QGSttsEntry *sttsEntry = sttsBox.entries[sttsEntryIndex];
  229. uint32_t sampleOffset = [stcoBox.chunkOffsets[stcoChunkLogicIndex] unsignedIntValue] + stscEntrySampleOffset;
  230. uint32_t ctts = 0;
  231. if (i < cttsBox.compositionOffsets.count) {
  232. ctts = [cttsBox.compositionOffsets[i] unsignedIntValue];
  233. }
  234. QGMP4Sample *sample = [QGMP4Sample new];
  235. sample.codecType = QGMP4CodecTypeVideo;
  236. sample.sampleIndex = i;
  237. sample.chunkIndex = stcoChunkLogicIndex;
  238. sample.sampleDelta = sttsEntry.sampleDelta;
  239. sample.sampleSize = [stszBox.sampleSizes[i] unsignedIntValue];
  240. sample.pts = tmp + ctts;
  241. sample.streamOffset = sampleOffset;
  242. [videoSamples addObject:sample];
  243. stscEntrySampleOffset += sample.sampleSize;
  244. tmp += sample.sampleDelta;
  245. stscEntrySampleIndex++;
  246. if (stscEntrySampleIndex >= stscEntry.samplesPerChunk) {
  247. if (stcoChunkLogicIndex + 1 < stcoBox.chunkOffsets.count) {
  248. stcoChunkLogicIndex++;
  249. }
  250. stscEntrySampleIndex = 0;
  251. stscEntrySampleOffset = 0;
  252. }
  253. sttsEntrySampleIndex++;
  254. if (sttsEntrySampleIndex >= sttsEntry.sampleCount) {
  255. sttsEntrySampleIndex = 0;
  256. if (sttsEntryIndex + 1 < sttsBox.entries.count) {
  257. sttsEntryIndex++;
  258. }
  259. }
  260. if (stscEntryIndex + 1 < stscBox.entries.count) {
  261. if (stcoChunkLogicIndex >= stscBox.entries[stscEntryIndex + 1].firstChunk - 1) {
  262. stscEntryIndex++;
  263. }
  264. }
  265. }
  266. _videoSamples = videoSamples;
  267. return _videoSamples;
  268. }
  269. - (NSArray *)videoSyncSampleIndexes {
  270. QGMP4StssBox *stssBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stss];
  271. return stssBox.syncSamples;
  272. }
  273. /**
  274. 调用该方法才会解析mp4文件并得到必要信息。
  275. */
  276. - (void)parse {
  277. [_parser parse];
  278. _rootBox = _parser.rootBox;
  279. // 解析视频解码配置信息
  280. [self parseVideoDecoderConfigRecord];
  281. }
  282. #pragma mark - Private
  283. - (void)parseVideoDecoderConfigRecord {
  284. if (self.videoCodecID == QGMP4VideoStreamCodecIDH264) {
  285. [self parseAvccDecoderConfigRecord];
  286. } else if (self.videoCodecID == QGMP4VideoStreamCodecIDH265) {
  287. [self parseHvccDecoderConfigRecord];
  288. }
  289. }
  290. - (void)parseAvccDecoderConfigRecord {
  291. self.spsData = [self parseAvccSPSData];
  292. self.ppsData = [self parseAvccPPSData];
  293. }
  294. - (void)parseHvccDecoderConfigRecord {
  295. NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_hvcC]];
  296. if (extraData.length <= 8) {
  297. return;
  298. }
  299. const char *bytes = extraData.bytes;
  300. int index = 30; // 21 + 4 + 4
  301. //int lengthSize = ((bytes[index++] & 0xff) & 0x03) + 1;
  302. int arrayNum = bytes[index++] & 0xff;
  303. // sps pps vps 种类数量
  304. for (int i = 0; i < arrayNum; i++) {
  305. int value = bytes[index++] & 0xff;
  306. int naluType = value & 0x3F;
  307. // sps pps vps 各自的数量
  308. int naluNum = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
  309. index += 2;
  310. for (int j = 0; j < naluNum; j++) {
  311. int naluLength = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
  312. index += 2;
  313. NSData *paramData = [NSData dataWithBytes:&bytes[index] length:naluLength];
  314. if (naluType == 32) {
  315. // vps
  316. self.vpsData = paramData;
  317. } else if (naluType == 33) {
  318. // sps
  319. self.spsData = paramData;
  320. } else if (naluType == 34) {
  321. // pps
  322. self.ppsData = paramData;
  323. }
  324. index += naluLength;
  325. }
  326. }
  327. }
  328. - (NSData *)parseAvccSPSData {
  329. //boxsize(32)+boxtype(32)+prefix(40)+预留(3)+spsCount(5)+spssize(16)+...+ppscount(8)+ppssize(16)+...
  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. //sps数量 默认一个暂无使用
  336. //NSInteger spsCount = bytes[13]&0x1f;
  337. NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
  338. NSInteger naluType = (uint8_t)bytes[16]&0x1F;
  339. if (spsLength + 16 > extraData.length || naluType != 7) {
  340. return nil;
  341. }
  342. NSData *spsData = [NSData dataWithBytes:&bytes[16] length:spsLength];
  343. return spsData;
  344. }
  345. - (NSData *)parseAvccPPSData {
  346. NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_avcC]];
  347. if (extraData.length <= 8) {
  348. return nil;
  349. }
  350. const char *bytes = extraData.bytes;
  351. NSInteger spsCount = bytes[13]&0x1f;
  352. NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
  353. NSInteger prefixLength = 16 + spsLength;
  354. while (--spsCount > 0) {
  355. if (prefixLength+2 >= extraData.length) {
  356. return nil;
  357. }
  358. NSInteger nextSpsLength = ((bytes[prefixLength]&0xff)<<8)+bytes[prefixLength+1]&0xff;
  359. prefixLength += nextSpsLength;
  360. }
  361. //默认1个
  362. // NSInteger ppsCount = bytes[prefixLength]&0xff;
  363. if (prefixLength+3 >= extraData.length) {
  364. return nil;
  365. }
  366. NSInteger ppsLength = ((bytes[prefixLength+1]&0xff)<<8)+(bytes[prefixLength+2]&0xff);
  367. NSInteger naluType = (uint8_t)bytes[prefixLength+3]&0x1F;
  368. if (naluType != 8 || (ppsLength+prefixLength+3) > extraData.length) {
  369. return nil;
  370. }
  371. NSData *ppsData = [NSData dataWithBytes:&bytes[prefixLength+3] length:ppsLength];
  372. return ppsData;
  373. }
  374. - (NSInteger)readPicWidth {
  375. if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
  376. return 0;
  377. }
  378. QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
  379. NSInteger sizeIndex = 32;
  380. NSUInteger readLength = 2;
  381. QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
  382. [_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
  383. NSData *widthData = [_parser.fileHandle readDataOfLength:readLength];
  384. if (widthData.length < readLength) {
  385. return 0;
  386. }
  387. const char *bytes = widthData.bytes;
  388. NSInteger width = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
  389. return width;
  390. }
  391. - (NSInteger)readPicHeight {
  392. if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
  393. return 0;
  394. }
  395. QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
  396. NSInteger sizeIndex = 34;
  397. NSUInteger readLength = 2;
  398. QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
  399. [_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
  400. NSData *heightData = [_parser.fileHandle readDataOfLength:readLength];
  401. if (heightData.length < readLength) {
  402. return 0;
  403. }
  404. const char *bytes = heightData.bytes;
  405. NSInteger height = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
  406. return height;
  407. }
  408. - (double)readDuration {
  409. QGMP4MvhdBox *mdhdBox = [self.rootBox subBoxOfType:QGMP4BoxType_mvhd];
  410. NSData *mvhdData = [_parser readDataForBox:mdhdBox];
  411. const char *bytes = mvhdData.bytes;
  412. NSInteger version = READ32BIT(&bytes[8]);
  413. NSInteger timescaleIndex = 20;
  414. NSInteger timescaleLength = 4;
  415. NSInteger durationIndex = 24;
  416. NSInteger durationLength = 4;
  417. if (version == 1) {
  418. timescaleIndex = 28;
  419. durationIndex = 32;
  420. durationLength = 8;
  421. }
  422. NSInteger scale = [_parser readValue:&bytes[timescaleIndex] length:timescaleLength];
  423. NSInteger duration = [_parser readValue:&bytes[durationIndex] length:durationLength];
  424. if (scale == 0) {
  425. return 0;
  426. }
  427. double result = duration/(double)scale;
  428. return result;
  429. }
  430. - (NSData *)readPacketOfSample:(NSInteger)sampleIndex {
  431. if (sampleIndex >= self.videoSamples.count) {
  432. VAP_Error(kQGVAPModuleCommon, @"readPacketOfSample beyond bounds!:%@ > %@", @(sampleIndex), @(self.videoSamples.count-1));
  433. return nil;
  434. }
  435. QGMP4Sample *videoSample = self.videoSamples[sampleIndex];
  436. NSInteger currentSampleSize = videoSample.sampleSize;
  437. [_parser.fileHandle seekToFileOffset:videoSample.streamOffset];
  438. // 当视频文件有问题时,sampleIndex还没有到最后,sampleIndex < self.videoSamples.count(总帧数)时,readDataOfLength长度可能为0Bytes
  439. NSData *packetData = [_parser.fileHandle readDataOfLength:currentSampleSize];
  440. return packetData;
  441. }
  442. - (NSData *)readDataOfBox:(QGMP4Box *)box length:(NSInteger)length offset:(NSInteger)offset {
  443. if (length <= 0 || offset + length > box.length) {
  444. return nil;
  445. }
  446. [_parser.fileHandle seekToFileOffset:box.startIndexInBytes+offset];
  447. NSData *data = [_parser.fileHandle readDataOfLength:length];
  448. return data;
  449. }
  450. #pragma mark -- delegate
  451. - (void)MP4FileDidFinishParse:(QGMP4Parser *)parser {
  452. }
  453. - (void)didParseMP4Box:(QGMP4Box *)box parser:(QGMP4Parser *)parser {
  454. switch (box.type) {
  455. case QGMP4BoxType_hdlr: {
  456. QGMP4TrackType trackType = ((QGMP4HdlrBox*)box).trackType;
  457. QGMP4TrackBox *trackBox = (QGMP4TrackBox*)[box superBoxOfType:QGMP4BoxType_trak];
  458. switch (trackType) {
  459. case QGMP4TrackType_Video:
  460. self.videoTrackBox = trackBox;
  461. break;
  462. case QGMP4TrackType_Audio:
  463. self.audioTrackBox = trackBox;
  464. break;
  465. default:
  466. break;
  467. }
  468. } break;
  469. case QGMP4BoxType_avc1: {
  470. self.videoCodecID = QGMP4VideoStreamCodecIDH264;
  471. } break;
  472. case QGMP4BoxType_hvc1: {
  473. self.videoCodecID = QGMP4VideoStreamCodecIDH265;
  474. } break;
  475. default:
  476. break;
  477. }
  478. }
  479. @end