Skip to content

Commit d83844f

Browse files
author
ianyanzhang
committed
1、Upgrade Demo to optimize the user experience
1 parent 9550862 commit d83844f

File tree

11 files changed

+535
-74
lines changed

11 files changed

+535
-74
lines changed

Demo/TXLiteAVDemo/SuperPlayerKit/SuperPlayer.podspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Pod::Spec.new do |spec|
1212

1313
spec.dependency 'SDWebImage'
1414
spec.dependency 'Masonry'
15+
spec.dependency 'AFNetworking'
1516
#spec.dependency 'MMLayout'
1617

1718
spec.static_framework = true
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// SPPlayCGIParser.h
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/26.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "SPPlayCGIParserProtocol.h"
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@interface SPPlayCGIParser : NSObject
16+
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version;
17+
@end
18+
19+
NS_ASSUME_NONNULL_END
20+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// SPPlayCGIParser.m
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/26.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import "SPPlayCGIParser.h"
10+
11+
#import "SPPlayCGIParser_V2.h"
12+
#import "SPPlayCGIParser_V4.h"
13+
14+
@implementation SPPlayCGIParser
15+
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version {
16+
if (version == 2) {
17+
return [SPPlayCGIParser_V2 class];
18+
} else {
19+
return [SPPlayCGIParser_V4 class];
20+
}
21+
}
22+
@end
23+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// PlayCGIParserProtocol.h
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/25.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "SPPlayCGIParseResult.h"
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@protocol SPPlayCGIParserProtocol <NSObject>
16+
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp;
17+
@end
18+
19+
NS_ASSUME_NONNULL_END
20+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// SPPlayCGIParser_V2.h
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/25.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "SPPlayCGIParserProtocol.h"
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@interface SPPlayCGIParser_V2 : NSObject <SPPlayCGIParserProtocol>
16+
17+
@end
18+
19+
NS_ASSUME_NONNULL_END
20+
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// SPPlayCGIParser_V2.m
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/25.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import "SPPlayCGIParser_V2.h"
10+
11+
#import "J2Obj.h"
12+
#import "SuperPlayerUrl.h"
13+
#import "TXBitrateItemHelper.h"
14+
#import "TXImageSprite.h"
15+
16+
@implementation SPPlayCGIParser_V2
17+
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)responseObject {
18+
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
19+
NSString * masterUrl = J2Str([responseObject valueForKeyPath:@"videoInfo.masterPlayList.url"]);
20+
// masterUrl = nil;
21+
if (masterUrl.length > 0) {
22+
// 1. 如果有master url,优先用这个
23+
ret.url = masterUrl;
24+
} else {
25+
NSString *mainDefinition = J2Str([responseObject valueForKeyPath:@"playerInfo.defaultVideoClassification"]);
26+
27+
NSArray *videoClassification = J2Array([responseObject valueForKeyPath:@"playerInfo.videoClassification"]);
28+
NSArray *transcodeList = J2Array([responseObject valueForKeyPath:@"videoInfo.transcodeList"]);
29+
30+
NSMutableArray<SuperPlayerUrl *> *result = [NSMutableArray new];
31+
32+
// 2. 如果有转码的清晰度,用转码流
33+
for (NSDictionary *transcode in transcodeList) {
34+
SuperPlayerUrl *subModel = [SuperPlayerUrl new];
35+
subModel.url = J2Str(transcode[@"url"]);
36+
NSNumber *theDefinition = J2Num(transcode[@"definition"]);
37+
38+
for (NSDictionary *definition in videoClassification) {
39+
for (NSObject *definition2 in J2Array([definition valueForKeyPath:@"definitionList"])) {
40+
if ([definition2 isEqual:theDefinition]) {
41+
subModel.title = J2Str([definition valueForKeyPath:@"name"]);
42+
NSString *definitionId = J2Str([definition valueForKeyPath:@"id"]);
43+
// 初始播放清晰度
44+
if ([definitionId isEqualToString:mainDefinition]) {
45+
if (![ret.url containsString:@".mp4"]) ret.url = subModel.url;
46+
}
47+
break;
48+
}
49+
}
50+
}
51+
// 同一个清晰度可能存在多个转码格式,这里只保留一种格式,且优先mp4类型
52+
for (SuperPlayerUrl *item in result) {
53+
if ([item.title isEqual:subModel.title]) {
54+
if (![item.url containsString:@".mp4"]) {
55+
item.url = subModel.url;
56+
}
57+
subModel = nil;
58+
break;
59+
}
60+
}
61+
62+
if (subModel) {
63+
[result addObject:subModel];
64+
}
65+
}
66+
ret.multiVideoURLs = result;
67+
}
68+
// 3. 以上都没有,用原始地址
69+
if (ret.url == nil) {
70+
NSString *source = J2Str([responseObject valueForKeyPath:@"videoInfo.sourceVideo.url"]);
71+
ret.url = source;
72+
}
73+
74+
NSArray *imageSprites = J2Array([responseObject valueForKeyPath:@"imageSpriteInfo.imageSpriteList"]);
75+
if (imageSprites.count > 0) {
76+
// id imageSpriteObj = imageSprites[0];
77+
id imageSpriteObj = imageSprites.lastObject;
78+
NSString * vtt = J2Str([imageSpriteObj valueForKeyPath:@"webVttUrl"]);
79+
NSArray * imgUrls = J2Array([imageSpriteObj valueForKeyPath:@"imageUrls"]);
80+
NSMutableArray *imgUrlArray = @[].mutableCopy;
81+
for (NSString *url in imgUrls) {
82+
NSURL *nsurl = [NSURL URLWithString:url];
83+
if (nsurl) {
84+
[imgUrlArray addObject:nsurl];
85+
}
86+
}
87+
88+
TXImageSprite *imageSprite = [[TXImageSprite alloc] init];
89+
[imageSprite setVTTUrl:[NSURL URLWithString:vtt] imageUrls:imgUrlArray];
90+
ret.imageSprite = imageSprite;
91+
}
92+
93+
NSArray *keyFrameDescList = J2Array([responseObject valueForKeyPath:@"keyFrameDescInfo.keyFrameDescList"]);
94+
if (keyFrameDescList.count > 0) {
95+
NSMutableArray<SPVideoFrameDescription *> *checkPoints = [[NSMutableArray alloc] initWithCapacity:keyFrameDescList.count];
96+
for (NSDictionary *info in keyFrameDescList) {
97+
SPVideoFrameDescription *checkPoint = [SPVideoFrameDescription instanceFromDictionary:info];
98+
[checkPoints addObject:checkPoint];
99+
}
100+
ret.keyFrameDescList = checkPoints;
101+
}
102+
return ret;
103+
}
104+
@end
105+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// PlayCGIV4Parser.h
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/25.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
#import "SPPlayCGIParserProtocol.h"
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@interface SPPlayCGIParser_V4 : NSObject <SPPlayCGIParserProtocol>
16+
17+
@end
18+
19+
NS_ASSUME_NONNULL_END
20+
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//
2+
// PlayCGIV4Parser.m
3+
// SuperPlayer
4+
//
5+
// Created by cui on 2019/12/25.
6+
// Copyright © 2019 annidy. All rights reserved.
7+
//
8+
9+
#import "SPPlayCGIParser_V4.h"
10+
//#import "SPResolutionDefination.h"
11+
#import "AdaptiveStream.h"
12+
#import "J2Obj.h"
13+
#import "SPSubStreamInfo.h"
14+
#import "TXImageSprite.h"
15+
16+
@implementation SPPlayCGIParser_V4
17+
18+
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp {
19+
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
20+
21+
// 获取媒体信息
22+
NSDictionary *media = jsonResp[@"media"];
23+
if ([media isKindOfClass:[NSDictionary class]]) {
24+
do {
25+
//解析视频名称
26+
ret.name = [media valueForKeyPath:@"basicInfo.name"];
27+
NSString* audioVideoType = [media valueForKey:@"audioVideoType"];
28+
NSDictionary *streamInfo = [self getStreamInfo:audioVideoType media:media];
29+
if (streamInfo == nil) {
30+
NSArray *drmOutputs = [media valueForKeyPath:@"streamingInfo.drmOutput"];
31+
for (NSDictionary *drmOutput in drmOutputs) {
32+
SPDrmType type = [SPPlayCGIParseResult drmTypeFromString:J2Str(drmOutput[@"type"])];
33+
if (type == SPDrmTypeSimpleAES) {
34+
streamInfo = drmOutput;
35+
ret.drmType = SPDrmTypeSimpleAES;
36+
break;
37+
}
38+
}
39+
ret.drmToken = [media valueForKeyPath:@"streamingInfo.drmToken"];
40+
}
41+
42+
NSNumber *duration = [media valueForKeyPath:@"basicInfo.duration"];
43+
if ([duration isKindOfClass:[NSNumber class]]) {
44+
ret.originalDuration = duration.doubleValue;
45+
}
46+
// 解析分辨率名称
47+
NSArray * subStreamDictArray = J2Array(streamInfo[@"subStreams"]);
48+
ret.multiVideoURLs = [self parseResolutionName:subStreamDictArray];
49+
50+
//解析视频播放url
51+
NSString *url = streamInfo[@"url"];
52+
if ([url isKindOfClass:[NSString class]] && url.length > 0) {
53+
//未加密直接解析出视频url
54+
ret.url = url;
55+
} else {
56+
//有加密,url为空,则解析drm加密的url信息
57+
NSArray *urlArray = streamInfo[@"drmUrls"];
58+
if ([urlArray isKindOfClass:[NSArray class]] && urlArray.count > 0) {
59+
NSMutableArray *drmURLArray = [NSMutableArray arrayWithCapacity:urlArray.count];
60+
for (NSDictionary *dict in urlArray) {
61+
if ([dict isKindOfClass:[NSDictionary class]]) {
62+
continue;
63+
}
64+
AdaptiveStream *stream = [[AdaptiveStream alloc] init];
65+
stream.url = dict[@"url"];
66+
stream.drmType = dict[@"type"];
67+
[drmURLArray addObject:stream];
68+
}
69+
ret.adaptiveStreamArray = drmURLArray;
70+
}
71+
}
72+
73+
//解析略缩图信息
74+
NSDictionary *imageSpriteInfo = media[@"imageSpriteInfo"];
75+
76+
if ([imageSpriteInfo isKindOfClass:[NSDictionary class]]) {
77+
NSString * vttURLString = J2Str(imageSpriteInfo[@"webVttUrl"]);
78+
NSURL * vttURL = [NSURL URLWithString:vttURLString];
79+
NSArray * imageURLStrings = J2Array(imageSpriteInfo[@"imageUrls"]);
80+
NSMutableArray<NSURL *> *imageURLs = [NSMutableArray arrayWithCapacity:imageURLStrings.count];
81+
for (NSString *urlString in imageURLStrings) {
82+
NSURL *url = [NSURL URLWithString:urlString];
83+
if (url) {
84+
[imageURLs addObject:url];
85+
}
86+
}
87+
TXImageSprite *sprite = [[TXImageSprite alloc] init];
88+
[sprite setVTTUrl:vttURL imageUrls:imageURLs];
89+
ret.imageSprite = sprite;
90+
}
91+
92+
//解析关键帧信息
93+
NSDictionary *keyFrameDescInfo = media[@"keyFrameDescInfo"];
94+
if ([keyFrameDescInfo isKindOfClass:[NSDictionary class]]) {
95+
NSArray *keyFrameDescList = keyFrameDescInfo[@"keyFrameDescList"];
96+
if ([keyFrameDescList isKindOfClass:[NSArray class]] && keyFrameDescList.count > 0) {
97+
ret.keyFrameDescList = [self parseKeyframeData:keyFrameDescList];
98+
}
99+
}
100+
} while (0);
101+
}
102+
return ret;
103+
}
104+
105+
+ (NSDictionary *)getStreamInfo:(NSString*) audioVideoType media:(NSDictionary*) media{
106+
NSDictionary *streamInfo;
107+
if ([audioVideoType isEqualToString:@"Original"]) { //原视频输出
108+
streamInfo = [media valueForKey:@"originalInfo"];
109+
}else if ([audioVideoType isEqualToString:@"Transcode"]){ //转码输出
110+
streamInfo = [media valueForKey:@"transcodeInfo"];
111+
}else{ //自适应码流输出
112+
streamInfo = [media valueForKeyPath:@"streamingInfo.plainOutput"];
113+
}
114+
return streamInfo;;
115+
}
116+
117+
+(NSMutableArray *) parseResolutionName:(NSArray*)subStreamDictArray{
118+
NSMutableArray *subStreamInfoArray = [NSMutableArray arrayWithCapacity:subStreamDictArray.count];
119+
for (NSDictionary *resInfo in subStreamDictArray) {
120+
SuperPlayerUrl *url = [[SuperPlayerUrl alloc] init];
121+
url.title = J2Str(resInfo[@"resolutionName"]);
122+
// SPSubStreamInfo *info = [SPSubStreamInfo infoWithDictionary:resInfo];
123+
[subStreamInfoArray addObject:url];
124+
}
125+
return subStreamInfoArray;
126+
}
127+
128+
+(NSMutableArray<SPVideoFrameDescription *> *) parseKeyframeData:(NSArray *)keyFrameDescList{
129+
NSMutableArray<SPVideoFrameDescription *> *videoPoints = [NSMutableArray array];
130+
for (NSDictionary *jsonObject in keyFrameDescList) {
131+
SPVideoFrameDescription *point = [SPVideoFrameDescription instanceFromDictionary:jsonObject];
132+
if (point) {
133+
[videoPoints addObject:point];
134+
}
135+
}
136+
return videoPoints;
137+
}
138+
139+
@end
140+

0 commit comments

Comments
 (0)