Compare commits

...

15 Commits

Author SHA1 Message Date
chenliming 40b1f7d37f update 2016-07-13 11:58:53 +08:00
chenliming 5d9bbd2b5b update 2016-07-12 17:17:26 +08:00
chenliming 909b49c8e9 声明。。。 2016-07-12 16:25:04 +08:00
chenliming aea2fe1a7e ... 2016-07-12 16:11:12 +08:00
chenliming 3279030e13 update 2016-07-12 16:08:29 +08:00
chenliming 135910e1d0 update version 2016-07-12 16:07:49 +08:00
chenliming 5f893de671 add error callback 2016-07-12 16:05:23 +08:00
小歪~~~ 55e896a4b6 Merge pull request #8 from toss156/master
优化美颜,美颜程度可调节,  调整默认参数配置
2016-07-12 14:08:57 +08:00
toss156 759daed2bc 调整默认参数配置 2016-07-12 13:26:01 +08:00
toss156 392770247c 优化美颜,美颜程度可调节 2016-07-12 11:58:11 +08:00
feng c3d506c2f6 Merge pull request #2 from LaiFengiOS/master
update to last version
2016-07-11 15:43:59 +08:00
chenliming a60d7c504c 删除几个⚠️ 2016-07-11 12:00:52 +08:00
chenliming 9a4270ccb7 优化丢帧策略 2016-07-11 11:02:54 +08:00
chenliming 270a23218e 修改丢帧一个小bug 2016-07-07 19:45:06 +08:00
feng 8aa0091432 Merge pull request #1 from LaiFengiOS/master
update to last version
2016-06-24 09:46:39 +08:00
17 changed files with 444 additions and 113 deletions
+2 -2
View File
@@ -2,7 +2,7 @@
Pod::Spec.new do |s|
s.name = "LFLiveKit"
s.version = "1.6"
s.version = "1.6.5"
s.summary = "LaiFeng ios Live. LFLiveKit."
s.homepage = "https://github.com/chenliming777"
s.license = { :type => "MIT", :file => "LICENSE" }
@@ -19,7 +19,7 @@ Pod::Spec.new do |s|
s.requires_arc = true
s.dependency "CocoaAsyncSocket", "~> 7.4.1"
s.dependency 'LMGPUImage', '~> 0.1.9'
s.dependency "GPUImage", :git=>"https://github.com/BradLarson/GPUImage"
s.dependency "pili-librtmp", "~> 1.0.2"
end
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.6</string>
<string>1.6.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+15
View File
@@ -60,6 +60,21 @@ typedef NS_ENUM(NSUInteger, LFLiveType){
/** The beautyFace control capture shader filter empty or beautiy */
@property (nonatomic, assign) BOOL beautyFace;
/** The beautyLevel control beautyFace Level, default 0.5, between 0.0 ~ 1.0 */
@property (nonatomic, assign) CGFloat beautyLevel;
/** The brightLevel control brightness Level, default 0.5, between 0.0 ~ 1.0 */
@property (nonatomic, assign) CGFloat brightLevel;
/** The torch control camera zoom scale default 1.0, between 1.0 ~ 3.0 */
@property (nonatomic, assign) CGFloat zoomScale;
/** The torch control capture flash is on or off */
@property (nonatomic, assign) BOOL torch;
/** The mirror control mirror of front camera is on or off */
@property (nonatomic, assign) BOOL mirror;
/** The muted control callbackAudioData,muted will memset 0.*/
@property (nonatomic,assign) BOOL muted;
+45 -5
View File
@@ -14,6 +14,7 @@
#import "LFStreamRtmpSocket.h"
#import "LFStreamTcpSocket.h"
#import "LFLiveStreamInfo.h"
#import "LFGPUImageBeautyFilter.h"
#define LFLiveReportKey @"com.youku.liveSessionReport"
@@ -153,12 +154,12 @@
NSUInteger videoBitRate = [_videoEncoder videoBitRate];
if(status == LFLiveBuffferIncrease){
if(videoBitRate < _videoConfiguration.videoMaxBitRate){
videoBitRate = videoBitRate + 50*1024;
videoBitRate = videoBitRate + 50 * 1000;
[_videoEncoder setVideoBitRate:videoBitRate];
}
}else{
if(videoBitRate > _videoConfiguration.videoMinBitRate){
videoBitRate = videoBitRate - 100*1024;
videoBitRate = videoBitRate - 100 * 1000;
[_videoEncoder setVideoBitRate:videoBitRate];
}
}
@@ -198,6 +199,46 @@
return self.videoCaptureSource.beautyFace;
}
- (void)setBeautyLevel:(CGFloat)beautyLevel {
[self.videoCaptureSource setBeautyLevel:beautyLevel];
}
- (CGFloat)beautyLevel {
return self.videoCaptureSource.beautyLevel;
}
- (void)setBrightLevel:(CGFloat)brightLevel {
[self.videoCaptureSource setBrightLevel:brightLevel];
}
- (CGFloat)brightLevel {
return self.videoCaptureSource.brightLevel;
}
- (void)setZoomScale:(CGFloat)zoomScale {
[self.videoCaptureSource setZoomScale:zoomScale];
}
- (CGFloat)zoomScale {
return self.videoCaptureSource.zoomScale;
}
- (void)setTorch:(BOOL)torch {
[self.videoCaptureSource setTorch:torch];
}
- (BOOL)torch {
return self.videoCaptureSource.torch;
}
- (void)setMirror:(BOOL)mirror {
[self.videoCaptureSource setMirror:mirror];
}
- (BOOL)mirror {
return self.videoCaptureSource.mirror;
}
- (void)setMuted:(BOOL)muted{
[self.audioCaptureSource setMuted:muted];
}
@@ -241,7 +282,7 @@
- (id<LFStreamSocket>)socket{
if(!_socket){
if(self.liveType == LFLiveRTMP){
_socket = [[LFStreamRtmpSocket alloc] initWithStream:self.streamInfo];
_socket = [[LFStreamRtmpSocket alloc] initWithStream:self.streamInfo videoSize:self.videoConfiguration.videoSize reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
}else if(self.liveType == LFLiveFLV){
_socket = [[LFStreamTcpSocket alloc] initWithStream:self.streamInfo videoSize:self.videoConfiguration.videoSize reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
}
@@ -264,8 +305,7 @@
_timestamp = NOW;
_isFirstFrame = false;
currentts = 0;
}
else {
} else {
currentts = NOW - _timestamp;
}
dispatch_semaphore_signal(_lock);
+3 -2
View File
@@ -86,8 +86,8 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
AURenderCallbackStruct cb;
cb.inputProcRefCon = (__bridge void *)(self);
cb.inputProc = handleInputBuffer;
status = AudioUnitSetProperty(self.componetInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desc, sizeof(desc));
status = AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 1, &cb, sizeof(cb));
AudioUnitSetProperty(self.componetInstance, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &desc, sizeof(desc));
AudioUnitSetProperty(self.componetInstance, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 1, &cb, sizeof(cb));
status = AudioUnitInitialize(self.componetInstance);
@@ -168,6 +168,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
seccReason = @"The reason for the change is unknown.";
break;
}
NSLog(@"handleRouteChange reason is %@",seccReason);
AVAudioSessionPortDescription *input = [[session.currentRoute.inputs count]?session.currentRoute.inputs:nil objectAtIndex:0];
if (input.portType == AVAudioSessionPortHeadsetMic) {
+15
View File
@@ -38,6 +38,21 @@
/** The beautyFace control capture shader filter empty or beautiy */
@property (nonatomic, assign) BOOL beautyFace;
/** The torch control capture flash is on or off */
@property (nonatomic, assign) BOOL torch;
/** The mirror control mirror of front camera is on or off */
@property (nonatomic, assign) BOOL mirror;
/** The beautyLevel control beautyFace Level, default 0.5, between 0.0 ~ 1.0 */
@property (nonatomic, assign) CGFloat beautyLevel;
/** The brightLevel control brightness Level, default 0.5, between 0.0 ~ 1.0 */
@property (nonatomic, assign) CGFloat brightLevel;
/** The torch control camera zoom scale default 1.0, between 1.0 ~ 3.0 */
@property (nonatomic, assign) CGFloat zoomScale;
/** The videoFrameRate control videoCapture output data count */
@property (nonatomic, assign) NSInteger videoFrameRate;
+76 -2
View File
@@ -14,6 +14,7 @@
@interface LFVideoCapture ()
@property(nonatomic, strong) GPUImageVideoCamera *videoCamera;
@property(nonatomic, weak) LFGPUImageBeautyFilter *beautyFilter;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
@property(nonatomic, strong) GPUImageCropFilter *cropfilter;
@@ -23,6 +24,10 @@
@end
@implementation LFVideoCapture
@synthesize torch = _torch;
@synthesize beautyLevel = _beautyLevel;
@synthesize brightLevel = _brightLevel;
@synthesize zoomScale = _zoomScale;
#pragma mark -- LifeCycle
- (instancetype)initWithVideoConfiguration:(LFLiveVideoConfiguration *)configuration{
@@ -43,6 +48,9 @@
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil];
self.beautyFace = YES;
self.beautyLevel = 0.5;
self.brightLevel = 0.5;
self.zoomScale = 1.0;
}
return self;
}
@@ -100,6 +108,72 @@
return _videoCamera.frameRate;
}
- (void)setTorch:(BOOL)torch {
BOOL ret;
if(!_videoCamera.captureSession) return;
AVCaptureSession* session = (AVCaptureSession*)_videoCamera.captureSession;
[session beginConfiguration];
if (_videoCamera.inputCamera) {
if (_videoCamera.inputCamera.torchAvailable) {
NSError* err = nil;
if ([_videoCamera.inputCamera lockForConfiguration:&err]) {
[_videoCamera.inputCamera setTorchMode:( torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff ) ];
[_videoCamera.inputCamera unlockForConfiguration];
ret = (_videoCamera.inputCamera.torchMode == AVCaptureTorchModeOn);
} else {
NSLog(@"Error while locking device for torch: %@", err);
ret = false;
}
} else {
NSLog(@"Torch not available in current camera input");
}
}
[session commitConfiguration];
_torch = ret;
}
- (BOOL)torch {
return _videoCamera.inputCamera.torchMode;
}
- (void)setMirror:(BOOL)mirror {
_videoCamera.horizontallyMirrorFrontFacingCamera = mirror;
_videoCamera.horizontallyMirrorRearFacingCamera = mirror;
}
- (BOOL)mirror {
return _videoCamera.horizontallyMirrorFrontFacingCamera;
}
- (void)setBeautyLevel:(CGFloat)beautyLevel {
_beautyLevel = beautyLevel;
if (_beautyFilter) {
[_beautyFilter setBeautyLevel:_beautyLevel];
}
}
- (CGFloat)beautyLevel {
return _beautyLevel;
}
- (void)setBrightLevel:(CGFloat)brightLevel {
_brightLevel = brightLevel;
if (_beautyFilter) {
[_beautyFilter setBrightLevel:brightLevel];
}
}
- (CGFloat)brightLevel {
return _brightLevel;
}
- (void)setZoomScale:(CGFloat)zoomScale {
if (self.videoCamera && self.videoCamera.inputCamera) {
AVCaptureDevice* device = (AVCaptureDevice*)self.videoCamera.inputCamera;
if ([device lockForConfiguration:nil]) {
device.videoZoomFactor = zoomScale;
[device unlockForConfiguration];
_zoomScale = zoomScale;
}
}
}
- (CGFloat)zoomScale {
return _zoomScale;
}
- (void)setBeautyFace:(BOOL)beautyFace{
if(_beautyFace == beautyFace) return;
@@ -111,14 +185,14 @@
if (_beautyFace) {
_output = [[LFGPUImageEmptyFilter alloc] init];
_filter = [[LFGPUImageBeautyFilter alloc] init];
_beautyFilter = _filter;
__weak typeof(self) _self = self;
[_output setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
[_self processVideo:output];
}];
} else {
_filter = [[LFGPUImageEmptyFilter alloc] init];
_beautyFilter = nil;
__weak typeof(self) _self = self;
[_filter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
[_self processVideo:output];
+1 -1
View File
@@ -129,7 +129,7 @@
uint32_t count = size / sizeof(AudioClassDescription);
AudioClassDescription descs[count];
status = AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, descs);
AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, descs);
for (uint32_t i = 0; i < count; i++){
if ((type == descs[i].mSubType) && (manufacturer == descs[i].mManufacturer)){
memcpy(&audioDesc, &descs[i], sizeof(audioDesc));
+9 -9
View File
@@ -59,16 +59,16 @@
}
_currentVideoBitRate = _configuration.videoBitRate;
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ExpectedFrameRate, (__bridge CFTypeRef)@(_configuration.videoFrameRate));
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(_configuration.videoBitRate));
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ExpectedFrameRate, (__bridge CFTypeRef)@(_configuration.videoFrameRate));
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(_configuration.videoBitRate));
NSArray *limit = @[@(_configuration.videoBitRate * 1.5/8),@(1)];
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)limit);
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanFalse);
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Main_AutoLevel);
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanFalse);
status = VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_H264EntropyMode, kVTH264EntropyMode_CABAC);
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)limit);
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanFalse);
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Main_AutoLevel);
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanFalse);
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_H264EntropyMode, kVTH264EntropyMode_CABAC);
VTCompressionSessionPrepareToEncodeFrames(compressionSession);
}
@@ -31,9 +31,10 @@
configuration.videoFrameRate = 15;
configuration.videoMaxFrameRate = 15;
configuration.videoMinFrameRate = 10;
configuration.videoBitRate = 500 * 1024;
configuration.videoMaxBitRate = 600 * 1024;
configuration.videoMinBitRate = 250 * 1024;
configuration.videoBitRate = 500 * 1000;
configuration.videoMaxBitRate = 600 * 1000;
configuration.videoMinBitRate = 400 * 1000;
configuration.videoSize = CGSizeMake(360, 640);
}
break;
case LFLiveVideoQuality_Low2:
@@ -42,9 +43,10 @@
configuration.videoFrameRate = 24;
configuration.videoMaxFrameRate = 24;
configuration.videoMinFrameRate = 12;
configuration.videoBitRate = 800 * 1024;
configuration.videoMaxBitRate = 900 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 600 * 1000;
configuration.videoMaxBitRate = 720 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(360, 640);
}
break;
case LFLiveVideoQuality_Low3:
@@ -53,9 +55,10 @@
configuration.videoFrameRate = 30;
configuration.videoMaxFrameRate = 30;
configuration.videoMinFrameRate = 15;
configuration.videoBitRate = 800 * 1024;
configuration.videoMaxBitRate = 900 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 800 * 1000;
configuration.videoMaxBitRate = 960 * 1000;
configuration.videoMinBitRate = 600 * 1000;
configuration.videoSize = CGSizeMake(360, 640);
}
break;
case LFLiveVideoQuality_Medium1:
@@ -64,9 +67,10 @@
configuration.videoFrameRate = 15;
configuration.videoMaxFrameRate = 15;
configuration.videoMinFrameRate = 10;
configuration.videoBitRate = 800 * 1024;
configuration.videoMaxBitRate = 900 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 800 * 1000;
configuration.videoMaxBitRate = 960 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(540, 960);
}
break;
case LFLiveVideoQuality_Medium2:
@@ -75,9 +79,10 @@
configuration.videoFrameRate = 24;
configuration.videoMaxFrameRate = 24;
configuration.videoMinFrameRate = 12;
configuration.videoBitRate = 800 * 1024;
configuration.videoMaxBitRate = 900 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 800 * 1000;
configuration.videoMaxBitRate = 960 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(540, 960);
}
break;
case LFLiveVideoQuality_Medium3:
@@ -86,9 +91,10 @@
configuration.videoFrameRate = 30;
configuration.videoMaxFrameRate = 30;
configuration.videoMinFrameRate = 15;
configuration.videoBitRate = 1000 * 1024;
configuration.videoMaxBitRate = 1200 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 1000 * 1000;
configuration.videoMaxBitRate = 1200 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(540, 960);
}
break;
case LFLiveVideoQuality_High1:
@@ -97,9 +103,10 @@
configuration.videoFrameRate = 15;
configuration.videoMaxFrameRate = 15;
configuration.videoMinFrameRate = 10;
configuration.videoBitRate = 1000 * 1024;
configuration.videoMaxBitRate = 1200 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 1000 * 1000;
configuration.videoMaxBitRate = 1200 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(720, 1280);
}
break;
case LFLiveVideoQuality_High2:
@@ -108,9 +115,10 @@
configuration.videoFrameRate = 24;
configuration.videoMaxFrameRate = 24;
configuration.videoMinFrameRate = 12;
configuration.videoBitRate = 1200 * 1024;
configuration.videoMaxBitRate = 1300 * 1024;
configuration.videoMinBitRate = 800 * 1024;
configuration.videoBitRate = 1200 * 1000;
configuration.videoMaxBitRate = 1440 * 1000;
configuration.videoMinBitRate = 800 * 1000;
configuration.videoSize = CGSizeMake(720, 1280);
}
break;
case LFLiveVideoQuality_High3:
@@ -119,9 +127,10 @@
configuration.videoFrameRate = 30;
configuration.videoMaxFrameRate = 30;
configuration.videoMinFrameRate = 15;
configuration.videoBitRate = 1200 * 1024;
configuration.videoMaxBitRate = 1300 * 1024;
configuration.videoMinBitRate = 500 * 1024;
configuration.videoBitRate = 1200 * 1000;
configuration.videoMaxBitRate = 1440 * 1000;
configuration.videoMinBitRate = 500 * 1000;
configuration.videoSize = CGSizeMake(720, 1280);
}
break;
default:
@@ -130,10 +139,11 @@
configuration.sessionPreset = [configuration supportSessionPreset:configuration.sessionPreset];
configuration.videoMaxKeyframeInterval = configuration.videoFrameRate*2;
configuration.orientation = orientation;
CGSize size = configuration.videoSize;
if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown){
configuration.videoSize = CGSizeMake(368, 640);
configuration.videoSize = CGSizeMake(size.width, size.height);
}else{
configuration.videoSize = CGSizeMake(640, 368);
configuration.videoSize = CGSizeMake(size.height, size.width);
}
return configuration;
}
+3 -2
View File
@@ -3,6 +3,7 @@
@interface LFGPUImageBeautyFilter : GPUImageFilter {
}
@property (nonatomic, assign) NSInteger beautyLevel;
@property (nonatomic, assign) CGFloat beautyLevel;
@property (nonatomic, assign) CGFloat brightLevel;
@property (nonatomic, assign) CGFloat toneLevel;
@end
+89 -37
View File
@@ -8,13 +8,17 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
uniform sampler2D inputImageTexture;
uniform highp vec2 singleStepOffset;
uniform mediump float params;
uniform highp vec4 params;
uniform highp float brightness;
const highp vec3 W = vec3(0.299,0.587,0.114);
highp vec2 blurCoordinates[20];
const highp mat3 saturateMatrix = mat3(
1.1102,-0.0598,-0.061,
-0.0774,1.0826,-0.1186,
-0.0228,-0.0228,1.1772);
highp vec2 blurCoordinates[24];
highp float hardLight(highp float color)
{
highp float hardLight(highp float color) {
if(color <= 0.5)
color = color * color * 2.0;
else
@@ -45,8 +49,12 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
highp float sampleColor = centralColor.g * 20.0;
highp float sampleColor = centralColor.g * 22.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
@@ -67,8 +75,12 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
sampleColor = sampleColor / 48.0;
sampleColor = sampleColor / 62.0;
highp float highPass = centralColor.g - sampleColor + 0.5;
@@ -76,13 +88,27 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
{
highPass = hardLight(highPass);
}
highp float luminance = dot(centralColor, W);
highp float lumance = dot(centralColor, W);
highp float alpha = pow(luminance, params);
highp float alpha = pow(lumance, params.r);
highp vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
gl_FragColor = vec4(mix(smoothColor.rgb, max(smoothColor, centralColor), alpha), 1.0);
smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0);
smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0);
smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0);
highp vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
highp vec3 bianliang = max(smoothColor, centralColor);
highp vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
highp vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
}
);
#else
@@ -93,10 +119,14 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
uniform sampler2D inputImageTexture;
uniform mediump vec2 singleStepOffset;
uniform mediump float params;
uniform mediump vec4 params;
uniform mediump float brightness;
const mediump mat3 saturateMatrix = mat3(
1.1102,-0.0598,-0.061,
-0.0774,1.0826,-0.1186,
-0.0228,-0.0228,1.1772);
const mediump vec3 W = vec3(0.299,0.587,0.114);
mediump vec2 blurCoordinates[20];
mediump vec2 blurCoordinates[24];
mediump float hardLight(mediump float color)
{
@@ -130,8 +160,12 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
mediump float sampleColor = centralColor.g * 20.0;
mediump float sampleColor = centralColor.g * 22.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
@@ -152,8 +186,12 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
sampleColor = sampleColor / 48.0;
sampleColor = sampleColor / 62.0;
mediump float highPass = centralColor.g - sampleColor + 0.5;
@@ -167,7 +205,21 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
mediump vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
gl_FragColor = vec4(mix(smoothColor.rgb, max(smoothColor, centralColor), alpha), 1.0);
smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0);
smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0);
smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0);
mediump vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
mediump vec3 bianliang = max(smoothColor, centralColor);
mediump vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
mediump vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
}
);
#endif
@@ -181,9 +233,11 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
return nil;
}
self.beautyLevel = 2
;
_toneLevel = 0.5;
_beautyLevel = 0.5;
_brightLevel = 0.5;
[self setParams:_beautyLevel tone:_toneLevel];
[self setBrightLevel:_brightLevel];
return self;
}
@@ -197,27 +251,25 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
[self setPoint:offset forUniformName:@"singleStepOffset"];
}
- (void)setBeautyLevel:(NSInteger)level
- (void)setBeautyLevel:(CGFloat)beautyLevel
{
switch (level) {
case 1:
[self setFloat:1.0f forUniformName:@"params"];
break;
case 2:
[self setFloat:0.8f forUniformName:@"params"];
break;
case 3:
[self setFloat:0.6f forUniformName:@"params"];
break;
case 4:
[self setFloat:0.4f forUniformName:@"params"];
break;
case 5:
[self setFloat:0.33f forUniformName:@"params"];
break;
default:
break;
_beautyLevel = beautyLevel;
[self setParams:_beautyLevel tone:_toneLevel];
}
- (void)setBrightLevel:(CGFloat)brightLevel
{
_brightLevel = brightLevel;
[self setFloat:0.6 * (-0.5 + brightLevel) forUniformName:@"brightness"];
}
- (void)setParams:(CGFloat)beauty tone:(CGFloat)tone {
GPUVector4 fBeautyParam;
fBeautyParam.one = 1.0 - 0.6 * beauty;
fBeautyParam.two = 1.0 - 0.3 * beauty;
fBeautyParam.three = 0.1 + 0.3 * tone;
fBeautyParam.four = 0.1 + 0.3 * tone;
[self setFloatVec4:fBeautyParam forUniform:@"params"];
}
@end
+99 -12
View File
@@ -9,6 +9,9 @@
#import "LFStreamRtmpSocket.h"
#import "rtmp.h"
static const NSInteger RetryTimesBreaken = 20;///< 重连1分钟 3秒一次 一共20次
static const NSInteger RetryTimesMargin = 3;
#define DATA_ITEMS_MAX_COUNT 100
#define RTMP_DATA_RESERVE_SIZE 400
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE)
@@ -16,7 +19,7 @@
#define SAVC(x) static const AVal av_##x = AVC(#x)
static const AVal av_setDataFrame = AVC("@setDataFrame");
static const AVal av_SDKVersion = AVC("LFLiveKit 1.5.2");
static const AVal av_SDKVersion = AVC("LFLiveKit 1.6");
SAVC(onMetaData);
SAVC(duration);
SAVC(width);
@@ -44,9 +47,12 @@ SAVC(mp4a);
@property (nonatomic, strong) LFLiveStreamInfo *stream;
@property (nonatomic, strong) LFStreamingBuffer *buffer;
@property (nonatomic, strong) dispatch_queue_t socketQueue;
@property (nonatomic, strong) LFLiveDebug *debugInfo;
//错误信息
@property (nonatomic, assign) RTMPError error;
@property (nonatomic, assign) NSInteger retryTimes4netWorkBreaken;
@property (nonatomic, assign) NSInteger reconnectInterval;
@property (nonatomic, assign) NSInteger reconnectCount;
@property (nonatomic, assign) BOOL isSending;
@property (nonatomic, assign) BOOL isConnected;
@@ -56,15 +62,22 @@ SAVC(mp4a);
@property (nonatomic, assign) BOOL sendVideoHead;
@property (nonatomic, assign) BOOL sendAudioHead;
@end
@implementation LFStreamRtmpSocket
#pragma mark -- LFStreamSocket
- (instancetype)initWithStream:(LFLiveStreamInfo*)stream{
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo*)stream videoSize:(CGSize)videoSize reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount{
if(!stream) @throw [NSException exceptionWithName:@"LFStreamRtmpSocket init error" reason:@"stream is nil" userInfo:nil];
if(self = [super init]){
_stream = stream;
if(reconnectInterval > 0) _reconnectInterval = reconnectInterval;
else _reconnectInterval = RetryTimesMargin;
if(reconnectCount > 0) _reconnectCount = reconnectCount;
else _reconnectCount = RetryTimesBreaken;
}
return self;
}
@@ -74,7 +87,10 @@ SAVC(mp4a);
if(!_stream) return;
if(_isConnecting) return;
if(_rtmp != NULL) return;
self.debugInfo.streamId = self.stream.streamId;
self.debugInfo.uploadUrl = self.stream.url;
self.debugInfo.isRtmp = YES;
[self clean];
[self RTMP264_Connect:(char*)[_stream.url cStringUsingEncoding:NSASCIIStringEncoding]];
});
}
@@ -86,7 +102,6 @@ SAVC(mp4a);
PILI_RTMP_Free(_rtmp);
_rtmp = NULL;
}
[self clean];
});
}
@@ -108,9 +123,9 @@ SAVC(mp4a);
- (void)sendFrame{
if(!self.isSending && self.buffer.list.count > 0){
self.isSending = YES;
if(!_isConnected || _isReconnecting || _isConnecting || !_rtmp) return;
// 调用发送接口
LFFrame *frame = [self.buffer popFirstObject];
if([frame isKindOfClass:[LFVideoFrame class]]){
@@ -129,6 +144,28 @@ SAVC(mp4a);
}
}
self.debugInfo.dataFlow += frame.data.length;
if(CACurrentMediaTime()*1000 - self.debugInfo.timeStamp < 1000) {
self.debugInfo.bandwidth += frame.data.length;
if([frame isKindOfClass:[LFAudioFrame class]]){
self.debugInfo.capturedAudioCount ++;
}else{
self.debugInfo.capturedVideoCount ++;
}
self.debugInfo.unSendCount = self.buffer.list.count;
}else {
self.debugInfo.currentBandwidth = self.debugInfo.bandwidth;
self.debugInfo.currentCapturedAudioCount = self.debugInfo.capturedAudioCount;
self.debugInfo.currentCapturedVideoCount = self.debugInfo.capturedVideoCount;
if(self.delegate && [self.delegate respondsToSelector:@selector(socketDebug:debugInfo:)]){
[self.delegate socketDebug:self debugInfo:self.debugInfo];
}
self.debugInfo.bandwidth = 0;
self.debugInfo.capturedAudioCount = 0;
self.debugInfo.capturedVideoCount = 0;
self.debugInfo.timeStamp = CACurrentMediaTime()*1000;
}
}
}
@@ -139,6 +176,7 @@ SAVC(mp4a);
_isConnected = NO;
_sendAudioHead = NO;
_sendVideoHead = NO;
self.debugInfo = nil;
[self.buffer removeAllObject];
self.retryTimes4netWorkBreaken = 0;
}
@@ -167,6 +205,10 @@ SAVC(mp4a);
goto Failed;
}
_rtmp->m_errorCallback = RTMPErrorCallback;
_rtmp->m_connCallback = ConnectionTimeCallback;
_rtmp->m_userData = (__bridge void*)self;
_rtmp->m_msgCounter = 1;
//设置可写,即发布流,这个函数必须在连接前使用,否则无效
PILI_RTMP_EnableWrite(_rtmp);
@@ -196,10 +238,6 @@ SAVC(mp4a);
Failed:
PILI_RTMP_Close(_rtmp, &_error);
PILI_RTMP_Free(_rtmp);
[self clean];
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveError];
}
return -1;
}
@@ -251,7 +289,7 @@ Failed:
*enc++ = 0;
*enc++ = 0;
*enc++ = AMF_OBJECT_END;
packet.m_nBodySize = enc - packet.m_body;
if(!PILI_RTMP_SendPacket(_rtmp, &packet, FALSE, &_error)) {
return;
@@ -268,7 +306,7 @@ Failed:
const char *pps = videoFrame.pps.bytes;
NSInteger sps_len = videoFrame.sps.length;
NSInteger pps_len = videoFrame.pps.length;
body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
@@ -398,6 +436,48 @@ Failed:
free(body);
}
// 断线重连
-(void) reconnect {
_isReconnecting = NO;
if(_isConnected) return;
if(_rtmp){
PILI_RTMP_ReconnectStream(_rtmp, 0, &_error);
}else{
[self stop];
[self start];
}
}
#pragma mark -- CallBack
void RTMPErrorCallback(RTMPError *error, void *userData){
LFStreamRtmpSocket *socket = (__bridge LFStreamRtmpSocket*)userData;
if(error->code == RTMPErrorSocketClosedByPeer){
[socket stop];
if(socket.delegate && [socket.delegate respondsToSelector:@selector(socketStatus:status:)]){
[socket.delegate socketStatus:socket status:LFLiveError];
}
}else{
if(socket.retryTimes4netWorkBreaken++ < socket.reconnectCount && !socket.isReconnecting){
socket.isConnected = NO;
socket.isConnecting = NO;
socket.isReconnecting = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(socket.reconnectInterval * NSEC_PER_SEC)), socket.socketQueue, ^{
[socket reconnect];
});
}else if(socket.retryTimes4netWorkBreaken >= socket.reconnectCount){
if(socket.delegate && [socket.delegate respondsToSelector:@selector(socketStatus:status:)]){
[socket.delegate socketStatus:socket status:LFLiveError];
}
if(socket.delegate && [socket.delegate respondsToSelector:@selector(socketDidError:errorCode:)]){
[socket.delegate socketDidError:socket errorCode:LFLiveSocketError_ReConnectTimeOut];
}
}
}
}
void ConnectionTimeCallback(PILI_CONNECTION_TIME* conn_time, void *userData){
//LFStreamRtmpSocket *socket = (__bridge LFStreamRtmpSocket*)userData;
}
#pragma mark -- Getter Setter
- (dispatch_queue_t)socketQueue{
@@ -415,4 +495,11 @@ Failed:
return _buffer;
}
- (LFLiveDebug*)debugInfo{
if(!_debugInfo){
_debugInfo = [[LFLiveDebug alloc] init];
}
return _debugInfo;
}
@end
+11 -7
View File
@@ -94,9 +94,9 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
return;
}
LFFrame *firstIFrame = [self firstIFrame];
if(firstIFrame){
[self.list removeObject:firstIFrame];
NSArray *iFrames = [self expireIFrames];///<  删除一个I帧(但一个I帧可能对应多个nal)
if(iFrames){
[self.list removeObjectsInArray:iFrames];
return;
}
@@ -111,7 +111,7 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
LFVideoFrame *videoFrame = (LFVideoFrame*)frame;
if(videoFrame.isKeyFrame && pframes.count > 0){
break;
}else{
}else if(!videoFrame.isKeyFrame){
[pframes addObject:frame];
}
}
@@ -119,14 +119,18 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
return pframes;
}
- (LFFrame*)firstIFrame{
- (NSArray*)expireIFrames{
NSMutableArray *iframes = [[NSMutableArray alloc] init];
uint64_t timeStamp = 0;
for(NSInteger index = 0;index < self.list.count;index++){
LFFrame *frame = [self.list objectAtIndex:index];
if([frame isKindOfClass:[LFVideoFrame class]] && ((LFVideoFrame*)frame).isKeyFrame){
return frame;
if(timeStamp != 0 && timeStamp != frame.timestamp) break;
[iframes addObject:frame];
timeStamp = frame.timestamp;
}
}
return nil;
return iframes;
}
NSInteger frameDataCompare(id obj1, id obj2, void *context){
+35 -3
View File
@@ -20,6 +20,7 @@
@property (nonatomic, strong) UIView *containerView;
@property (nonatomic, strong) LFLiveDebug *debugInfo;
@property (nonatomic, strong) LFLiveSession *session;
@property (nonatomic, strong) UILabel *stateLabel;
@end
@@ -31,6 +32,7 @@
[self requestAccessForVideo];
[self requestAccessForAudio];
[self addSubview:self.containerView];
[self.containerView addSubview:self.stateLabel];
[self.containerView addSubview:self.closeButton];
[self.containerView addSubview:self.cameraButton];
[self.containerView addSubview:self.beautyButton];
@@ -93,17 +95,36 @@
#pragma mark -- LFStreamingSessionDelegate
/** live status changed will callback */
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state{
NSLog(@"liveStateDidChange: %ld", state);
switch (state) {
case LFLiveReady:
_stateLabel.text = @"未连接";
break;
case LFLivePending:
_stateLabel.text = @"连接中";
break;
case LFLiveStart:
_stateLabel.text = @"已连接";
break;
case LFLiveError:
_stateLabel.text = @"连接错误";
break;
case LFLiveStop:
_stateLabel.text = @"未连接";
break;
default:
break;
}
}
/** live debug info callback */
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo{
NSLog(@"debugInfo: %lf", debugInfo.dataFlow);
}
/** callback socket errorcode */
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode{
NSLog(@"errorCode: %ld", errorCode);
}
#pragma mark -- Getter Setter
@@ -111,6 +132,7 @@
if(!_session){
/***  默认分辨率368 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Medium2] liveType:LFLiveRTMP];
_session.delegate = self;
/**   自己定制单声道 */
/*
@@ -212,6 +234,16 @@
return _containerView;
}
- (UILabel*)stateLabel{
if(!_stateLabel){
_stateLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 80, 40)];
_stateLabel.text = @"未连接";
_stateLabel.textColor = [UIColor whiteColor];
_stateLabel.font = [UIFont boldSystemFontOfSize:14.f];
}
return _stateLabel;
}
- (UIButton*)closeButton{
if(!_closeButton){
_closeButton = [UIButton new];
+1 -1
View File
@@ -5,6 +5,6 @@ target "LFLiveKit" do
pod 'CocoaAsyncSocket', '~> 7.4.1'
pod 'pili-librtmp', '~> 1.0.2'
pod 'LMGPUImage', '~> 0.1.9'
pod 'GPUImage', :git=>https://github.com/BradLarson/GPUImage
end