mirror of
https://github.com/DKJone/DKWechatHelper.git
synced 2025-05-31 00:06:08 +08:00
568 lines
19 KiB
Objective-C
568 lines
19 KiB
Objective-C
// QGMP4Parser.m
|
||
// Tencent is pleased to support the open source community by making vap available.
|
||
//
|
||
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
|
||
//
|
||
// Licensed under the MIT License (the "License"); you may not use this file except in
|
||
// compliance with the License. You may obtain a copy of the License at
|
||
//
|
||
// http://opensource.org/licenses/MIT
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software distributed under the License is
|
||
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||
// either express or implied. See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
#import "QGMP4Parser.h"
|
||
#import "QGVAPLogger.h"
|
||
|
||
#pragma mark - mp4 parser
|
||
@interface QGMP4Parser() {
|
||
|
||
QGMp4BoxDataFetcher _boxDataFetcher;
|
||
}
|
||
|
||
@property (nonatomic, strong) NSString *filePath;
|
||
|
||
@end
|
||
|
||
@implementation QGMP4Parser
|
||
|
||
#pragma mark -- life cycle
|
||
|
||
- (instancetype)initWithFilePath:(NSString *)filePath {
|
||
|
||
if (self = [super init]) {
|
||
_filePath = filePath;
|
||
_fileHandle = [NSFileHandle fileHandleForReadingAtPath:_filePath];
|
||
__weak __typeof(self) weakSelf = self;
|
||
_boxDataFetcher = ^NSData *(QGMP4Box *box) {return [weakSelf readDataForBox:box];};
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (void)dealloc {
|
||
|
||
[_fileHandle closeFile];
|
||
}
|
||
|
||
#pragma mark -- methods
|
||
|
||
- (void)parse {
|
||
|
||
if (!_filePath || !_fileHandle) {
|
||
return ;
|
||
}
|
||
|
||
unsigned long long fileSize = [_fileHandle seekToEndOfFile];
|
||
[_fileHandle seekToFileOffset:0];
|
||
_rootBox = [QGMP4BoxFactory createBoxForType:QGMP4BoxType_unknown startIndex:0 length:fileSize];
|
||
NSMutableArray *BFSQueue = [NSMutableArray new];
|
||
[BFSQueue addObject:_rootBox];
|
||
|
||
QGMP4Box *calBox = _rootBox;
|
||
|
||
//长度包含包含类型码长度+本身长度
|
||
while ((calBox = [BFSQueue firstObject])) {
|
||
[BFSQueue removeObjectAtIndex:0];
|
||
|
||
if (calBox.length <= 2*(kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes)) {
|
||
//长度限制
|
||
continue ;
|
||
}
|
||
|
||
unsigned long long offset = 0;
|
||
unsigned long long length = 0;
|
||
QGMP4BoxType type = QGMP4BoxType_unknown;
|
||
|
||
//第一个子box
|
||
offset = calBox.superBox ? (calBox.startIndexInBytes + kQGBoxSizeLengthInBytes + kQGBoxTypeLengthInBytes) : 0;
|
||
|
||
//avcbox特殊处理
|
||
if (calBox.type == QGMP4BoxType_avc1 || calBox.type == QGMP4BoxType_hvc1 || calBox.type == QGMP4BoxType_stsd) {
|
||
unsigned long long avcOffset = calBox.startIndexInBytes+kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes;
|
||
unsigned long long avcEdge = calBox.startIndexInBytes+calBox.length-kQGBoxSizeLengthInBytes-kQGBoxTypeLengthInBytes;
|
||
unsigned long long avcLength = 0;
|
||
QGMP4BoxType avcType = QGMP4BoxType_unknown;
|
||
for (; avcOffset < avcEdge; avcOffset++) {
|
||
readBoxTypeAndLength(_fileHandle, avcOffset, &avcType, &avcLength);
|
||
if (avcType == QGMP4BoxType_avc1 || avcType == QGMP4BoxType_avcC || avcType == QGMP4BoxType_hvc1 || avcType == QGMP4BoxType_hvcC) {
|
||
QGMP4Box *avcBox = [QGMP4BoxFactory createBoxForType:avcType startIndex:avcOffset length:avcLength];
|
||
if (!calBox.subBoxes) {
|
||
calBox.subBoxes = [NSMutableArray new];
|
||
}
|
||
[calBox.subBoxes addObject:avcBox];
|
||
avcBox.superBox = calBox;
|
||
[BFSQueue addObject:avcBox];
|
||
offset = (avcBox.startIndexInBytes+avcBox.length);
|
||
[self didParseBox:avcBox];
|
||
break ;
|
||
}
|
||
}
|
||
}
|
||
do {
|
||
//判断是否会越界
|
||
if ((offset+kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes)>(calBox.startIndexInBytes+calBox.length)) {
|
||
break ;
|
||
}
|
||
readBoxTypeAndLength(_fileHandle, offset, &type, &length);
|
||
|
||
if ((offset+length)>(calBox.startIndexInBytes+calBox.length)) {
|
||
//reach to super box end or not a box
|
||
break ;
|
||
}
|
||
|
||
if (![QGMP4BoxFactory isTypeValueValid:type] && (offset == (calBox.startIndexInBytes + kQGBoxSizeLengthInBytes + kQGBoxTypeLengthInBytes))) {
|
||
//目前的策略是
|
||
break ;
|
||
}
|
||
QGMP4Box *subBox = [QGMP4BoxFactory createBoxForType:type startIndex:offset length:length];
|
||
subBox.superBox = calBox;
|
||
if (!calBox.subBoxes) {
|
||
calBox.subBoxes = [NSMutableArray new];
|
||
}
|
||
//加入box节点
|
||
[calBox.subBoxes addObject:subBox];
|
||
|
||
//进入广度优先遍历队列
|
||
[BFSQueue addObject:subBox];
|
||
[self didParseBox:subBox];
|
||
|
||
//继续兄弟box
|
||
offset += length;
|
||
} while(1);
|
||
}
|
||
|
||
[self didFinisheParseFile];
|
||
}
|
||
|
||
- (NSData *)readDataForBox:(QGMP4Box *)box {
|
||
|
||
if (!box) {
|
||
return nil;
|
||
}
|
||
[_fileHandle seekToFileOffset:box.startIndexInBytes];
|
||
return [_fileHandle readDataOfLength:(NSUInteger)box.length];
|
||
}
|
||
|
||
- (NSInteger)readValue:(const char*)bytes length:(NSInteger)length {
|
||
|
||
NSInteger value = 0;
|
||
for (int i = 0; i < length; i++) {
|
||
value += (bytes[i]&0xff)<<((length-i-1)*8);
|
||
}
|
||
return value;
|
||
}
|
||
|
||
#pragma mark -- private methods
|
||
|
||
- (void)didParseBox:(QGMP4Box *)box {
|
||
|
||
if ([box respondsToSelector:@selector(boxDidParsed:)]) {
|
||
[box boxDidParsed:_boxDataFetcher];
|
||
}
|
||
if ([self.delegate respondsToSelector:@selector(didParseMP4Box:parser:)]) {
|
||
[self.delegate didParseMP4Box:box parser:self];
|
||
}
|
||
}
|
||
|
||
- (void)didFinisheParseFile {
|
||
|
||
if ([self.delegate respondsToSelector:@selector(MP4FileDidFinishParse:)]) {
|
||
[self.delegate MP4FileDidFinishParse:self];
|
||
}
|
||
}
|
||
|
||
void readBoxTypeAndLength(NSFileHandle *fileHandle, unsigned long long offset, QGMP4BoxType *type, unsigned long long *length) {
|
||
|
||
[fileHandle seekToFileOffset:offset];
|
||
NSData *data = [fileHandle readDataOfLength:kQGBoxSizeLengthInBytes+kQGBoxTypeLengthInBytes];
|
||
const char *bytes = data.bytes;
|
||
*length = ((bytes[0]&0xff)<<24)+((bytes[1]&0xff)<<16)+((bytes[2]&0xff)<<8)+(bytes[3]&0xff);
|
||
*type = ((bytes[4]&0xff)<<24)+((bytes[5]&0xff)<<16)+((bytes[6]&0xff)<<8)+(bytes[7]&0xff);
|
||
}
|
||
|
||
@end
|
||
|
||
#pragma mark - parser proxy
|
||
|
||
@interface QGMP4ParserProxy() <QGMP4ParserDelegate> {
|
||
|
||
QGMP4Parser *_parser;
|
||
}
|
||
|
||
@end
|
||
|
||
@implementation QGMP4ParserProxy
|
||
|
||
- (instancetype)initWithFilePath:(NSString *)filePath {
|
||
|
||
if (self = [super init]) {
|
||
|
||
_parser = [[QGMP4Parser alloc] initWithFilePath:filePath];
|
||
_parser.delegate = self;
|
||
}
|
||
return self;
|
||
}
|
||
|
||
- (NSInteger)picWidth {
|
||
|
||
if (_picWidth == 0) {
|
||
_picWidth = [self readPicWidth];
|
||
}
|
||
return _picWidth;
|
||
}
|
||
|
||
- (NSInteger)picHeight {
|
||
|
||
if (_picHeight == 0) {
|
||
_picHeight = [self readPicHeight];
|
||
}
|
||
return _picHeight;
|
||
}
|
||
|
||
- (NSInteger)fps {
|
||
|
||
if (_fps == 0) {
|
||
if (self.videoSamples.count == 0) {
|
||
return 0;
|
||
}
|
||
_fps = self.videoSamples.count/self.duration;
|
||
}
|
||
return _fps;
|
||
}
|
||
|
||
- (double)duration {
|
||
|
||
if (_duration == 0) {
|
||
_duration = [self readDuration];
|
||
}
|
||
return _duration;
|
||
}
|
||
|
||
- (NSArray *)videoSamples {
|
||
|
||
if (_videoSamples) {
|
||
return _videoSamples;
|
||
}
|
||
NSMutableArray *videoSamples = [NSMutableArray new];
|
||
|
||
uint64_t start_play_time = 0;
|
||
uint64_t tmp = 0;
|
||
uint32_t sampIdx = 0;
|
||
QGMP4SttsBox *sttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stts];
|
||
QGMP4StszBox *stszBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsz];
|
||
QGMP4StscBox *stscBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stsc];
|
||
QGMP4StcoBox *stcoBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_stco];
|
||
QGMP4CttsBox *cttsBox = [self.videoTrackBox subBoxOfType:QGMP4BoxType_ctts];
|
||
for (int i = 0; i < sttsBox.entries.count; ++i) {
|
||
QGSttsEntry *entry = sttsBox.entries[i];
|
||
for (int j = 0; j < entry.sampleCount; ++j) {
|
||
QGMP4Sample *sample = [QGMP4Sample new];
|
||
sample.sampleDelta = entry.sampleDelta;
|
||
sample.codecType = QGMP4CodecTypeVideo;
|
||
sample.sampleIndex = sampIdx;
|
||
sample.pts = tmp + [cttsBox.compositionOffsets[j] unsignedLongLongValue];
|
||
if (sampIdx < stszBox.sampleSizes.count) {
|
||
sample.sampleSize = (int32_t)[stszBox.sampleSizes[sampIdx] integerValue];
|
||
}
|
||
[videoSamples addObject:sample];
|
||
start_play_time += entry.sampleDelta;
|
||
sampIdx++;
|
||
tmp += entry.sampleDelta;
|
||
}
|
||
|
||
NSMutableArray<QGChunkOffsetEntry *> *chunkOffsets = [NSMutableArray new];
|
||
uint32_t chunkIndex = 0;
|
||
uint32_t totalSample = 0;
|
||
for (int j = 0; j < stscBox.entries.count; ++j) {
|
||
QGStscEntry *entry = stscBox.entries[j];
|
||
if (j < stscBox.entries.count - 1) {
|
||
QGStscEntry *nextEntry = stscBox.entries[j+1];
|
||
for (int k = 0; k < nextEntry.firstChunk - entry.firstChunk; ++k) {
|
||
QGChunkOffsetEntry *offsetEntry = [QGChunkOffsetEntry new];
|
||
offsetEntry.samplesPerChunk = entry.samplesPerChunk;
|
||
totalSample += entry.samplesPerChunk;
|
||
if (chunkIndex < stcoBox.chunkOffsets.count) {
|
||
offsetEntry.offset = (uint32_t)[stcoBox.chunkOffsets[chunkIndex] integerValue];
|
||
}
|
||
chunkIndex++;
|
||
[chunkOffsets addObject:offsetEntry];
|
||
}
|
||
} else {
|
||
//只有一个或最后一个
|
||
while (chunkIndex < stcoBox.chunkOffsets.count) {
|
||
QGChunkOffsetEntry *offsetEntry = [QGChunkOffsetEntry new];
|
||
offsetEntry.samplesPerChunk = entry.samplesPerChunk;
|
||
offsetEntry.offset = (uint32_t)[stcoBox.chunkOffsets[chunkIndex] integerValue];
|
||
totalSample += entry.samplesPerChunk;
|
||
chunkIndex++;
|
||
[chunkOffsets addObject:offsetEntry];
|
||
}
|
||
}
|
||
}
|
||
sampIdx = 0;
|
||
for (int i = 0; i < chunkOffsets.count; ++i) {
|
||
QGChunkOffsetEntry *offsetEntry = chunkOffsets[i];
|
||
uint32_t offsetChunk = 0;
|
||
for (int j = 0; j < offsetEntry.samplesPerChunk; ++j) {
|
||
if (sampIdx < videoSamples.count) {
|
||
QGMP4Sample *videoSample = videoSamples[sampIdx];
|
||
videoSample.chunkIndex = i;
|
||
videoSample.streamOffset = offsetEntry.offset + offsetChunk;
|
||
offsetChunk += videoSample.sampleSize;
|
||
sampIdx++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
_videoSamples = videoSamples;
|
||
return _videoSamples;
|
||
}
|
||
|
||
/**
|
||
调用该方法才会解析mp4文件并得到必要信息。
|
||
*/
|
||
- (void)parse {
|
||
|
||
[_parser parse];
|
||
_rootBox = _parser.rootBox;
|
||
|
||
// 解析视频解码配置信息
|
||
[self parseVideoDecoderConfigRecord];
|
||
}
|
||
|
||
#pragma mark - Private
|
||
|
||
- (void)parseVideoDecoderConfigRecord {
|
||
if (self.videoCodecID == QGMP4VideoStreamCodecIDH264) {
|
||
[self parseAvccDecoderConfigRecord];
|
||
} else if (self.videoCodecID == QGMP4VideoStreamCodecIDH265) {
|
||
[self parseHvccDecoderConfigRecord];
|
||
}
|
||
}
|
||
|
||
- (void)parseAvccDecoderConfigRecord {
|
||
self.spsData = [self parseAvccSPSData];
|
||
self.ppsData = [self parseAvccPPSData];
|
||
}
|
||
|
||
- (void)parseHvccDecoderConfigRecord {
|
||
NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_hvcC]];
|
||
if (extraData.length <= 8) {
|
||
return;
|
||
}
|
||
|
||
const char *bytes = extraData.bytes;
|
||
int index = 30; // 21 + 4 + 4
|
||
|
||
//int lengthSize = ((bytes[index++] & 0xff) & 0x03) + 1;
|
||
int arrayNum = bytes[index++] & 0xff;
|
||
|
||
// sps pps vps 种类数量
|
||
for (int i = 0; i < arrayNum; i++) {
|
||
int value = bytes[index++] & 0xff;
|
||
int naluType = value & 0x3F;
|
||
// sps pps vps 各自的数量
|
||
int naluNum = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
|
||
index += 2;
|
||
|
||
for (int j = 0; j < naluNum; j++) {
|
||
int naluLength = ((bytes[index] & 0xff) << 8) + (bytes[index + 1] & 0xff);
|
||
index += 2;
|
||
NSData *paramData = [NSData dataWithBytes:&bytes[index] length:naluLength];
|
||
|
||
if (naluType == 32) {
|
||
// vps
|
||
self.vpsData = paramData;
|
||
} else if (naluType == 33) {
|
||
// sps
|
||
self.spsData = paramData;
|
||
} else if (naluType == 34) {
|
||
// pps
|
||
self.ppsData = paramData;
|
||
}
|
||
|
||
index += naluLength;
|
||
}
|
||
}
|
||
}
|
||
|
||
- (NSData *)parseAvccSPSData {
|
||
//boxsize(32)+boxtype(32)+prefix(40)+预留(3)+spsCount(5)+spssize(16)+...+ppscount(8)+ppssize(16)+...
|
||
NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_avcC]];
|
||
if (extraData.length <= 8) {
|
||
return nil;
|
||
}
|
||
const char *bytes = extraData.bytes;
|
||
//sps数量 默认一个暂无使用
|
||
//NSInteger spsCount = bytes[13]&0x1f;
|
||
NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
|
||
NSInteger naluType = (uint8_t)bytes[16]&0x1F;
|
||
if (spsLength + 16 > extraData.length || naluType != 7) {
|
||
return nil;
|
||
}
|
||
NSData *spsData = [NSData dataWithBytes:&bytes[16] length:spsLength];
|
||
return spsData;
|
||
}
|
||
|
||
- (NSData *)parseAvccPPSData {
|
||
NSData *extraData = [_parser readDataForBox:[self.videoTrackBox subBoxOfType:QGMP4BoxType_avcC]];
|
||
if (extraData.length <= 8) {
|
||
return nil;
|
||
}
|
||
const char *bytes = extraData.bytes;
|
||
NSInteger spsCount = bytes[13]&0x1f;
|
||
NSInteger spsLength = ((bytes[14]&0xff)<<8) + (bytes[15]&0xff);
|
||
NSInteger prefixLength = 16 + spsLength;
|
||
|
||
while (--spsCount > 0) {
|
||
if (prefixLength+2 >= extraData.length) {
|
||
return nil;
|
||
}
|
||
NSInteger nextSpsLength = ((bytes[prefixLength]&0xff)<<8)+bytes[prefixLength+1]&0xff;
|
||
prefixLength += nextSpsLength;
|
||
}
|
||
|
||
//默认1个
|
||
// NSInteger ppsCount = bytes[prefixLength]&0xff;
|
||
if (prefixLength+3 >= extraData.length) {
|
||
return nil;
|
||
}
|
||
NSInteger ppsLength = ((bytes[prefixLength+1]&0xff)<<8)+(bytes[prefixLength+2]&0xff);
|
||
NSInteger naluType = (uint8_t)bytes[prefixLength+3]&0x1F;
|
||
if (naluType != 8 || (ppsLength+prefixLength+3) > extraData.length) {
|
||
return nil;
|
||
}
|
||
|
||
NSData *ppsData = [NSData dataWithBytes:&bytes[prefixLength+3] length:ppsLength];
|
||
return ppsData;
|
||
}
|
||
|
||
- (NSInteger)readPicWidth {
|
||
if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
|
||
return 0;
|
||
}
|
||
|
||
QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
|
||
NSInteger sizeIndex = 32;
|
||
NSUInteger readLength = 2;
|
||
QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
|
||
[_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
|
||
NSData *widthData = [_parser.fileHandle readDataOfLength:readLength];
|
||
|
||
if (widthData.length < readLength) {
|
||
return 0;
|
||
}
|
||
|
||
const char *bytes = widthData.bytes;
|
||
NSInteger width = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
|
||
return width;
|
||
}
|
||
|
||
- (NSInteger)readPicHeight {
|
||
if (self.videoCodecID == QGMP4VideoStreamCodecIDUnknown) {
|
||
return 0;
|
||
}
|
||
|
||
QGMP4BoxType boxType = self.videoCodecID == QGMP4VideoStreamCodecIDH264 ? QGMP4BoxType_avc1 : QGMP4BoxType_hvc1;
|
||
NSInteger sizeIndex = 34;
|
||
NSUInteger readLength = 2;
|
||
QGMP4Box *avc1 = [self.videoTrackBox subBoxOfType:boxType];
|
||
[_parser.fileHandle seekToFileOffset:avc1.startIndexInBytes+sizeIndex];
|
||
NSData *heightData = [_parser.fileHandle readDataOfLength:readLength];
|
||
|
||
if (heightData.length < readLength) {
|
||
return 0;
|
||
}
|
||
|
||
const char *bytes = heightData.bytes;
|
||
NSInteger height = ((bytes[0]&0xff)<<8)+(bytes[1]&0xff);
|
||
return height;
|
||
}
|
||
|
||
- (double)readDuration {
|
||
|
||
QGMP4MvhdBox *mdhdBox = [self.rootBox subBoxOfType:QGMP4BoxType_mvhd];
|
||
NSData *mvhdData = [_parser readDataForBox:mdhdBox];
|
||
const char *bytes = mvhdData.bytes;
|
||
NSInteger version = READ32BIT(&bytes[8]);
|
||
NSInteger timescaleIndex = 20;
|
||
NSInteger timescaleLength = 4;
|
||
NSInteger durationIndex = 24;
|
||
NSInteger durationLength = 4;
|
||
if (version == 1) {
|
||
timescaleIndex = 28;
|
||
durationIndex = 32;
|
||
durationLength = 8;
|
||
}
|
||
|
||
NSInteger scale = [_parser readValue:&bytes[timescaleIndex] length:timescaleLength];
|
||
NSInteger duration = [_parser readValue:&bytes[durationIndex] length:durationLength];
|
||
if (scale == 0) {
|
||
return 0;
|
||
}
|
||
double result = duration/(double)scale;
|
||
return result;
|
||
}
|
||
|
||
- (NSData *)readPacketOfSample:(NSInteger)sampleIndex {
|
||
|
||
if (sampleIndex >= self.videoSamples.count) {
|
||
VAP_Error(kQGVAPModuleCommon, @"readPacketOfSample beyond bounds!:%@ > %@", @(sampleIndex), @(self.videoSamples.count-1));
|
||
return nil;
|
||
}
|
||
QGMP4Sample *videoSample = self.videoSamples[sampleIndex];
|
||
NSInteger currentSampleSize = videoSample.sampleSize;
|
||
[_parser.fileHandle seekToFileOffset:videoSample.streamOffset];
|
||
// 当视频文件有问题时,sampleIndex还没有到最后,sampleIndex < self.videoSamples.count(总帧数)时,readDataOfLength长度可能为0Bytes
|
||
NSData *packetData = [_parser.fileHandle readDataOfLength:currentSampleSize];
|
||
return packetData;
|
||
}
|
||
|
||
- (NSData *)readDataOfBox:(QGMP4Box *)box length:(NSInteger)length offset:(NSInteger)offset {
|
||
|
||
if (length <= 0 || offset + length > box.length) {
|
||
return nil;
|
||
}
|
||
[_parser.fileHandle seekToFileOffset:box.startIndexInBytes+offset];
|
||
NSData *data = [_parser.fileHandle readDataOfLength:length];
|
||
return data;
|
||
}
|
||
|
||
#pragma mark -- delegate
|
||
|
||
- (void)MP4FileDidFinishParse:(QGMP4Parser *)parser {
|
||
|
||
}
|
||
|
||
- (void)didParseMP4Box:(QGMP4Box *)box parser:(QGMP4Parser *)parser {
|
||
|
||
switch (box.type) {
|
||
case QGMP4BoxType_hdlr: {
|
||
QGMP4TrackType trackType = ((QGMP4HdlrBox*)box).trackType;
|
||
QGMP4TrackBox *trackBox = (QGMP4TrackBox*)[box superBoxOfType:QGMP4BoxType_trak];
|
||
switch (trackType) {
|
||
case QGMP4TrackType_Video:
|
||
self.videoTrackBox = trackBox;
|
||
break;
|
||
case QGMP4TrackType_Audio:
|
||
self.audioTrackBox = trackBox;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
} break;
|
||
case QGMP4BoxType_avc1: {
|
||
self.videoCodecID = QGMP4VideoStreamCodecIDH264;
|
||
} break;
|
||
case QGMP4BoxType_hvc1: {
|
||
self.videoCodecID = QGMP4VideoStreamCodecIDH265;
|
||
} break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
@end
|