Skip to content

Commit 3f6d8bc

Browse files
author
zhaoyongqiang
committed
1.实现采集yuv本地视频, 2.实现渲染本地piexlBuffer 3.添加多路视频自采集
1 parent 47b088d commit 3f6d8bc

14 files changed

Lines changed: 726 additions & 19 deletions

File tree

iOS/APIExample/APIExample.xcodeproj/project.pbxproj

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@
142142
E728B84C28B6015800674A4A /* AgoraPictureInPictureController.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84B28B6015800674A4A /* AgoraPictureInPictureController.m */; };
143143
E728B84F28B601A300674A4A /* AgoraSampleBufferRender.m in Sources */ = {isa = PBXBuildFile; fileRef = E728B84E28B601A300674A4A /* AgoraSampleBufferRender.m */; };
144144
E728B85128B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E728B85028B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib */; };
145+
E728B85828B86B0700674A4A /* CustomVideoSourcePushMulti.strings in Resources */ = {isa = PBXBuildFile; fileRef = E728B85328B86B0700674A4A /* CustomVideoSourcePushMulti.strings */; };
146+
E728B85928B86B0700674A4A /* CustomVideoSourcePushMulti.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E728B85528B86B0700674A4A /* CustomVideoSourcePushMulti.storyboard */; };
147+
E728B85A28B86B0700674A4A /* CustomVideoSourcePushMulti.swift in Sources */ = {isa = PBXBuildFile; fileRef = E728B85728B86B0700674A4A /* CustomVideoSourcePushMulti.swift */; };
148+
E728B85C28B8971200674A4A /* sample.yuv in Resources */ = {isa = PBXBuildFile; fileRef = E728B85B28B8971200674A4A /* sample.yuv */; };
145149
E74877B328A23B2F00CA2F58 /* SimpleFilter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B10BE0D26AFFFA6002E1373 /* SimpleFilter.framework */; };
146150
E74877B728A23B8B00CA2F58 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74877B628A23B8B00CA2F58 /* NetworkManager.swift */; };
147151
E74877BA28A23C1400CA2F58 /* JSONObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74877B928A23C1400CA2F58 /* JSONObject.swift */; };
@@ -385,6 +389,10 @@
385389
E728B84D28B601A300674A4A /* AgoraSampleBufferRender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AgoraSampleBufferRender.h; sourceTree = "<group>"; };
386390
E728B84E28B601A300674A4A /* AgoraSampleBufferRender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AgoraSampleBufferRender.m; sourceTree = "<group>"; };
387391
E728B85028B60D5B00674A4A /* VideoViewSampleBufferDisplayView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VideoViewSampleBufferDisplayView.xib; sourceTree = "<group>"; };
392+
E728B85428B86B0700674A4A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/CustomVideoSourcePushMulti.strings"; sourceTree = "<group>"; };
393+
E728B85628B86B0700674A4A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/CustomVideoSourcePushMulti.storyboard; sourceTree = "<group>"; };
394+
E728B85728B86B0700674A4A /* CustomVideoSourcePushMulti.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomVideoSourcePushMulti.swift; sourceTree = "<group>"; };
395+
E728B85B28B8971200674A4A /* sample.yuv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sample.yuv; sourceTree = "<group>"; };
388396
E74877B628A23B8B00CA2F58 /* NetworkManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
389397
E74877B928A23C1400CA2F58 /* JSONObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONObject.swift; sourceTree = "<group>"; };
390398
E74877C928A2611C00CA2F58 /* ToastView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
@@ -670,6 +678,7 @@
670678
8B349FE22681E2CE007247F2 /* agora-logo.png */,
671679
576CA80925A9CC3A0091520B /* output.raw */,
672680
03414B5425546DEC00AB114D /* frames0.yuv */,
681+
E728B85B28B8971200674A4A /* sample.yuv */,
673682
03BEED0C251CAB9C005E78F4 /* audioeffect.mp3 */,
674683
03BEED0A251C4446005E78F4 /* audiomixing.mp3 */,
675684
);
@@ -933,6 +942,7 @@
933942
671BD6B227E1DB2D0076D5E1 /* CustomAudioRender */,
934943
033A9EF1252D61E200BC26E1 /* CustomVideoRender */,
935944
033A9EEF252D61E200BC26E1 /* CustomVideoSourcePush */,
945+
E728B85228B86B0700674A4A /* CustomVideoSourcePushMulti */,
936946
033A9EE3252D5C6900BC26E1 /* VideoMetadata */,
937947
034C625C2524A06800296ECF /* VoiceChanger */,
938948
038576772521E568003C369A /* MediaChannelRelay */,
@@ -970,6 +980,17 @@
970980
path = PictureInPicture;
971981
sourceTree = "<group>";
972982
};
983+
E728B85228B86B0700674A4A /* CustomVideoSourcePushMulti */ = {
984+
isa = PBXGroup;
985+
children = (
986+
E728B85328B86B0700674A4A /* CustomVideoSourcePushMulti.strings */,
987+
E728B85528B86B0700674A4A /* CustomVideoSourcePushMulti.storyboard */,
988+
E728B85728B86B0700674A4A /* CustomVideoSourcePushMulti.swift */,
989+
);
990+
name = CustomVideoSourcePushMulti;
991+
path = APIExample/Examples/Advanced/CustomVideoSourcePushMulti;
992+
sourceTree = SOURCE_ROOT;
993+
};
973994
E74877B528A23B8B00CA2F58 /* NetworkManager */ = {
974995
isa = PBXGroup;
975996
children = (
@@ -1158,6 +1179,7 @@
11581179
033A9F2A252D737900BC26E1 /* Localizable.strings in Resources */,
11591180
8BE7ABC2279E065000DFBCEF /* FusionCDN.strings in Resources */,
11601181
576EA54825AC3523000B3D79 /* CustomPcmAudioSource.storyboard in Resources */,
1182+
E728B85828B86B0700674A4A /* CustomVideoSourcePushMulti.strings in Resources */,
11611183
6709B23C2806BB4A000BCC58 /* RawAudioData.storyboard in Resources */,
11621184
033A9F7F252D8B5900BC26E1 /* AudioMixing.storyboard in Resources */,
11631185
E728B84728B5FFCB00674A4A /* PictureInPicture.strings in Resources */,
@@ -1168,8 +1190,10 @@
11681190
03BEED0D251CAB9C005E78F4 /* audioeffect.mp3 in Resources */,
11691191
A7CA48C424553CF700507435 /* Popover.storyboard in Resources */,
11701192
03D13BDC2448758B00B599B3 /* LaunchScreen.storyboard in Resources */,
1193+
E728B85C28B8971200674A4A /* sample.yuv in Resources */,
11711194
8BC751D5273E502700552265 /* LiveStreaming.strings in Resources */,
11721195
8B349FE32681E2CE007247F2 /* agora-logo.png in Resources */,
1196+
E728B85928B86B0700674A4A /* CustomVideoSourcePushMulti.storyboard in Resources */,
11731197
033A9F23252D70E400BC26E1 /* JoinChannelVideo.storyboard in Resources */,
11741198
03414B5525546DEC00AB114D /* frames0.yuv in Resources */,
11751199
8B5E5B53274CBF760040E97D /* VideoProcess.storyboard in Resources */,
@@ -1327,6 +1351,7 @@
13271351
6709B23B2806B0EA000BCC58 /* RawAudioData.swift in Sources */,
13281352
033A9EEA252D5F5E00BC26E1 /* JoinMultiChannel.swift in Sources */,
13291353
0339BE64251DCA3B007D4FDD /* GlobalSettings.swift in Sources */,
1354+
E728B85A28B86B0700674A4A /* CustomVideoSourcePushMulti.swift in Sources */,
13301355
E728B84C28B6015800674A4A /* AgoraPictureInPictureController.m in Sources */,
13311356
8407E0942472320800AC5DE8 /* (null) in Sources */,
13321357
8B5E5B50274CB68E0040E97D /* RhythmPlayer.swift in Sources */,
@@ -1731,6 +1756,22 @@
17311756
name = PictureInPicture.storyboard;
17321757
sourceTree = "<group>";
17331758
};
1759+
E728B85328B86B0700674A4A /* CustomVideoSourcePushMulti.strings */ = {
1760+
isa = PBXVariantGroup;
1761+
children = (
1762+
E728B85428B86B0700674A4A /* zh-Hans */,
1763+
);
1764+
name = CustomVideoSourcePushMulti.strings;
1765+
sourceTree = "<group>";
1766+
};
1767+
E728B85528B86B0700674A4A /* CustomVideoSourcePushMulti.storyboard */ = {
1768+
isa = PBXVariantGroup;
1769+
children = (
1770+
E728B85628B86B0700674A4A /* Base */,
1771+
);
1772+
name = CustomVideoSourcePushMulti.storyboard;
1773+
sourceTree = "<group>";
1774+
};
17341775
E7899BD72861673600851463 /* CreateDataStream.strings */ = {
17351776
isa = PBXVariantGroup;
17361777
children = (

iOS/APIExample/APIExample/Common/ExternalVideo/AgoraSampleBufferRender.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN
2020

2121
- (void)renderVideoData:(AgoraOutputVideoFrame *_Nonnull)videoData;
2222

23+
- (void)renderVideoPixelBuffer:(AgoraOutputVideoFrame *_Nonnull)videoData;
24+
2325
@end
2426

2527
NS_ASSUME_NONNULL_END

iOS/APIExample/APIExample/Common/ExternalVideo/AgoraSampleBufferRender.m

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,36 @@ - (void)renderVideoData:(AgoraOutputVideoFrame *_Nonnull)videoData {
152152
}
153153
}
154154

155+
- (void)renderVideoPixelBuffer:(AgoraOutputVideoFrame *_Nonnull)videoData {
156+
if (!videoData) {
157+
return;
158+
}
159+
160+
dispatch_async(dispatch_get_main_queue(), ^{
161+
self->_videoWidth = videoData.width;
162+
self->_videoHeight = videoData.height;
163+
164+
[self layoutDisplayLayer];
165+
});
166+
167+
@autoreleasepool {
168+
CVPixelBufferRef pixelBuffer = videoData.pixelBuffer;
169+
170+
CMVideoFormatDescriptionRef videoInfo;
171+
CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, &videoInfo);
172+
173+
CMSampleTimingInfo timingInfo;
174+
timingInfo.duration = kCMTimeZero;
175+
timingInfo.decodeTimeStamp = kCMTimeInvalid;
176+
timingInfo.presentationTimeStamp = CMTimeMake(CACurrentMediaTime()*1000, 1000);
177+
178+
CMSampleBufferRef sampleBuffer;
179+
CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault, pixelBuffer, videoInfo, &timingInfo, &sampleBuffer);
180+
181+
[self.displayLayer enqueueSampleBuffer:sampleBuffer];
182+
CMSampleBufferInvalidate(sampleBuffer);
183+
CFRelease(sampleBuffer);
184+
}
185+
}
186+
155187
@end

iOS/APIExample/APIExample/Common/ExternalVideo/AgoraYUVImageSourcePush.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ NS_ASSUME_NONNULL_BEGIN
1313

1414
@protocol AgoraYUVImageSourcePushDelegate <NSObject>
1515

16-
-(void)onVideoFrame:(NSData*)buffer size:(CGSize)size rotation:(int)rotation;
16+
-(void)onVideoFrame:(CVPixelBufferRef)buffer
17+
size:(CGSize)size
18+
trackId: (NSUInteger)trackId
19+
rotation:(int)rotation;
1720

1821
@end
1922

2023
@interface AgoraYUVImageSourcePush : NSObject
24+
- (instancetype)initWithSize: (CGSize)size fileName: (NSString *)fileName frameRate: (int)frameRate;
25+
@property(nonatomic, assign)UInt32 trackId;
2126
@property(nonatomic, weak)id<AgoraYUVImageSourcePushDelegate> delegate;
2227

2328
-(void)startSource;
2429
-(void)stopSource;
2530
@end
2631

32+
2733
NS_ASSUME_NONNULL_END

iOS/APIExample/APIExample/Common/ExternalVideo/AgoraYUVImageSourcePush.m

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,77 @@
77
//
88

99
#import "AgoraYUVImageSourcePush.h"
10+
#import <UIKit/UIKit.h>
11+
#import "MediaUtils.h"
1012

1113
@interface AgoraYUVImageSourcePush ()
1214
@property(nonatomic, strong) NSData* yuvData;
1315
@property(nonatomic, strong) NSTimer* timer;
16+
@property(nonatomic, assign) int videoW;
17+
@property(nonatomic, assign) int videoH;
18+
@property(nonatomic, strong)NSFileHandle *fileHandle;
19+
@property(nonatomic, assign) int frameRate;
20+
@property(nonatomic, copy) NSString *fileName;
1421
@end
1522

1623
@implementation AgoraYUVImageSourcePush
1724

18-
-(id)init
19-
{
25+
- (instancetype)initWithSize: (CGSize)size fileName: (NSString *)fileName frameRate: (int)frameRate {
2026
if(self = [super init]) {
21-
// initialize yuv data
22-
NSString *yuvPath = [[NSBundle mainBundle] pathForResource:@"frames0" ofType:@"yuv"];
23-
self.yuvData = [NSData dataWithContentsOfFile:yuvPath options:NSDataReadingUncached error:NULL];
27+
self.fileName = fileName;
28+
self.videoW = size.width;
29+
self.videoH = size.height;
30+
self.frameRate = frameRate;
31+
[self loadData];
2432
}
2533
return self;
2634
}
2735

36+
- (void)loadData {
37+
NSString *yuvPath = [[NSBundle mainBundle] pathForResource:self.fileName ofType:@"yuv"];
38+
self.fileHandle = [NSFileHandle fileHandleForReadingAtPath:yuvPath];
39+
}
40+
2841
-(void)startSource
2942
{
3043
if(self.timer) {
3144
return;
3245
}
46+
NSUInteger frameSizeY = self.videoW*self.videoH;
47+
NSUInteger frameSizeU = self.videoW*self.videoH/4;
48+
NSUInteger frameSizeV = self.videoW*self.videoH/4;
49+
50+
__block NSUInteger i = 0;
51+
NSTimeInterval sT = NSDate.date.timeIntervalSince1970;
52+
3353
__weak AgoraYUVImageSourcePush * weakSelf = self;
34-
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
54+
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.frameRate / 100.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
3555
if(weakSelf.delegate) {
36-
[weakSelf.delegate onVideoFrame:weakSelf.yuvData size:CGSizeMake(176, 144) rotation:0];
56+
NSData *dataY = [weakSelf.fileHandle readDataOfLength:frameSizeY];
57+
NSData *dataU = [weakSelf.fileHandle readDataOfLength:frameSizeU];
58+
NSData *dataV = [weakSelf.fileHandle readDataOfLength:frameSizeV];
59+
60+
if (dataY.length==0 || dataV.length==0 || dataU.length==0) {
61+
i = 0;
62+
[weakSelf loadData];
63+
dataY = [weakSelf.fileHandle readDataOfLength:frameSizeY];
64+
dataU = [weakSelf.fileHandle readDataOfLength:frameSizeU];
65+
dataV = [weakSelf.fileHandle readDataOfLength:frameSizeV];
66+
}
67+
CVPixelBufferRef pixelBuffer = [MediaUtils i420ToPixelBuffer:(void *)dataY.bytes
68+
srcU:(void *)dataU.bytes
69+
srcV:(void *)dataV.bytes
70+
width:weakSelf.videoW
71+
height:weakSelf.videoH];
72+
[weakSelf.delegate onVideoFrame:pixelBuffer size:CGSizeMake(weakSelf.videoW, weakSelf.videoH) trackId: self.trackId rotation:0];
73+
CVPixelBufferRelease(pixelBuffer);
74+
NSTimeInterval cT = NSDate.date.timeIntervalSince1970;
75+
NSTimeInterval dT = cT-sT;
76+
NSTimeInterval tT = i/25.0;
77+
if (dT<tT) {
78+
[NSThread sleepForTimeInterval:tT-dT];
79+
}
80+
i++;
3781
}
3882
}];
3983
}

iOS/APIExample/APIExample/Common/Utils/MediaUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ NS_ASSUME_NONNULL_BEGIN
1313

1414
@interface MediaUtils : NSObject
1515

16+
+ (CVPixelBufferRef)i420ToPixelBuffer:(void *)srcY srcU:(void *)srcU srcV:(void *)srcV width:(int)width height:(int)height;
1617
+ (nullable UIImage *)i420ToImage:(nullable void *)srcY srcU:(nullable void *)srcU srcV:(nullable void *)srcV width:(int)width height:(int)height;
1718
+ (nullable UIImage *)pixelBufferToImage:(CVPixelBufferRef)pixelBuffer;
1819

20+
+ (CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img;
21+
1922
@end
2023

2124
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)