Compare commits

...

50 Commits

Author SHA1 Message Date
chenliming 659dfb81d0 删除flv格式 只保留rtmp 2016-07-15 14:10:49 +08:00
chenliming 4865bdc508 connect error 2016-07-15 14:06:50 +08:00
chenliming e63026415a demo支持后台传输 2016-07-15 12:18:02 +08:00
chenliming 21335ed3f0 修改横竖屏接口 ,只支持横屏或者竖屏,内部实现了旋转,但暂时不支持横竖切换(因为需要服务器的支持比较复杂) 2016-07-15 12:10:31 +08:00
chenliming b109289bc1 添加超时时间 2016-07-14 21:55:36 +08:00
chenliming 1e56fc2941 这样改也可以哦 😄 2016-07-14 21:50:20 +08:00
chenliming 14a3b2eb4b 后台应用(例如微信视频) 回到前台没有声音 2016-07-14 21:37:08 +08:00
chenliming 510d796ab1 commit reconnect 2016-07-14 21:14:01 +08:00
chenliming 48dac15d54 update demo version 2016-07-14 20:51:16 +08:00
chenliming 13bc9ad1eb update version 2016-07-14 19:59:01 +08:00
chenliming 1e6e42f2c6 线程变为单线程 2016-07-14 19:58:26 +08:00
chenliming ed2d37e6f4 update 2016-07-14 19:39:50 +08:00
chenliming fbbf5d9da5 麦克风被占用问题 2016-07-14 19:37:36 +08:00
chenliming 8f57142e5a 修改内存bug 2016-07-14 19:28:56 +08:00
chenliming d198058ce3 修改停止直播的bug 2016-07-14 17:57:27 +08:00
chenliming 3ea70b4780 短线重连的bug 2016-07-14 16:50:44 +08:00
chenliming 8b0224626a update demo 2016-07-13 17:40:23 +08:00
chenliming 41fe9d1070 update version 2016-07-13 17:30:51 +08:00
chenliming d7b981c516 fix 内存bug 2016-07-13 17:30:17 +08:00
chenliming 09a4627886 Revert "test"
This reverts commit a140408a6a.
2016-07-13 12:19:08 +08:00
chenliming a140408a6a test 2016-07-13 12:17:23 +08:00
chenliming 3539bae752 Revert "update"
This reverts commit 40b1f7d37f.
2016-07-13 12:01:14 +08:00
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
chenliming 037dbdef7a update version 2016-06-22 15:24:03 +08:00
小歪~~~ f91bb1c889 Merge pull request #3 from toss156/develop
添加发送metadata
2016-06-17 18:32:35 +08:00
toss156 7101ae842b fix beauty face bug 2016-06-17 17:05:51 +08:00
toss156 f5f37755df 优化美颜效果 2016-06-17 14:31:01 +08:00
toss156 43a82bffbb port to pili-librtmp 2016-06-17 09:57:01 +08:00
toss156 d7af9fb4eb 添加发送metadata 2016-06-16 16:41:51 +08:00
chenliming d25498162c add demo 2016-06-08 12:32:46 +08:00
chenliming 6f3ab33e8b update version 2016-06-08 10:56:33 +08:00
chenliming 62d0cee977 去除警告 2016-06-08 10:55:16 +08:00
chenliming ba7743d6ee 修改。。 2016-06-08 10:42:02 +08:00
chenliming dca255052b modify... 2016-06-08 10:34:44 +08:00
chenliming b51c53e93b modify read 2016-06-08 10:09:26 +08:00
chenliming 21763f5c1d modify spec 2016-06-08 10:01:31 +08:00
62 changed files with 3215 additions and 977 deletions
+7 -6
View File
@@ -2,15 +2,15 @@
Pod::Spec.new do |s|
s.name = "LFLiveKit"
s.version = "1.4.1"
s.summary = "objectc ios Live. LFLiveKit."
s.version = "1.7.2"
s.summary = "LaiFeng ios Live. LFLiveKit."
s.homepage = "https://github.com/chenliming777"
s.license = { :type => "MIT", :file => "FILE_LICENSE" }
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "chenliming" => "chenliming777@qq.com" }
s.platform = :ios, "8.0"
s.ios.deployment_target = "8.0"
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit", :tag => "#{s.version}" }
s.source_files = "LFLiveKit/**/*.{h,m}"
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit.git", :tag => "#{s.version}" }
s.source_files = "LFLiveKit/**/*.{*.h,*.m}"
s.public_header_files = "LFLiveKit/**/*.h"
s.frameworks = "VideoToolbox", "AudioToolbox","AVFoundation","Foundation","UIKit"
@@ -20,6 +20,7 @@ Pod::Spec.new do |s|
s.dependency "CocoaAsyncSocket", "~> 7.4.1"
s.dependency 'LMGPUImage', '~> 0.1.9'
s.dependency "librtmp-iOS", "~> 1.1.0"
s.dependency "pili-librtmp", "~> 1.0.2"
s.dependency "YYDispatchQueuePool"
end
+31 -32
View File
@@ -40,19 +40,19 @@
84001FEC1D0016380026C63F /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC41D0016380026C63F /* LFLiveStreamInfo.m */; };
84001FED1D0016380026C63F /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FC51D0016380026C63F /* LFVideoFrame.h */; };
84001FEE1D0016380026C63F /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC61D0016380026C63F /* LFVideoFrame.m */; };
84001FEF1D0016380026C63F /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FCA1D0016380026C63F /* LFStreamingBuffer.h */; };
84001FF01D0016380026C63F /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FCB1D0016380026C63F /* LFStreamingBuffer.m */; };
84001FF11D0016380026C63F /* LFStreamRtmpSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FCC1D0016380026C63F /* LFStreamRtmpSocket.h */; };
84001FF21D0016380026C63F /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FCD1D0016380026C63F /* LFStreamRtmpSocket.m */; };
84001FF31D0016380026C63F /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FCE1D0016380026C63F /* LFStreamSocket.h */; };
84001FF41D0016380026C63F /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FCF1D0016380026C63F /* NSMutableArray+LFAdd.h */; };
84001FF51D0016380026C63F /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FD01D0016380026C63F /* NSMutableArray+LFAdd.m */; };
84001FF71D0017590026C63F /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FF61D0017590026C63F /* AVFoundation.framework */; };
84001FF91D00175D0026C63F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FF81D00175D0026C63F /* Foundation.framework */; };
84001FFB1D0017630026C63F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFA1D0017630026C63F /* UIKit.framework */; };
84001FFD1D0017680026C63F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFC1D0017680026C63F /* AudioToolbox.framework */; };
84001FFF1D00176C0026C63F /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFE1D00176C0026C63F /* VideoToolbox.framework */; };
840020011D0017850026C63F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 840020001D0017850026C63F /* libz.tbd */; };
8493627A1D38B542002C8F13 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362701D38B542002C8F13 /* LFStreamingBuffer.h */; };
8493627B1D38B542002C8F13 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362711D38B542002C8F13 /* LFStreamingBuffer.m */; };
8493627C1D38B542002C8F13 /* LFStreamRtmpSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */; };
8493627D1D38B542002C8F13 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */; };
8493627E1D38B542002C8F13 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362741D38B542002C8F13 /* LFStreamSocket.h */; };
849362811D38B542002C8F13 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */; };
849362821D38B542002C8F13 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */; };
AD7F89B4621A7EFEBEA72D49 /* libPods-LFLiveKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8CB02D2A92EA1F5A262F154 /* libPods-LFLiveKit.a */; };
/* End PBXBuildFile section */
@@ -103,19 +103,19 @@
84001FC41D0016380026C63F /* LFLiveStreamInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveStreamInfo.m; sourceTree = "<group>"; };
84001FC51D0016380026C63F /* LFVideoFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoFrame.h; sourceTree = "<group>"; };
84001FC61D0016380026C63F /* LFVideoFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoFrame.m; sourceTree = "<group>"; };
84001FCA1D0016380026C63F /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamingBuffer.h; sourceTree = "<group>"; };
84001FCB1D0016380026C63F /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamingBuffer.m; sourceTree = "<group>"; };
84001FCC1D0016380026C63F /* LFStreamRtmpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamRtmpSocket.h; sourceTree = "<group>"; };
84001FCD1D0016380026C63F /* LFStreamRtmpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamRtmpSocket.m; sourceTree = "<group>"; };
84001FCE1D0016380026C63F /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamSocket.h; sourceTree = "<group>"; };
84001FCF1D0016380026C63F /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+LFAdd.h"; sourceTree = "<group>"; };
84001FD01D0016380026C63F /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+LFAdd.m"; sourceTree = "<group>"; };
84001FF61D0017590026C63F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
84001FF81D00175D0026C63F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
84001FFA1D0017630026C63F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
84001FFC1D0017680026C63F /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
84001FFE1D00176C0026C63F /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
840020001D0017850026C63F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
849362701D38B542002C8F13 /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamingBuffer.h; sourceTree = "<group>"; };
849362711D38B542002C8F13 /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamingBuffer.m; sourceTree = "<group>"; };
849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamRtmpSocket.h; sourceTree = "<group>"; };
849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamRtmpSocket.m; sourceTree = "<group>"; };
849362741D38B542002C8F13 /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamSocket.h; sourceTree = "<group>"; };
849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+LFAdd.h"; sourceTree = "<group>"; };
849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+LFAdd.m"; sourceTree = "<group>"; };
A17586B27CD6843997425CCF /* Pods-LFLiveKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKit/Pods-LFLiveKit.debug.xcconfig"; sourceTree = "<group>"; };
B75B965E6B94DE4CBCC82EA7 /* Pods-LFLiveKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKit/Pods-LFLiveKit.release.xcconfig"; sourceTree = "<group>"; };
B8CB02D2A92EA1F5A262F154 /* libPods-LFLiveKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKit.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -192,7 +192,7 @@
84001FA41D0016380026C63F /* capture */,
84001FA91D0016380026C63F /* coder */,
84001FB51D0016380026C63F /* filter */,
84001FC91D0016380026C63F /* publish */,
8493626F1D38B542002C8F13 /* publish */,
84001F8F1D0015D10026C63F /* Info.plist */,
);
path = LFLiveKit;
@@ -270,19 +270,18 @@
path = objects;
sourceTree = "<group>";
};
84001FC91D0016380026C63F /* publish */ = {
8493626F1D38B542002C8F13 /* publish */ = {
isa = PBXGroup;
children = (
84001FCE1D0016380026C63F /* LFStreamSocket.h */,
84001FCA1D0016380026C63F /* LFStreamingBuffer.h */,
84001FCB1D0016380026C63F /* LFStreamingBuffer.m */,
84001FCC1D0016380026C63F /* LFStreamRtmpSocket.h */,
84001FCD1D0016380026C63F /* LFStreamRtmpSocket.m */,
84001FCF1D0016380026C63F /* NSMutableArray+LFAdd.h */,
84001FD01D0016380026C63F /* NSMutableArray+LFAdd.m */,
849362701D38B542002C8F13 /* LFStreamingBuffer.h */,
849362711D38B542002C8F13 /* LFStreamingBuffer.m */,
849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */,
849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */,
849362741D38B542002C8F13 /* LFStreamSocket.h */,
849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */,
849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */,
);
name = publish;
path = upload;
path = publish;
sourceTree = "<group>";
};
EDD4B76A07A6817C79BB4E5C /* Pods */ = {
@@ -302,25 +301,25 @@
buildActionMask = 2147483647;
files = (
84001FDB1D0016380026C63F /* LFLiveAudioConfiguration.h in Headers */,
8493627C1D38B542002C8F13 /* LFStreamRtmpSocket.h in Headers */,
84001FDD1D0016380026C63F /* LFLiveVideoConfiguration.h in Headers */,
84001FE31D0016380026C63F /* LFLiveSession.h in Headers */,
8493627A1D38B542002C8F13 /* LFStreamingBuffer.h in Headers */,
84001FEB1D0016380026C63F /* LFLiveStreamInfo.h in Headers */,
84001FE91D0016380026C63F /* LFLiveDebug.h in Headers */,
84001FF11D0016380026C63F /* LFStreamRtmpSocket.h in Headers */,
84001FE71D0016380026C63F /* LFFrame.h in Headers */,
84001FEF1D0016380026C63F /* LFStreamingBuffer.h in Headers */,
84001FD61D0016380026C63F /* LFHardwareAudioEncoder.h in Headers */,
84001FDF1D0016380026C63F /* LFGPUImageBeautyFilter.h in Headers */,
84001FD31D0016380026C63F /* LFVideoCapture.h in Headers */,
84001FD11D0016380026C63F /* LFAudioCapture.h in Headers */,
84001FF41D0016380026C63F /* NSMutableArray+LFAdd.h in Headers */,
84001FE11D0016380026C63F /* LFGPUImageEmptyFilter.h in Headers */,
84001FDA1D0016380026C63F /* LFVideoEncoding.h in Headers */,
84001FE51D0016380026C63F /* LFAudioFrame.h in Headers */,
84001FED1D0016380026C63F /* LFVideoFrame.h in Headers */,
84001FD81D0016380026C63F /* LFHardwareVideoEncoder.h in Headers */,
849362811D38B542002C8F13 /* NSMutableArray+LFAdd.h in Headers */,
8493627E1D38B542002C8F13 /* LFStreamSocket.h in Headers */,
84001FD51D0016380026C63F /* LFAudioEncoding.h in Headers */,
84001FF31D0016380026C63F /* LFStreamSocket.h in Headers */,
84001F8E1D0015D10026C63F /* LFLiveKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -462,11 +461,11 @@
84001FDC1D0016380026C63F /* LFLiveAudioConfiguration.m in Sources */,
84001FD41D0016380026C63F /* LFVideoCapture.m in Sources */,
84001FE81D0016380026C63F /* LFFrame.m in Sources */,
84001FF01D0016380026C63F /* LFStreamingBuffer.m in Sources */,
84001FF51D0016380026C63F /* NSMutableArray+LFAdd.m in Sources */,
849362821D38B542002C8F13 /* NSMutableArray+LFAdd.m in Sources */,
8493627B1D38B542002C8F13 /* LFStreamingBuffer.m in Sources */,
84001FDE1D0016380026C63F /* LFLiveVideoConfiguration.m in Sources */,
84001FD21D0016380026C63F /* LFAudioCapture.m in Sources */,
84001FF21D0016380026C63F /* LFStreamRtmpSocket.m in Sources */,
8493627D1D38B542002C8F13 /* LFStreamRtmpSocket.m in Sources */,
84001FD91D0016380026C63F /* LFHardwareVideoEncoder.m in Sources */,
84001FEC1D0016380026C63F /* LFLiveStreamInfo.m in Sources */,
84001FEA1D0016380026C63F /* LFLiveDebug.m in Sources */,
@@ -42,7 +42,7 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5CFA1E6A87A325722DE7DCED3A58CCA1"
BlueprintIdentifier = "7C2BDDF89D4243C7BCA44592D146DEED"
BuildableName = "libPods-LFLiveKit.a"
BlueprintName = "Pods-LFLiveKit"
ReferencedContainer = "container:Pods/Pods.xcodeproj">
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>84001F891D0015D10026C63F</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>84001F931D0015D10026C63F</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
+1 -1
View File
@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.4.1</string>
<string>1.7.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
+15
View File
@@ -53,6 +53,21 @@ typedef void (^ LFRequestComplete)(_Nullable id info,NSError *_Nullable errorMsg
/** 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;
+47 -6
View File
@@ -13,6 +13,7 @@
#import "LFHardwareAudioEncoder.h"
#import "LFStreamRtmpSocket.h"
#import "LFLiveStreamInfo.h"
#import "LFGPUImageBeautyFilter.h"
#define LFLiveReportKey @"com.youku.liveSessionReport"
@@ -81,7 +82,8 @@
- (void)startLive:(LFLiveStreamInfo*)streamInfo{
if(!streamInfo) return;
_streamInfo = streamInfo;
_streamInfo.videoConfiguration = _videoConfiguration;
_streamInfo.audioConfiguration = _audioConfiguration;
[self.socket start];
}
@@ -148,12 +150,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];
}
}
@@ -193,6 +195,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];
}
@@ -235,7 +277,7 @@
- (id<LFStreamSocket>)socket{
if(!_socket){
_socket = [[LFStreamRtmpSocket alloc] initWithStream:self.streamInfo];
_socket = [[LFStreamRtmpSocket alloc] initWithStream:self.streamInfo videoSize:self.videoConfiguration.videoSize reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
[_socket setDelegate:self];
}
return _socket;
@@ -255,8 +297,7 @@
_timestamp = NOW;
_isFirstFrame = false;
currentts = 0;
}
else {
} else {
currentts = NOW - _timestamp;
}
dispatch_semaphore_signal(_lock);
+6 -4
View File
@@ -32,7 +32,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
self.taskQueue = dispatch_queue_create("com.youku.Laifeng.audioCapture.Queue", NULL);
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES withOptions:kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation error:nil];
[session setActive:YES error:nil];
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(handleRouteChange:)
@@ -45,7 +45,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
NSError *error = nil;
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers error:nil];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[session setMode:AVAudioSessionModeVideoRecording error:&error];
@@ -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,8 @@ 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;
+142 -37
View File
@@ -14,23 +14,47 @@
@interface LFVideoCapture ()
@property(nonatomic, strong) GPUImageVideoCamera *videoCamera;
@property(nonatomic, weak) LFGPUImageBeautyFilter *beautyFilter;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *emptyFilter;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *beau;
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
@property(nonatomic, strong) GPUImageCropFilter *cropfilter;
@property(nonatomic, strong) GPUImageView *gpuImageView;
@property (nonatomic, strong) LFLiveVideoConfiguration *configuration;
@property(nonatomic, strong) LFLiveVideoConfiguration *configuration;
@end
@implementation LFVideoCapture
@synthesize torch = _torch;
@synthesize beautyLevel = _beautyLevel;
@synthesize brightLevel = _brightLevel;
@synthesize zoomScale = _zoomScale;
#pragma mark -- LifeCycle
- (instancetype)initWithVideoConfiguration:(LFLiveVideoConfiguration *)configuration{
if(self = [super init]){
_configuration = configuration;
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:_configuration.avSessionPreset cameraPosition:AVCaptureDevicePositionFront];
_videoCamera.outputImageOrientation = _configuration.orientation;
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
if(configuration.landscape){
if(statusBar != UIInterfaceOrientationLandscapeLeft && statusBar != UIInterfaceOrientationLandscapeRight){
NSLog(@"当前设置方向出错");
NSLog(@"当前设置方向出错");
NSLog(@"当前设置方向出错");
_videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
}else{
_videoCamera.outputImageOrientation = statusBar;
}
}else{
if(statusBar != UIInterfaceOrientationPortrait && statusBar != UIInterfaceOrientationPortraitUpsideDown){
NSLog(@"当前设置方向出错");
NSLog(@"当前设置方向出错");
NSLog(@"当前设置方向出错");
_videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
}else{
_videoCamera.outputImageOrientation = statusBar;
}
}
_videoCamera.horizontallyMirrorFrontFacingCamera = NO;
_videoCamera.horizontallyMirrorRearFacingCamera = NO;
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
@@ -42,8 +66,11 @@
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterBackground:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarChanged:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
self.beautyFace = YES;
self.beautyLevel = 0.5;
self.brightLevel = 0.5;
self.zoomScale = 1.0;
}
return self;
}
@@ -80,8 +107,11 @@
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition{
[_videoCamera rotateCamera];
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
if(captureDevicePosition == AVCaptureDevicePositionFront) [_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
else [_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
if (captureDevicePosition == AVCaptureDevicePositionFront) {
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
} else {
[_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
}
}
- (AVCaptureDevicePosition)captureDevicePosition{
@@ -98,68 +128,125 @@
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;
_beautyFace = beautyFace;
[_emptyFilter removeAllTargets];
[_filter removeAllTargets];
[_cropfilter removeAllTargets];
[_videoCamera removeAllTargets];
[_beau removeAllTargets];
if(_beautyFace){
_filter = [[GPUImageUnsharpMaskFilter alloc] init];
[(GPUImageUnsharpMaskFilter*)_filter setIntensity:1.23];
[(GPUImageUnsharpMaskFilter*)_filter setBlurRadiusInPixels:13];
_beau = [[LFGPUImageBeautyFilter alloc] init];
_emptyFilter = [[LFGPUImageEmptyFilter alloc] init];
}else{
_filter = [[LFGPUImageEmptyFilter alloc] init];
}
if (beautyFace) {
if (_beautyFace) {
_output = [[LFGPUImageEmptyFilter alloc] init];
_filter = [[LFGPUImageBeautyFilter alloc] init];
_beautyFilter = _filter;
__weak typeof(self) _self = self;
[_emptyFilter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
[_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];
}];
}
if(_configuration.isClipVideo){
if(_configuration.orientation == UIInterfaceOrientationPortrait || _configuration.orientation == UIInterfaceOrientationPortraitUpsideDown){
if (_configuration.isClipVideo) {
if (_configuration.landscape){
_cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.125, 0, 0.75, 1)];
}else{
} else {
_cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0, 0.125, 1, 0.75)];
}
[_videoCamera addTarget:_cropfilter];
[_cropfilter addTarget:_filter];
}else{
} else {
[_videoCamera addTarget:_filter];
}
if (beautyFace) {
[_filter addTarget:_beau];
[_beau addTarget:_emptyFilter];
[_emptyFilter addTarget:_gpuImageView];
if (_beautyFace) {
[_filter addTarget:_output];
[_output addTarget:_gpuImageView];
} else {
[_filter addTarget:_gpuImageView];
}
if(_videoCamera.cameraPosition == AVCaptureDevicePositionFront) [_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
else [_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
if (_videoCamera.cameraPosition == AVCaptureDevicePositionFront) {
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
} else {
[_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
}
}
#pragma mark -- Custom Method
- (void) processVideo:(GPUImageOutput *)output{
- (void)processVideo:(GPUImageOutput *)output{
__weak typeof(self) _self = self;
@autoreleasepool {
GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
@@ -168,7 +255,7 @@
if(pixelBuffer && _self.delegate && [_self.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:)]){
[_self.delegate captureOutput:_self pixelBuffer:pixelBuffer];
}
}
}
@@ -187,4 +274,22 @@
[UIApplication sharedApplication].idleTimerDisabled = YES;
}
- (void)statusBarChanged:(NSNotification*)notification{
NSLog(@"UIApplicationWillChangeStatusBarOrientationNotification. UserInfo: %@", notification.userInfo);
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
if(_configuration.landscape){
if(statusBar == UIInterfaceOrientationLandscapeLeft){
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeRight;
}else if(statusBar == UIInterfaceOrientationLandscapeRight){
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
}
}else{
if(statusBar == UIInterfaceOrientationPortrait){
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortraitUpsideDown;
}else if(statusBar == UIInterfaceOrientationPortraitUpsideDown){
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
}
}
}
@end
+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 -10
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);
}
@@ -238,7 +238,6 @@ static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatu
- (char*)GetFilePathByfileName:(char*)filename
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
@@ -50,8 +50,8 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
/// 视频配置(质量)
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality;
/// 视频配置(质量 & 方向)
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality orientation:(UIInterfaceOrientation)orientation;
/// 视频配置(质量 & 是否是横屏)
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality landscape:(BOOL)landscape;
#pragma mark - Attribute
///=============================================================================
@@ -61,7 +61,7 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
@property (nonatomic, assign) CGSize videoSize;
/// 视频输出方向
@property (nonatomic, assign) UIInterfaceOrientation orientation;
@property (nonatomic, assign) BOOL landscape;
/// 视频的帧率,即 fps
@property (nonatomic, assign) NSUInteger videoFrameRate;
@@ -18,110 +18,119 @@
}
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality{
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality orientation:UIInterfaceOrientationPortrait];
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality landscape:NO];
return configuration;
}
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality orientation:(UIInterfaceOrientation)orientation{
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality landscape:(BOOL)landscape{
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration new];
switch (videoQuality) {
case LFLiveVideoQuality_Low1:
case LFLiveVideoQuality_Low1:
{
configuration.sessionPreset = LFCaptureSessionPreset360x640;
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:
case LFLiveVideoQuality_Low2:
{
configuration.sessionPreset = LFCaptureSessionPreset360x640;
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:
case LFLiveVideoQuality_Low3:
{
configuration.sessionPreset = LFCaptureSessionPreset360x640;
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:
case LFLiveVideoQuality_Medium1:
{
configuration.sessionPreset = LFCaptureSessionPreset540x960;
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:
case LFLiveVideoQuality_Medium2:
{
configuration.sessionPreset = LFCaptureSessionPreset540x960;
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:
case LFLiveVideoQuality_Medium3:
{
configuration.sessionPreset = LFCaptureSessionPreset540x960;
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:
case LFLiveVideoQuality_High1:
{
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
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:
case LFLiveVideoQuality_High2:
{
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
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:
case LFLiveVideoQuality_High3:
{
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
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:
@@ -129,11 +138,12 @@
}
configuration.sessionPreset = [configuration supportSessionPreset:configuration.sessionPreset];
configuration.videoMaxKeyframeInterval = configuration.videoFrameRate*2;
configuration.orientation = orientation;
if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown){
configuration.videoSize = CGSizeMake(368, 640);
configuration.landscape = landscape;
CGSize size = configuration.videoSize;
if(landscape){
configuration.videoSize = CGSizeMake(size.height, size.width);
}else{
configuration.videoSize = CGSizeMake(640, 368);
configuration.videoSize = CGSizeMake(size.width, size.height);
}
return configuration;
}
@@ -142,17 +152,17 @@
- (NSString*)avSessionPreset{
NSString *avSessionPreset = nil;
switch (self.sessionPreset) {
case LFCaptureSessionPreset360x640:
case LFCaptureSessionPreset360x640:
{
avSessionPreset = AVCaptureSessionPreset640x480;
}
break;
case LFCaptureSessionPreset540x960:
case LFCaptureSessionPreset540x960:
{
avSessionPreset = AVCaptureSessionPresetiFrame960x540;
}
break;
case LFCaptureSessionPreset720x1280:
case LFCaptureSessionPreset720x1280:
{
avSessionPreset = AVCaptureSessionPreset1280x720;
}
@@ -215,7 +225,7 @@
[aCoder encodeObject:@(self.videoMaxKeyframeInterval) forKey:@"videoMaxKeyframeInterval"];
[aCoder encodeObject:@(self.videoBitRate) forKey:@"videoBitRate"];
[aCoder encodeObject:@(self.sessionPreset) forKey:@"sessionPreset"];
[aCoder encodeObject:@(self.orientation) forKey:@"orientation"];
[aCoder encodeObject:@(self.landscape) forKey:@"landscape"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
@@ -225,7 +235,7 @@
_videoMaxKeyframeInterval = [[aDecoder decodeObjectForKey:@"videoMaxKeyframeInterval"] unsignedIntegerValue];
_videoBitRate = [[aDecoder decodeObjectForKey:@"videoBitRate"] unsignedIntegerValue];
_sessionPreset = [[aDecoder decodeObjectForKey:@"sessionPreset"] unsignedIntegerValue];
_orientation = [[aDecoder decodeObjectForKey:@"orientation"] unsignedIntegerValue];
_landscape = [[aDecoder decodeObjectForKey:@"landscape"] unsignedIntegerValue];
return self;
}
@@ -242,7 +252,7 @@
@(self.isClipVideo),
self.avSessionPreset,
@(self.sessionPreset),
@(self.orientation),];
@(self.landscape),];
for (NSObject *value in values) {
hash ^= value.hash;
@@ -269,7 +279,7 @@
object.isClipVideo == self.isClipVideo &&
[object.avSessionPreset isEqualToString:self.avSessionPreset] &&
object.sessionPreset == self.sessionPreset &&
object.orientation == self.orientation;
object.landscape == self.landscape;
}
}
@@ -292,7 +302,7 @@
[desc appendFormat:@" isClipVideo:%zi",self.isClipVideo];
[desc appendFormat:@" avSessionPreset:%@",self.avSessionPreset];
[desc appendFormat:@" sessionPreset:%zi",self.sessionPreset];
[desc appendFormat:@" orientation:%zi",self.orientation];
[desc appendFormat:@" landscape:%zi",self.landscape];
return desc;
}
+5 -43
View File
@@ -1,47 +1,9 @@
#import "GPUImageFilterGroup.h"
#import "GPUImageFilter.h"
@class GPUImageGaussianBlurFilter;
//@class GPUImageBilateralFilter;
/** A Gaussian blur that preserves focus within a circular region
*/
@interface LFGPUImageBeautyFilter : GPUImageFilterGroup
{
GPUImageGaussianBlurFilter *blurFilter;
GPUImageFilter *selectiveFocusFilter;
BOOL hasOverriddenAspectRatio;
@interface LFGPUImageBeautyFilter : GPUImageFilter {
}
/** The radius of the circular area being excluded from the blur
*/
@property (readwrite, nonatomic) CGFloat excludeCircleRadius;
/** The center of the circular area being excluded from the blur
*/
@property (readwrite, nonatomic) CGPoint excludeCirclePoint;
/** The size of the area between the blurred portion and the clear circle
*/
@property (readwrite, nonatomic) CGFloat excludeBlurSize;
/** A radius in pixels to use for the blur, with a default of 5.0. This adjusts the sigma variable in the Gaussian distribution function.
*/
@property (readwrite, nonatomic) CGFloat blurRadiusInPixels;
/** The aspect ratio of the image, used to adjust the circularity of the in-focus region. By default, this matches the image aspect ratio, but you can override this value.
*/
@property (readwrite, nonatomic) CGFloat aspectRatio;
@property (nonatomic, assign) CGFloat beautyLevel;
@property (nonatomic, assign) CGFloat brightLevel;
@property (nonatomic, assign) CGFloat toneLevel;
@end
//#import <GPUImage/GPUImage.h>
//
//@class GPUImageCombinationFilter;
//
//@interface LFGPUImageBeautyFilter : GPUImageFilterGroup {
// //GPUImageBilateralFilter *bilateralFilter;
// GPUImageGaussianBlurFilter *bilateralFilter;
// GPUImageCannyEdgeDetectionFilter *cannyEdgeFilter;
// GPUImageCombinationFilter *combinationFilter;
// GPUImageHSBFilter *hsbFilter;
//}
//
//@end
+225 -427
View File
@@ -1,478 +1,276 @@
#import "LFGPUImageBeautyFilter.h"
#import "GPUImageGaussianBlurFilter.h"
#import "GPUImageTwoInputFilter.h"
#import "GPUImageBilateralFilter.h"
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSString *const KLFGPUImageBeautyFragmentShaderString = SHADER_STRING
(
NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
(
varying highp vec2 textureCoordinate;
varying highp vec2 textureCoordinate2;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
uniform lowp float excludeCircleRadius;
uniform lowp vec2 excludeCirclePoint;
uniform lowp float excludeBlurSize;
uniform highp float aspectRatio;
//247 217 211
uniform highp vec2 singleStepOffset;
uniform highp vec4 params;
uniform highp float brightness;
const highp vec3 W = vec3(0.299,0.587,0.114);
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) {
if(color <= 0.5)
color = color * color * 2.0;
else
color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
return color;
}
void main()
{
lowp vec4 tmpColor = texture2D(inputImageTexture, textureCoordinate);
// gl_FragColor = tmpColor;
// return;
lowp vec4 sharpImageColor = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 blurredImageColor = texture2D(inputImageTexture2, textureCoordinate2);
if((sharpImageColor.r > 0.372549 && sharpImageColor.g > 0.156863 && sharpImageColor.b > 0.078431 &&
sharpImageColor.r - sharpImageColor.g > 0.058823 && sharpImageColor.r - sharpImageColor.b > 0.058823) ||
(sharpImageColor.r > 0.784314 && sharpImageColor.g > 0.823530 && sharpImageColor.b > 0.666667 &&
abs(sharpImageColor.r - sharpImageColor.b) <= 0.058823 && sharpImageColor.r > sharpImageColor.b && sharpImageColor.g > sharpImageColor.b)) {
mediump float rpass;
mediump float gpass;
mediump float bpass;
mediump float hpass;
hpass = 0.5 / excludeBlurSize;
hpass = 1.0;
mediump float dis = distance(sharpImageColor, blurredImageColor);
bpass = min((0.4+1.0*(1.0*dis)), 1.0);
gl_FragColor = mix(sharpImageColor, blurredImageColor, 1.0-bpass);
} else {
mediump float rpass;
mediump float gpass;
mediump float bpass;
mediump float hpass;
hpass = 0.5 / excludeBlurSize;
hpass = 1.0;
mediump float dis = distance(sharpImageColor, blurredImageColor);
bpass = min((0.45+1.0*(1.0*dis)), 1.0);
gl_FragColor = mix(sharpImageColor, blurredImageColor, 1.0-bpass);
highp vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
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 * 22.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
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 / 62.0;
highp float highPass = centralColor.g - sampleColor + 0.5;
for(int i = 0; i < 5;i++)
{
highPass = hardLight(highPass);
}
mediump float r;
mediump float g;
mediump float b;
mediump float status = 0.81;
// r = min((gl_FragColor.r+sharpImageColor.r - sharpImageColor.r*gl_FragColor.r), 1.0);
// g = min((gl_FragColor.g+sharpImageColor.g - sharpImageColor.g*gl_FragColor.g), 1.0);
// b = min((gl_FragColor.b+sharpImageColor.b - sharpImageColor.b*gl_FragColor.b), 1.0);
r = min((gl_FragColor.r*2.0 - gl_FragColor.r*gl_FragColor.r), 1.0);
g = min((gl_FragColor.g*2.0 - gl_FragColor.g*gl_FragColor.g), 1.0);
b = min((gl_FragColor.b*2.0 - gl_FragColor.b*gl_FragColor.b), 1.0);
r = min(status*gl_FragColor.r+1.05*(1.0-status)*r, 1.0);
g = min(status*gl_FragColor.g+1.15*(1.0-status)*g, 1.0);
b = min(status*gl_FragColor.b+1.25*(1.0-status)*b, 1.0);
gl_FragColor = vec4(r, g, b, 1.0);
//gl_FragColor = vec4(r, g, b, 1.0);
highp float lumance = dot(centralColor, W);
highp float alpha = pow(lumance, params.r);
highp vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
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
NSString *const KLFGPUImageBeautyFragmentShaderString = SHADER_STRING
NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
(
varying vec2 textureCoordinate;
varying vec2 textureCoordinate2;
uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;
uniform float excludeCircleRadius;
uniform vec2 excludeCirclePoint;
uniform float excludeBlurSize;
uniform float aspectRatio;
uniform mediump vec2 singleStepOffset;
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[24];
mediump float hardLight(mediump float color)
{
if(color <= 0.5)
color = color * color * 2.0;
else
color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
return color;
}
void main()
{
// vec4 sharpImageColor = texture2D(inputImageTexture, textureCoordinate);
// vec4 blurredImageColor = texture2D(inputImageTexture2, textureCoordinate2);
//
// vec2 textureCoordinateToUse = vec2(textureCoordinate2.x, (textureCoordinate2.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
// float distanceFromCenter = distance(excludeCirclePoint, textureCoordinateToUse);
//
// gl_FragColor = mix(sharpImageColor, blurredImageColor, smoothstep(excludeCircleRadius - excludeBlurSize, excludeCircleRadius, distanceFromCenter));
mediump vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
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);
vec4 sharpImageColor = texture2D(inputImageTexture, textureCoordinate);
vec4 blurredImageColor = texture2D(inputImageTexture2, textureCoordinate2);
if(sharpImageColor.r > 0.372549/*0.372549*/) {
mediump float bpass;
bpass = min((sharpImageColor.r - blurredImageColor.r)*(sharpImageColor.r - blurredImageColor.r)*0.045455, 1.0);
//bpass = min((sharpImageColor.r - blurredImageColor.r)*(sharpImageColor.r - blurredImageColor.r)*0.038462, 1.0);
bpass = min((0.5+255.0*bpass), 1.0);
gl_FragColor = mix(sharpImageColor, blurredImageColor, 1.0-bpass);
} else {
gl_FragColor = vec4(sharpImageColor.r, sharpImageColor.g, sharpImageColor.b,1.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;
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
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 / 62.0;
mediump float highPass = centralColor.g - sampleColor + 0.5;
for(int i = 0; i < 5;i++)
{
highPass = hardLight(highPass);
}
mediump float r;
mediump float g;
mediump float b;
r = min((gl_FragColor.r*2.0 - gl_FragColor.r*gl_FragColor.r), 1.0);
g = min((gl_FragColor.g*2.0 - gl_FragColor.g*gl_FragColor.g), 1.0);
b = min((gl_FragColor.b*2.0 - gl_FragColor.b*gl_FragColor.b), 1.0);
mediump float luminance = dot(centralColor, W);
r = min(0.62*gl_FragColor.r+0.38*r, 1.0);
g = min(0.62*gl_FragColor.g+0.38*g, 1.0);
b = min(0.62*gl_FragColor.b+0.38*b, 1.0);
mediump float alpha = pow(luminance, params);
gl_FragColor = vec4(r, g, b, 1.0);
mediump vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
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
@implementation LFGPUImageBeautyFilter
@synthesize excludeCirclePoint = _excludeCirclePoint, excludeCircleRadius = _excludeCircleRadius, excludeBlurSize = _excludeBlurSize;
@synthesize blurRadiusInPixels = _blurRadiusInPixels;
@synthesize aspectRatio = _aspectRatio;
- (id)init;
{
if (!(self = [super init]))
if (!(self = [super initWithFragmentShaderFromString:kLFGPUImageBeautyFragmentShaderString]))
{
return nil;
}
hasOverriddenAspectRatio = NO;
// First pass: apply a variable Gaussian blur
blurFilter = [[GPUImageGaussianBlurFilter alloc] init];
//blurFilter = [[GPUImageBilateralFilter alloc] init];
blurFilter.texelSpacingMultiplier = 0.55;
blurFilter.blurRadiusInPixels = 23.0;
[self addFilter:blurFilter];
// Second pass: combine the blurred image with the original sharp one
selectiveFocusFilter = [[GPUImageTwoInputFilter alloc] initWithFragmentShaderFromString:KLFGPUImageBeautyFragmentShaderString];
[self addFilter:selectiveFocusFilter];
// Texture location 0 needs to be the sharp image for both the blur and the second stage processing
[blurFilter addTarget:selectiveFocusFilter atTextureLocation:1];
// To prevent double updating of this filter, disable updates from the sharp image side
self.initialFilters = [NSArray arrayWithObjects:blurFilter, selectiveFocusFilter, nil];
self.terminalFilter = selectiveFocusFilter;
//self.blurRadiusInPixels = 5.0;
//960*540
self.blurRadiusInPixels = 13.0;
//1280*720
//self.blurRadiusInPixels = 11.0;
self.excludeCircleRadius = 13.0;
self.excludeCirclePoint = CGPointMake(0.5f, 0.5f);
self.excludeBlurSize = 13.0;
_toneLevel = 0.5;
_beautyLevel = 0.5;
_brightLevel = 0.5;
[self setParams:_beautyLevel tone:_toneLevel];
[self setBrightLevel:_brightLevel];
return self;
}
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex
{
CGSize oldInputSize = inputTextureSize;
[super setInputSize:newSize atIndex:textureIndex];
inputTextureSize = newSize;
if ( (!CGSizeEqualToSize(oldInputSize, inputTextureSize)) && (!hasOverriddenAspectRatio) && (!CGSizeEqualToSize(newSize, CGSizeZero)) )
{
_aspectRatio = (inputTextureSize.width / inputTextureSize.height);
[selectiveFocusFilter setFloat:_aspectRatio forUniformName:@"aspectRatio"];
CGPoint offset = CGPointMake(2.0f / inputTextureSize.width, 2.0 / inputTextureSize.height);
[self setPoint:offset forUniformName:@"singleStepOffset"];
}
- (void)setBeautyLevel:(CGFloat)beautyLevel
{
_beautyLevel = beautyLevel;
[self setParams:_beautyLevel tone:_toneLevel];
}
- (void)setBrightLevel:(CGFloat)brightLevel
{
_brightLevel = brightLevel;
[self setFloat:0.6 * (-0.5 + brightLevel) forUniformName:@"brightness"];
}
}
#pragma mark -
#pragma mark Accessors
- (void)setBlurRadiusInPixels:(CGFloat)newValue;
{
//newValue = 25;
blurFilter.blurRadiusInPixels = newValue;
_excludeCircleRadius = newValue;
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeCircleRadius"];
_excludeBlurSize = newValue;
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeBlurSize"];
}
- (CGFloat)blurRadiusInPixels;
{
return blurFilter.blurRadiusInPixels;
}
- (void)setExcludeCirclePoint:(CGPoint)newValue;
{
_excludeCirclePoint = newValue;
[selectiveFocusFilter setPoint:newValue forUniformName:@"excludeCirclePoint"];
}
- (void)setExcludeCircleRadius:(CGFloat)newValue;
{
_excludeCircleRadius = newValue;
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeCircleRadius"];
}
- (void)setExcludeBlurSize:(CGFloat)newValue;
{
_excludeBlurSize = newValue;
[selectiveFocusFilter setFloat:newValue forUniformName:@"excludeBlurSize"];
}
- (void)setAspectRatio:(CGFloat)newValue;
{
hasOverriddenAspectRatio = YES;
_aspectRatio = newValue;
[selectiveFocusFilter setFloat:_aspectRatio forUniformName:@"aspectRatio"];
- (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
//#import "LFGPUImageBeautyFilter.h"
//
//// Internal CombinationFilter(It should not be used outside)
//@interface GPUImageCombinationFilter : GPUImageThreeInputFilter
//{
// GLint smoothDegreeUniform;
//}
//
//@property (nonatomic, assign) CGFloat intensity;
//
//@end
//
//NSString *const kGPUImageBeautifyFragmentShaderString = SHADER_STRING
//(
// varying highp vec2 textureCoordinate;
// varying highp vec2 textureCoordinate2;
// varying highp vec2 textureCoordinate3;
//
// uniform sampler2D inputImageTexture;
// uniform sampler2D inputImageTexture2;
// uniform sampler2D inputImageTexture3;
// uniform mediump float smoothDegree;
//
// void main()
// {
//// highp vec4 bilateral = texture2D(inputImageTexture, textureCoordinate);
//// highp vec4 canny = texture2D(inputImageTexture2, textureCoordinate2);
//// highp vec4 origin = texture2D(inputImageTexture3,textureCoordinate3);
//// highp vec4 smooth;
//// lowp float r = origin.r;
//// lowp float g = origin.g;
//// lowp float b = origin.b;
//// if (canny.r < 0.2 && r > 0.3725 && g > 0.1568 && b > 0.0784 && r > b && (max(max(r, g), b) - min(min(r, g), b)) > 0.0588 && abs(r-g) > 0.0588) {
//// smooth = (1.0 - smoothDegree) * (origin - bilateral) + bilateral;
//// }
//// else {
//// smooth = origin;
//// }
//// smooth.r = log(1.0 + 0.2 * smooth.r)/log(1.2);
//// smooth.g = log(1.0 + 0.2 * smooth.g)/log(1.2);
//// smooth.b = log(1.0 + 0.2 * smooth.b)/log(1.2);
//// gl_FragColor = smooth;
//
//
// highp vec4 blurredImageColor = texture2D(inputImageTexture, textureCoordinate);
// highp vec4 canny = texture2D(inputImageTexture2, textureCoordinate2);
// highp vec4 sharpImageColor = texture2D(inputImageTexture3,textureCoordinate3);
//
// //gl_FragColor = canny;
//
//
//
//
// if((sharpImageColor.r > 0.372549 && sharpImageColor.g > 0.156863 && sharpImageColor.b > 0.078431 &&
// sharpImageColor.r - sharpImageColor.g > 0.058823 && sharpImageColor.r - sharpImageColor.b > 0.058823) ||
// (sharpImageColor.r > 0.784314 && sharpImageColor.g > 0.823530 && sharpImageColor.b > 0.666667 &&
// abs(sharpImageColor.r - sharpImageColor.b) <= 0.058823 && sharpImageColor.r > sharpImageColor.b && sharpImageColor.g > sharpImageColor.b)) {
// mediump float rpass;
// mediump float gpass;
// mediump float bpass;
// mediump float hpass;
// //hpass = 0.5 / excludeBlurSize;
// hpass = 1.0;
// //1280*720
// //bpass = min((sharpImageColor.r - blurredImageColor.r)*(sharpImageColor.r - blurredImageColor.r)*0.045455, 1.0);
// //960*540
// rpass = min(((sharpImageColor.r - blurredImageColor.r)*hpass), 1.0);
// gpass = min(((sharpImageColor.g - blurredImageColor.g)*hpass), 1.0);
// bpass = min(((sharpImageColor.b - blurredImageColor.b)*hpass), 1.0);
// bpass = min((0.0+1.0*(1.0*bpass)), 1.0);
// gpass = min((0.0+1.0*(1.0*gpass)), 1.0);
// rpass = min((0.0+1.0*(1.0*rpass)), 1.0);
// mediump float dis = distance(sharpImageColor, blurredImageColor);
// bpass = min((0.35+1.0*(1.0*dis)), 1.0);
// if(canny.r > 0.2) {
// bpass = min((0.45+1.0*(1.0*dis)), 1.0);
// }
// gl_FragColor = mix(sharpImageColor, blurredImageColor, 1.0-bpass);
//
//
// } else {
// mediump float rpass;
// mediump float gpass;
// mediump float bpass;
// mediump float hpass;
// //hpass = 0.5 / excludeBlurSize;
// hpass = 1.0;
// //1280*720
// //bpass = min((sharpImageColor.r - blurredImageColor.r)*(sharpImageColor.r - blurredImageColor.r)*0.045455, 1.0);
// //960*540
// rpass = min(((sharpImageColor.r - blurredImageColor.r)*hpass), 1.0);
// gpass = min(((sharpImageColor.g - blurredImageColor.g)*hpass), 1.0);
// bpass = min(((sharpImageColor.b - blurredImageColor.b)*hpass), 1.0);
// bpass = min((0.5+1.0*(1.0*bpass)), 1.0);
// gpass = min((0.5+1.0*(1.0*gpass)), 1.0);
// rpass = min((0.5+1.0*(1.0*rpass)), 1.0);
//
// // gpass = max(rpass, gpass);
// // bpass = max(gpass, bpass);
// // bpass = min((0.5+1.0*(1.0*bpass)), 1.0);
// //gl_FragColor = vec4(1, 1, 1, 1.0);
// mediump float dis = distance(sharpImageColor, blurredImageColor);
// bpass = min((0.45+1.0*(1.0*dis)), 1.0);
// if(canny.r > 0.2) {
// bpass = min((0.45+1.0*(1.0*dis)), 1.0);
// }
// gl_FragColor = mix(sharpImageColor, blurredImageColor, 1.0-bpass);
////
// }
//
//
// //gl_FragColor = canny;
//
//
// mediump float r;
// mediump float g;
// mediump float b;
// mediump float status = 0.8;
// r = min((gl_FragColor.r*2.0 - gl_FragColor.r*gl_FragColor.r), 1.0);
// g = min((gl_FragColor.g*2.0 - gl_FragColor.g*gl_FragColor.g), 1.0);
// b = min((gl_FragColor.b*2.0 - gl_FragColor.b*gl_FragColor.b), 1.0);
// r = min(status*gl_FragColor.r+(1.0-status)*r, 1.0);
// g = min(status*gl_FragColor.g+1.2*(1.0-status)*g, 1.0);
// b = min(status*gl_FragColor.b+1.3*(1.0-status)*b, 1.0);
// gl_FragColor = vec4(r, g, b, 1.0);
//
// //gl_FragColor = blurredImageColor;
//
//
//
//
// }
// );
//
//@implementation GPUImageCombinationFilter
//
//- (id)init {
// if (self = [super initWithFragmentShaderFromString:kGPUImageBeautifyFragmentShaderString]) {
// smoothDegreeUniform = [filterProgram uniformIndex:@"smoothDegree"];
// }
// self.intensity = 0.5;
// return self;
//}
//
//- (void)setIntensity:(CGFloat)intensity {
// _intensity = intensity;
// [self setFloat:intensity forUniform:smoothDegreeUniform program:filterProgram];
//}
//
//@end
//
//@implementation LFGPUImageBeautyFilter
//
//- (id)init;
//{
// if (!(self = [super init]))
// {
// return nil;
// }
//
// // First pass: face smoothing filter
//// bilateralFilter = [[GPUImageBilateralFilter alloc] init];
//// bilateralFilter.distanceNormalizationFactor = 1.0;
//// bilateralFilter.texelSpacingMultiplier = 0.75;
//// bilateralFilter.blurRadiusInPixels = 11.0;
//// [self addFilter:bilateralFilter];
//
// bilateralFilter = [[GPUImageGaussianBlurFilter alloc] init];
// bilateralFilter.texelSpacingMultiplier = 0.55;
// bilateralFilter.blurRadiusInPixels = 13.0;
// [self addFilter:bilateralFilter];
//
// // Second pass: edge detection
// cannyEdgeFilter = [[GPUImageCannyEdgeDetectionFilter alloc] init];
// [self addFilter:cannyEdgeFilter];
//
// // Third pass: combination bilateral, edge detection and origin
// combinationFilter = [[GPUImageCombinationFilter alloc] init];
// [self addFilter:combinationFilter];
//
// // Adjust HSB
// hsbFilter = [[GPUImageHSBFilter alloc] init];
// [hsbFilter adjustBrightness:1.0];
// [hsbFilter adjustSaturation:1.0];
//
// [bilateralFilter addTarget:combinationFilter];
// [cannyEdgeFilter addTarget:combinationFilter];
//
// [combinationFilter addTarget:hsbFilter];
//
// self.initialFilters = [NSArray arrayWithObjects:bilateralFilter,cannyEdgeFilter,combinationFilter,nil];
// self.terminalFilter = hsbFilter;
//
// return self;
//}
//
//#pragma mark -
//#pragma mark GPUImageInput protocol
//
//- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
//{
// for (GPUImageOutput<GPUImageInput> *currentFilter in self.initialFilters)
// {
// if (currentFilter != self.inputFilterToIgnoreForUpdates)
// {
// if (currentFilter == combinationFilter) {
// textureIndex = 2;
// }
// [currentFilter newFrameReadyAtTime:frameTime atIndex:textureIndex];
// }
// }
//}
//
//- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
//{
// for (GPUImageOutput<GPUImageInput> *currentFilter in self.initialFilters)
// {
// if (currentFilter == combinationFilter) {
// textureIndex = 2;
// }
// [currentFilter setInputFramebuffer:newInputFramebuffer atIndex:textureIndex];
// }
//}
//
//@end
+13
View File
@@ -7,6 +7,8 @@
// 真正的上传地址 token等
#import <Foundation/Foundation.h>
#import "LFLiveAudioConfiguration.h"
#import "LFLiveVideoConfiguration.h"
/// 流状态
typedef NS_ENUM(NSUInteger, LFLiveState){
@@ -32,6 +34,17 @@ typedef NS_ENUM(NSUInteger,LFLiveSocketErrorCode) {
@interface LFLiveStreamInfo : NSObject
@property (nonatomic, copy) NSString *streamId;
#pragma mark -- FLV
@property (nonatomic, copy) NSString *host;
@property (nonatomic, assign) NSInteger port;
#pragma mark -- RTMP
@property (nonatomic, copy) NSString *url; ///< 上传地址 (RTMP用就好了)
///音频配置
@property (nonatomic, strong) LFLiveAudioConfiguration *audioConfiguration;
///视频配置
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
@end
+519
View File
@@ -0,0 +1,519 @@
//
// LFStreamRtmpSocket.m
// LFLiveKit
//
// Created by admin on 16/5/18.
// Copyright © 2016年 live Interactive. All rights reserved.
//
#import "LFStreamRtmpSocket.h"
#import "rtmp.h"
#import "YYDispatchQueuePool.h"
static const NSInteger RetryTimesBreaken = 20;///< 重连1分钟 3秒一次 一共20次
static const NSInteger RetryTimesMargin = 3;
static dispatch_queue_t YYRtmpSendQueue() {
YYDispatchQueuePool *pool = [[YYDispatchQueuePool alloc] initWithName:@"com.youku.laifeng.rtmpsendQueue" queueCount:1 qos:NSQualityOfServiceDefault];
dispatch_queue_t queue = [pool queue];
return queue;
}
#define RTMP_RECEIVE_TIMEOUT 2
#define DATA_ITEMS_MAX_COUNT 100
#define RTMP_DATA_RESERVE_SIZE 400
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE)
#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.6");
SAVC(onMetaData);
SAVC(duration);
SAVC(width);
SAVC(height);
SAVC(videocodecid);
SAVC(videodatarate);
SAVC(framerate);
SAVC(audiocodecid);
SAVC(audiodatarate);
SAVC(audiosamplerate);
SAVC(audiosamplesize);
SAVC(audiochannels);
SAVC(stereo);
SAVC(encoder);
SAVC(av_stereo);
SAVC(fileSize);
SAVC(avc1);
SAVC(mp4a);
@interface LFStreamRtmpSocket ()<LFStreamingBufferDelegate>
{
PILI_RTMP* _rtmp;
}
@property (nonatomic, weak) id<LFStreamSocketDelegate> delegate;
@property (nonatomic, strong) LFLiveStreamInfo *stream;
@property (nonatomic, strong) LFStreamingBuffer *buffer;
@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;
@property (nonatomic, assign) BOOL isConnecting;
@property (nonatomic, assign) BOOL isReconnecting;
@property (nonatomic, assign) BOOL sendVideoHead;
@property (nonatomic, assign) BOOL sendAudioHead;
@end
@implementation LFStreamRtmpSocket
#pragma mark -- LFStreamSocket
- (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;
}
- (void) start{
dispatch_async(YYRtmpSendQueue(), ^{
[self _start];
});
}
- (void)_start{
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]];
}
- (void) stop{
dispatch_async(YYRtmpSendQueue(), ^{
[self _stop];
});
}
- (void)_stop{
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveStop];
}
if(_rtmp != NULL){
PILI_RTMP_Close(_rtmp, &_error);
PILI_RTMP_Free(_rtmp);
_rtmp = NULL;
}
}
- (void) sendFrame:(LFFrame*)frame{
dispatch_async(YYRtmpSendQueue(), ^{
if(!frame) return;
[self.buffer appendObject:frame];
[self sendFrame];
});
}
- (void) setDelegate:(id<LFStreamSocketDelegate>)delegate{
_delegate = delegate;
}
#pragma mark -- CustomMethod
- (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]]){
if(!self.sendVideoHead){
self.sendVideoHead = YES;
[self sendVideoHeader:(LFVideoFrame*)frame];
}else{
[self sendVideo:(LFVideoFrame*)frame];
}
}else{
if(!self.sendAudioHead){
self.sendAudioHead = YES;
[self sendAudioHeader:(LFAudioFrame*)frame];
}else{
[self sendAudio:frame];
}
}
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;
}
}
}
- (void)clean{
_isConnecting = NO;
_isReconnecting = NO;
_isSending = NO;
_isConnected = NO;
_sendAudioHead = NO;
_sendVideoHead = NO;
self.debugInfo = nil;
[self.buffer removeAllObject];
self.retryTimes4netWorkBreaken = 0;
}
-(NSInteger) RTMP264_Connect:(char *)push_url{
//由于摄像头的timestamp是一直在累加,需要每次得到相对时间戳
//分配与初始化
if(_isConnecting) return -1;
_isConnecting = YES;
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLivePending];
}
if(_rtmp != NULL){
PILI_RTMP_Close(_rtmp, &_error);
PILI_RTMP_Free(_rtmp);
}
_rtmp = PILI_RTMP_Alloc();
PILI_RTMP_Init(_rtmp);
//设置URL
if (PILI_RTMP_SetupURL(_rtmp, push_url, &_error) == FALSE){
//log(LOG_ERR, "RTMP_SetupURL() failed!");
goto Failed;
}
_rtmp->m_errorCallback = RTMPErrorCallback;
_rtmp->m_connCallback = ConnectionTimeCallback;
_rtmp->m_userData = (__bridge void*)self;
_rtmp->m_msgCounter = 1;
_rtmp->Link.timeout = RTMP_RECEIVE_TIMEOUT;
//设置可写,即发布流,这个函数必须在连接前使用,否则无效
PILI_RTMP_EnableWrite(_rtmp);
//连接服务器
if (PILI_RTMP_Connect(_rtmp, NULL, &_error) == FALSE){
goto Failed;
}
//连接流
if (PILI_RTMP_ConnectStream(_rtmp, 0, &_error) == FALSE) {
goto Failed;
}
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveStart];
}
[self sendMetaData];
_isConnected = YES;
_isConnecting = NO;
_isReconnecting = NO;
_isSending = NO;
_retryTimes4netWorkBreaken = 0;
return 0;
Failed:
PILI_RTMP_Close(_rtmp, &_error);
PILI_RTMP_Free(_rtmp);
_rtmp = NULL;
if(self.delegate && [self.delegate respondsToSelector:@selector(socketDidError:errorCode:)]){
[self.delegate socketDidError:self errorCode:LFLiveSocketError_ConnectSocket];
}
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveError];
}
return -1;
}
#pragma mark -- Rtmp Send
- (void)sendMetaData {
PILI_RTMPPacket packet;
char pbuf[2048], *pend = pbuf+sizeof(pbuf);
packet.m_nChannel = 0x03; // control channel (invoke)
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
packet.m_packetType = RTMP_PACKET_TYPE_INFO;
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = _rtmp->m_stream_id;
packet.m_hasAbsTimestamp = TRUE;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
char *enc = packet.m_body;
enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
enc = AMF_EncodeString(enc, pend, &av_onMetaData);
*enc++ = AMF_OBJECT;
enc = AMF_EncodeNamedNumber(enc, pend, &av_duration, 0.0);
enc = AMF_EncodeNamedNumber(enc, pend, &av_fileSize, 0.0);
// videosize
enc = AMF_EncodeNamedNumber(enc, pend, &av_width, _stream.videoConfiguration.videoSize.width);
enc = AMF_EncodeNamedNumber(enc, pend, &av_height, _stream.videoConfiguration.videoSize.height);
// video
enc = AMF_EncodeNamedString(enc, pend, &av_videocodecid, &av_avc1);
enc = AMF_EncodeNamedNumber(enc, pend, &av_videodatarate, _stream.videoConfiguration.videoBitRate / 1000.f);
enc = AMF_EncodeNamedNumber(enc, pend, &av_framerate, _stream.videoConfiguration.videoFrameRate);
// audio
enc = AMF_EncodeNamedString(enc, pend, &av_audiocodecid, &av_mp4a);
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiodatarate, _stream.audioConfiguration.audioBitrate);
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplerate, _stream.audioConfiguration.audioSampleRate);
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplesize, 16.0);
enc = AMF_EncodeNamedBoolean(enc, pend, &av_stereo, _stream.audioConfiguration.numberOfChannels==2);
// sdk version
enc = AMF_EncodeNamedString(enc, pend, &av_encoder, &av_SDKVersion);
*enc++ = 0;
*enc++ = 0;
*enc++ = AMF_OBJECT_END;
packet.m_nBodySize = enc - packet.m_body;
if(!PILI_RTMP_SendPacket(_rtmp, &packet, FALSE, &_error)) {
return;
}
}
- (void)sendVideoHeader:(LFVideoFrame*)videoFrame {
if(!videoFrame || !videoFrame.sps || !videoFrame.pps) return;
unsigned char * body=NULL;
NSInteger iIndex = 0;
NSInteger rtmpLength = 1024;
const char *sps = videoFrame.sps.bytes;
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);
body[iIndex++] = 0x17;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x01;
body[iIndex++] = sps[1];
body[iIndex++] = sps[2];
body[iIndex++] = sps[3];
body[iIndex++] = 0xff;
/*sps*/
body[iIndex++] = 0xe1;
body[iIndex++] = (sps_len >> 8) & 0xff;
body[iIndex++] = sps_len & 0xff;
memcpy(&body[iIndex],sps,sps_len);
iIndex += sps_len;
/*pps*/
body[iIndex++] = 0x01;
body[iIndex++] = (pps_len >> 8) & 0xff;
body[iIndex++] = (pps_len) & 0xff;
memcpy(&body[iIndex], pps, pps_len);
iIndex += pps_len;
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:iIndex nTimestamp:0];
free(body);
}
- (void)sendVideo:(LFVideoFrame*)frame{
if(!frame || !frame.data || frame.data.length < 11) return;
NSInteger i = 0;
NSInteger rtmpLength = frame.data.length+9;
unsigned char *body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
if(frame.isKeyFrame){
body[i++] = 0x17;// 1:Iframe 7:AVC
} else{
body[i++] = 0x27;// 2:Pframe 7:AVC
}
body[i++] = 0x01;// AVC NALU
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = (frame.data.length >> 24) & 0xff;
body[i++] = (frame.data.length >> 16) & 0xff;
body[i++] = (frame.data.length >> 8) & 0xff;
body[i++] = (frame.data.length ) & 0xff;
memcpy(&body[i],frame.data.bytes,frame.data.length);
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:(rtmpLength) nTimestamp:frame.timestamp];
free(body);
}
-(NSInteger) sendPacket:(unsigned int)nPacketType data:(unsigned char *)data size:(NSInteger) size nTimestamp:(uint64_t) nTimestamp{
NSInteger rtmpLength = size;
PILI_RTMPPacket rtmp_pack;
PILI_RTMPPacket_Reset(&rtmp_pack);
PILI_RTMPPacket_Alloc(&rtmp_pack,(uint32_t)rtmpLength);
rtmp_pack.m_nBodySize = (uint32_t)size;
memcpy(rtmp_pack.m_body,data,size);
rtmp_pack.m_hasAbsTimestamp = 0;
rtmp_pack.m_packetType = nPacketType;
if(_rtmp) rtmp_pack.m_nInfoField2 = _rtmp->m_stream_id;
rtmp_pack.m_nChannel = 0x04;
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_LARGE;
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size !=4){
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
rtmp_pack.m_nTimeStamp = (uint32_t)nTimestamp;
NSInteger nRet = [self RtmpPacketSend:&rtmp_pack];
PILI_RTMPPacket_Free(&rtmp_pack);
return nRet;
}
- (NSInteger)RtmpPacketSend:(PILI_RTMPPacket*)packet{
if (PILI_RTMP_IsConnected(_rtmp)){
int success = PILI_RTMP_SendPacket(_rtmp,packet,0,&_error);
if(success){
self.isSending = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self sendFrame];
});
}
return success;
}
return -1;
}
- (void)sendAudioHeader:(LFAudioFrame*)audioFrame{
if(!audioFrame || !audioFrame.audioInfo) return;
NSInteger rtmpLength = audioFrame.audioInfo.length + 2;/*spec data长度,一般是2*/
unsigned char * body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
/*AF 00 + AAC RAW data*/
body[0] = 0xAF;
body[1] = 0x00;
memcpy(&body[2],audioFrame.audioInfo.bytes,audioFrame.audioInfo.length); /*spec_buf是AAC sequence header数据*/
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:0];
free(body);
}
- (void)sendAudio:(LFFrame*)frame {
if(!frame) return;
NSInteger rtmpLength = frame.data.length + 2;/*spec data长度,一般是2*/
unsigned char * body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
/*AF 01 + AAC RAW data*/
body[0] = 0xAF;
body[1] = 0x01;
memcpy(&body[2],frame.data.bytes,frame.data.length);
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:frame.timestamp];
free(body);
}
// 断线重连
-(void) reconnect {
dispatch_async(YYRtmpSendQueue(), ^{
_isReconnecting = NO;
if(_isConnected) return;
[self _stop];
[self _start];
});
}
#pragma mark -- CallBack
void RTMPErrorCallback(RTMPError *error, void *userData){
LFStreamRtmpSocket *socket = (__bridge LFStreamRtmpSocket*)userData;
if(error->code < 0){
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)), dispatch_get_main_queue(), ^{
[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
- (LFStreamingBuffer*)buffer{
if(!_buffer){
_buffer = [[LFStreamingBuffer alloc] init];
_buffer.delegate = self;
}
return _buffer;
}
- (LFLiveDebug*)debugInfo{
if(!_debugInfo){
_debugInfo = [[LFLiveDebug alloc] init];
}
return _debugInfo;
}
@end
@@ -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){
-342
View File
@@ -1,342 +0,0 @@
//
// LFStreamRtmpSocket.m
// LFLiveKit
//
// Created by admin on 16/5/18.
// Copyright © 2016年 live Interactive. All rights reserved.
//
#import "LFStreamRtmpSocket.h"
#import "rtmp.h"
#define DATA_ITEMS_MAX_COUNT 100
#define RTMP_DATA_RESERVE_SIZE 400
#define RTMP_CONNECTION_TIMEOUT 1500
#define RTMP_RECEIVE_TIMEOUT 2
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE)
@interface LFStreamRtmpSocket ()<LFStreamingBufferDelegate>
{
RTMP* _rtmp;
}
@property (nonatomic, weak) id<LFStreamSocketDelegate> delegate;
@property (nonatomic, strong) LFLiveStreamInfo *stream;
@property (nonatomic, strong) LFStreamingBuffer *buffer;
@property (nonatomic, strong) dispatch_queue_t socketQueue;
@property (nonatomic, assign) NSInteger retryTimes4netWorkBreaken;
@property (nonatomic, assign) BOOL isSending;
@property (nonatomic, assign) BOOL isConnected;
@property (nonatomic, assign) BOOL isConnecting;
@property (nonatomic, assign) BOOL isReconnecting;
@property (nonatomic, assign) BOOL sendVideoHead;
@property (nonatomic, assign) BOOL sendAudioHead;
@end
@implementation LFStreamRtmpSocket
#pragma mark -- LFStreamSocket
- (instancetype)initWithStream:(LFLiveStreamInfo*)stream{
if(!stream) @throw [NSException exceptionWithName:@"LFStreamRtmpSocket init error" reason:@"stream is nil" userInfo:nil];
if(self = [super init]){
_stream = stream;
}
return self;
}
- (void) start{
dispatch_async(self.socketQueue, ^{
if(!_stream) return;
if(_isConnecting) return;
if(_rtmp != NULL) return;
[self RTMP264_Connect:(char*)[_stream.url cStringUsingEncoding:NSASCIIStringEncoding]];
});
}
- (void) stop{
dispatch_async(self.socketQueue, ^{
if(_rtmp != NULL){
RTMP_Close(_rtmp);
RTMP_Free(_rtmp);
_rtmp = NULL;
}
[self clean];
});
}
- (void) sendFrame:(LFFrame*)frame{
__weak typeof(self) _self = self;
dispatch_async(self.socketQueue, ^{
__strong typeof(_self) self = _self;
if(!frame) return;
[self.buffer appendObject:frame];
[self sendFrame];
});
}
- (void) setDelegate:(id<LFStreamSocketDelegate>)delegate{
_delegate = delegate;
}
#pragma mark -- CustomMethod
- (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]]){
if(!self.sendVideoHead){
self.sendVideoHead = YES;
[self sendVideoHeader:(LFVideoFrame*)frame];
}else{
[self sendVideo:(LFVideoFrame*)frame];
}
}else{
if(!self.sendAudioHead){
self.sendAudioHead = YES;
[self sendAudioHeader:(LFAudioFrame*)frame];
}else{
[self sendAudio:frame];
}
}
}
}
- (void)clean{
_isConnecting = NO;
_isReconnecting = NO;
_isSending = NO;
_isConnected = NO;
_sendAudioHead = NO;
_sendVideoHead = NO;
[self.buffer removeAllObject];
self.retryTimes4netWorkBreaken = 0;
}
-(NSInteger) RTMP264_Connect:(char *)push_url{
//由于摄像头的timestamp是一直在累加,需要每次得到相对时间戳
//分配与初始化
if(_isConnecting) return -1;
_isConnecting = YES;
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLivePending];
}
if(_rtmp != NULL){
RTMP_Close(_rtmp);
RTMP_Free(_rtmp);
}
_rtmp = RTMP_Alloc();
RTMP_Init(_rtmp);
//设置URL
if (RTMP_SetupURL(_rtmp, push_url) < 0){
//log(LOG_ERR, "RTMP_SetupURL() failed!");
goto Failed;
}
//设置可写,即发布流,这个函数必须在连接前使用,否则无效
RTMP_EnableWrite(_rtmp);
_rtmp->Link.timeout = RTMP_RECEIVE_TIMEOUT;
//连接服务器
if (RTMP_Connect(_rtmp, NULL) < 0){
goto Failed;
}
//连接流
if (RTMP_ConnectStream(_rtmp, 0) < 0) {
goto Failed;
}
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveStart];
}
_isConnected = YES;
_isConnecting = NO;
_isReconnecting = NO;
_isSending = NO;
_retryTimes4netWorkBreaken = 0;
return 0;
Failed:
RTMP_Close(_rtmp);
RTMP_Free(_rtmp);
[self clean];
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
[self.delegate socketStatus:self status:LFLiveError];
}
return -1;
}
#pragma mark -- Rtmp Send
- (void)sendVideoHeader:(LFVideoFrame*)videoFrame{
if(!videoFrame || !videoFrame.sps || !videoFrame.pps) return;
unsigned char * body=NULL;
NSInteger iIndex = 0;
NSInteger rtmpLength = 1024;
const char *sps = videoFrame.sps.bytes;
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);
body[iIndex++] = 0x17;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x00;
body[iIndex++] = 0x01;
body[iIndex++] = sps[1];
body[iIndex++] = sps[2];
body[iIndex++] = sps[3];
body[iIndex++] = 0xff;
/*sps*/
body[iIndex++] = 0xe1;
body[iIndex++] = (sps_len >> 8) & 0xff;
body[iIndex++] = sps_len & 0xff;
memcpy(&body[iIndex],sps,sps_len);
iIndex += sps_len;
/*pps*/
body[iIndex++] = 0x01;
body[iIndex++] = (pps_len >> 8) & 0xff;
body[iIndex++] = (pps_len) & 0xff;
memcpy(&body[iIndex], pps, pps_len);
iIndex += pps_len;
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:iIndex nTimestamp:0];
free(body);
}
- (void)sendVideo:(LFVideoFrame*)frame{
if(!frame || !frame.data || frame.data.length < 11) return;
NSInteger i = 0;
NSInteger rtmpLength = frame.data.length+9;
unsigned char *body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
if(frame.isKeyFrame){
body[i++] = 0x17;// 1:Iframe 7:AVC
} else{
body[i++] = 0x27;// 2:Pframe 7:AVC
}
body[i++] = 0x01;// AVC NALU
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = 0x00;
body[i++] = (frame.data.length >> 24) & 0xff;
body[i++] = (frame.data.length >> 16) & 0xff;
body[i++] = (frame.data.length >> 8) & 0xff;
body[i++] = (frame.data.length ) & 0xff;
memcpy(&body[i],frame.data.bytes,frame.data.length);
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:(rtmpLength) nTimestamp:frame.timestamp];
free(body);
}
-(NSInteger) sendPacket:(unsigned int)nPacketType data:(unsigned char *)data size:(NSInteger) size nTimestamp:(uint64_t) nTimestamp{
NSInteger rtmpLength = size;
RTMPPacket rtmp_pack;
RTMPPacket_Reset(&rtmp_pack);
RTMPPacket_Alloc(&rtmp_pack,(uint32_t)rtmpLength);
rtmp_pack.m_nBodySize = (uint32_t)size;
memcpy(rtmp_pack.m_body,data,size);
rtmp_pack.m_hasAbsTimestamp = 0;
rtmp_pack.m_packetType = nPacketType;
if(_rtmp) rtmp_pack.m_nInfoField2 = _rtmp->m_stream_id;
rtmp_pack.m_nChannel = 0x04;
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_LARGE;
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size !=4){
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
}
rtmp_pack.m_nTimeStamp = (uint32_t)nTimestamp;
NSInteger nRet = [self RtmpPacketSend:&rtmp_pack];
RTMPPacket_Free(&rtmp_pack);
return nRet;
}
- (NSInteger)RtmpPacketSend:(RTMPPacket*)packet{
if (RTMP_IsConnected(_rtmp)){
int success = RTMP_SendPacket(_rtmp,packet,0);
if(success){
self.isSending = NO;
[self sendFrame];
}
return success;
}
return -1;
}
- (void)sendAudioHeader:(LFAudioFrame*)audioFrame{
if(!audioFrame || !audioFrame.audioInfo) return;
NSInteger rtmpLength = audioFrame.audioInfo.length + 2;/*spec data长度,一般是2*/
unsigned char * body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
/*AF 00 + AAC RAW data*/
body[0] = 0xAF;
body[1] = 0x00;
memcpy(&body[2],audioFrame.audioInfo.bytes,audioFrame.audioInfo.length); /*spec_buf是AAC sequence header数据*/
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:0];
free(body);
}
- (void)sendAudio:(LFFrame*)frame{
if(!frame) return;
NSInteger rtmpLength = frame.data.length + 2;/*spec data长度,一般是2*/
unsigned char * body = (unsigned char*)malloc(rtmpLength);
memset(body,0,rtmpLength);
/*AF 01 + AAC RAW data*/
body[0] = 0xAF;
body[1] = 0x01;
memcpy(&body[2],frame.data.bytes,frame.data.length);
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:frame.timestamp];
free(body);
}
#pragma mark -- Getter Setter
- (dispatch_queue_t)socketQueue{
if(!_socketQueue){
_socketQueue = dispatch_queue_create("com.youku.LaiFeng.live.socketQueue", NULL);
}
return _socketQueue;
}
- (LFStreamingBuffer*)buffer{
if(!_buffer){
_buffer = [[LFStreamingBuffer alloc] init];
_buffer.delegate = self;
}
return _buffer;
}
@end
+4
View File
@@ -0,0 +1,4 @@
#CocoaPods
Pods/
Podfile.lock
@@ -0,0 +1,474 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
57B42059E84CC681C5C99B68 /* libPods-LFLiveKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */; };
840762F11D07C7D0000FD0BF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F01D07C7D0000FD0BF /* main.m */; };
840762F41D07C7D0000FD0BF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F31D07C7D0000FD0BF /* AppDelegate.m */; };
840762F71D07C7D0000FD0BF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F61D07C7D0000FD0BF /* ViewController.m */; };
840762FC1D07C7D0000FD0BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 840762FB1D07C7D0000FD0BF /* Assets.xcassets */; };
840762FF1D07C7D0000FD0BF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */; };
840763291D07C894000FD0BF /* UIControl+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763241D07C894000FD0BF /* UIControl+YYAdd.m */; };
8407632A1D07C894000FD0BF /* UIView+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763261D07C894000FD0BF /* UIView+YYAdd.m */; };
8407632B1D07C894000FD0BF /* LFLivePreview.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763281D07C894000FD0BF /* LFLivePreview.m */; };
840763351D07C899000FD0BF /* camra_beauty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632D1D07C899000FD0BF /* camra_beauty@2x.png */; };
840763361D07C899000FD0BF /* camra_beauty@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632E1D07C899000FD0BF /* camra_beauty@3x.png */; };
840763371D07C899000FD0BF /* camra_beauty_close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */; };
840763381D07C899000FD0BF /* camra_beauty_close@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763301D07C899000FD0BF /* camra_beauty_close@3x.png */; };
840763391D07C899000FD0BF /* camra_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763311D07C899000FD0BF /* camra_preview@2x.png */; };
8407633A1D07C899000FD0BF /* camra_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763321D07C899000FD0BF /* camra_preview@3x.png */; };
8407633B1D07C899000FD0BF /* close_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763331D07C899000FD0BF /* close_preview@2x.png */; };
8407633C1D07C899000FD0BF /* close_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763341D07C899000FD0BF /* close_preview@3x.png */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.release.xcconfig"; sourceTree = "<group>"; };
5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.debug.xcconfig"; sourceTree = "<group>"; };
840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LFLiveKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
840762F01D07C7D0000FD0BF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
840762F21D07C7D0000FD0BF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
840762F31D07C7D0000FD0BF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
840762F51D07C7D0000FD0BF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
840762F61D07C7D0000FD0BF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
840762FB1D07C7D0000FD0BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
840762FE1D07C7D0000FD0BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
840763001D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
840763091D07C7D0000FD0BF /* LFLiveKitDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LFLiveKitDemoTests.m; sourceTree = "<group>"; };
8407630B1D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
840763141D07C7D0000FD0BF /* LFLiveKitDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LFLiveKitDemoUITests.m; sourceTree = "<group>"; };
840763161D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
840763231D07C894000FD0BF /* UIControl+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+YYAdd.h"; sourceTree = "<group>"; };
840763241D07C894000FD0BF /* UIControl+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+YYAdd.m"; sourceTree = "<group>"; };
840763251D07C894000FD0BF /* UIView+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+YYAdd.h"; sourceTree = "<group>"; };
840763261D07C894000FD0BF /* UIView+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+YYAdd.m"; sourceTree = "<group>"; };
840763271D07C894000FD0BF /* LFLivePreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLivePreview.h; sourceTree = "<group>"; };
840763281D07C894000FD0BF /* LFLivePreview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLivePreview.m; sourceTree = "<group>"; };
8407632D1D07C899000FD0BF /* camra_beauty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@2x.png"; sourceTree = "<group>"; };
8407632E1D07C899000FD0BF /* camra_beauty@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@3x.png"; sourceTree = "<group>"; };
8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@2x.png"; sourceTree = "<group>"; };
840763301D07C899000FD0BF /* camra_beauty_close@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@3x.png"; sourceTree = "<group>"; };
840763311D07C899000FD0BF /* camra_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@2x.png"; sourceTree = "<group>"; };
840763321D07C899000FD0BF /* camra_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@3x.png"; sourceTree = "<group>"; };
840763331D07C899000FD0BF /* close_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@2x.png"; sourceTree = "<group>"; };
840763341D07C899000FD0BF /* close_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@3x.png"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
840762E91D07C7D0000FD0BF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
57B42059E84CC681C5C99B68 /* libPods-LFLiveKitDemo.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
713DA9EBCA308093C74917F9 /* Frameworks */ = {
isa = PBXGroup;
children = (
5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
840762E31D07C7D0000FD0BF = {
isa = PBXGroup;
children = (
840762EE1D07C7D0000FD0BF /* LFLiveKitDemo */,
840763081D07C7D0000FD0BF /* LFLiveKitDemoTests */,
840763131D07C7D0000FD0BF /* LFLiveKitDemoUITests */,
840762ED1D07C7D0000FD0BF /* Products */,
9BA1F10CECEAF692D0035AED /* Pods */,
713DA9EBCA308093C74917F9 /* Frameworks */,
);
sourceTree = "<group>";
};
840762ED1D07C7D0000FD0BF /* Products */ = {
isa = PBXGroup;
children = (
840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
840762EE1D07C7D0000FD0BF /* LFLiveKitDemo */ = {
isa = PBXGroup;
children = (
840763221D07C894000FD0BF /* category */,
840763271D07C894000FD0BF /* LFLivePreview.h */,
840763281D07C894000FD0BF /* LFLivePreview.m */,
840762F21D07C7D0000FD0BF /* AppDelegate.h */,
840762F31D07C7D0000FD0BF /* AppDelegate.m */,
840762F51D07C7D0000FD0BF /* ViewController.h */,
840762F61D07C7D0000FD0BF /* ViewController.m */,
840762FB1D07C7D0000FD0BF /* Assets.xcassets */,
840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */,
840763001D07C7D0000FD0BF /* Info.plist */,
840762EF1D07C7D0000FD0BF /* Supporting Files */,
);
path = LFLiveKitDemo;
sourceTree = "<group>";
};
840762EF1D07C7D0000FD0BF /* Supporting Files */ = {
isa = PBXGroup;
children = (
8407632C1D07C899000FD0BF /* images */,
840762F01D07C7D0000FD0BF /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
840763081D07C7D0000FD0BF /* LFLiveKitDemoTests */ = {
isa = PBXGroup;
children = (
840763091D07C7D0000FD0BF /* LFLiveKitDemoTests.m */,
8407630B1D07C7D0000FD0BF /* Info.plist */,
);
path = LFLiveKitDemoTests;
sourceTree = "<group>";
};
840763131D07C7D0000FD0BF /* LFLiveKitDemoUITests */ = {
isa = PBXGroup;
children = (
840763141D07C7D0000FD0BF /* LFLiveKitDemoUITests.m */,
840763161D07C7D0000FD0BF /* Info.plist */,
);
path = LFLiveKitDemoUITests;
sourceTree = "<group>";
};
840763221D07C894000FD0BF /* category */ = {
isa = PBXGroup;
children = (
840763231D07C894000FD0BF /* UIControl+YYAdd.h */,
840763241D07C894000FD0BF /* UIControl+YYAdd.m */,
840763251D07C894000FD0BF /* UIView+YYAdd.h */,
840763261D07C894000FD0BF /* UIView+YYAdd.m */,
);
path = category;
sourceTree = "<group>";
};
8407632C1D07C899000FD0BF /* images */ = {
isa = PBXGroup;
children = (
8407632D1D07C899000FD0BF /* camra_beauty@2x.png */,
8407632E1D07C899000FD0BF /* camra_beauty@3x.png */,
8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */,
840763301D07C899000FD0BF /* camra_beauty_close@3x.png */,
840763311D07C899000FD0BF /* camra_preview@2x.png */,
840763321D07C899000FD0BF /* camra_preview@3x.png */,
840763331D07C899000FD0BF /* close_preview@2x.png */,
840763341D07C899000FD0BF /* close_preview@3x.png */,
);
path = images;
sourceTree = "<group>";
};
9BA1F10CECEAF692D0035AED /* Pods */ = {
isa = PBXGroup;
children = (
7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */,
195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
840762EB1D07C7D0000FD0BF /* LFLiveKitDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 840763191D07C7D0000FD0BF /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
buildPhases = (
7E4C7C5523618A0595228010 /* 📦 Check Pods Manifest.lock */,
840762E81D07C7D0000FD0BF /* Sources */,
840762E91D07C7D0000FD0BF /* Frameworks */,
840762EA1D07C7D0000FD0BF /* Resources */,
E4007BB7D4B0E165011BF22F /* 📦 Embed Pods Frameworks */,
64FCFF97E6544B1C8F282394 /* 📦 Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = LFLiveKitDemo;
productName = LFLiveKitDemo;
productReference = 840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
840762E41D07C7D0000FD0BF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = admin;
TargetAttributes = {
840762EB1D07C7D0000FD0BF = {
CreatedOnToolsVersion = 7.3;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = 840762E71D07C7D0000FD0BF /* Build configuration list for PBXProject "LFLiveKitDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 840762E31D07C7D0000FD0BF;
productRefGroup = 840762ED1D07C7D0000FD0BF /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
840762EB1D07C7D0000FD0BF /* LFLiveKitDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
840762EA1D07C7D0000FD0BF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
840763371D07C899000FD0BF /* camra_beauty_close@2x.png in Resources */,
840762FF1D07C7D0000FD0BF /* LaunchScreen.storyboard in Resources */,
840763351D07C899000FD0BF /* camra_beauty@2x.png in Resources */,
840762FC1D07C7D0000FD0BF /* Assets.xcassets in Resources */,
8407633A1D07C899000FD0BF /* camra_preview@3x.png in Resources */,
840763381D07C899000FD0BF /* camra_beauty_close@3x.png in Resources */,
8407633C1D07C899000FD0BF /* close_preview@3x.png in Resources */,
8407633B1D07C899000FD0BF /* close_preview@2x.png in Resources */,
840763391D07C899000FD0BF /* camra_preview@2x.png in Resources */,
840763361D07C899000FD0BF /* camra_beauty@3x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
64FCFF97E6544B1C8F282394 /* 📦 Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "📦 Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-resources.sh\"\n";
showEnvVarsInLog = 0;
};
7E4C7C5523618A0595228010 /* 📦 Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "📦 Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
E4007BB7D4B0E165011BF22F /* 📦 Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "📦 Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
840762E81D07C7D0000FD0BF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8407632B1D07C894000FD0BF /* LFLivePreview.m in Sources */,
840762F71D07C7D0000FD0BF /* ViewController.m in Sources */,
840763291D07C894000FD0BF /* UIControl+YYAdd.m in Sources */,
840762F41D07C7D0000FD0BF /* AppDelegate.m in Sources */,
8407632A1D07C894000FD0BF /* UIView+YYAdd.m in Sources */,
840762F11D07C7D0000FD0BF /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
840762FE1D07C7D0000FD0BF /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
840763171D07C7D0000FD0BF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
840763181D07C7D0000FD0BF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
8407631A1D07C7D0000FD0BF /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
8407631B1D07C7D0000FD0BF /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
840762E71D07C7D0000FD0BF /* Build configuration list for PBXProject "LFLiveKitDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
840763171D07C7D0000FD0BF /* Debug */,
840763181D07C7D0000FD0BF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
840763191D07C7D0000FD0BF /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8407631A1D07C7D0000FD0BF /* Debug */,
8407631B1D07C7D0000FD0BF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 840762E41D07C7D0000FD0BF /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:LFLiveKitDemo.xcodeproj">
</FileRef>
</Workspace>
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemo.app"
BlueprintName = "LFLiveKitDemo"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "840763041D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemoTests.xctest"
BlueprintName = "LFLiveKitDemoTests"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "8407630F1D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemoUITests.xctest"
BlueprintName = "LFLiveKitDemoUITests"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemo.app"
BlueprintName = "LFLiveKitDemo"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemo.app"
BlueprintName = "LFLiveKitDemo"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
BuildableName = "LFLiveKitDemo.app"
BlueprintName = "LFLiveKitDemo"
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>LFLiveKitDemo.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>840762EB1D07C7D0000FD0BF</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>840763041D07C7D0000FD0BF</key>
<dict>
<key>primary</key>
<true/>
</dict>
<key>8407630F1D07C7D0000FD0BF</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:LFLiveKitDemo.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>
+17
View File
@@ -0,0 +1,17 @@
//
// AppDelegate.h
// LFLiveKitDemo
//
// Created by admin on 16/6/8.
// Copyright © 2016年 admin. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
+54
View File
@@ -0,0 +1,54 @@
//
// AppDelegate.m
// LFLiveKitDemo
//
// Created by admin on 16/6/8.
// Copyright © 2016年 admin. All rights reserved.
//
#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
// nav.navigationBarHidden = YES;
self.window.rootViewController = [[ViewController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
@@ -0,0 +1,68 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+49
View File
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
+14
View File
@@ -0,0 +1,14 @@
//
// LFLivePreview.h
// LFLiveKit
//
// Created by 倾慕 on 16/5/2.
// Copyright © 2016年 live Interactive. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface LFLivePreview : UIView
@end
+327
View File
@@ -0,0 +1,327 @@
//
// LFLivePreview.m
// LFLiveKit
//
// Created by 倾慕 on 16/5/2.
// Copyright © 2016年 live Interactive. All rights reserved.
//
#import "LFLivePreview.h"
#import "UIControl+YYAdd.h"
#import "UIView+YYAdd.h"
#import "LFLiveSession.h"
@interface LFLivePreview ()<LFLiveSessionDelegate>
@property (nonatomic, strong) UIButton *beautyButton;
@property (nonatomic, strong) UIButton *cameraButton;
@property (nonatomic, strong) UIButton *closeButton;
@property (nonatomic, strong) UIButton *startLiveButton;
@property (nonatomic, strong) UIView *containerView;
@property (nonatomic, strong) LFLiveDebug *debugInfo;
@property (nonatomic, strong) LFLiveSession *session;
@property (nonatomic, strong) UILabel *stateLabel;
@end
@implementation LFLivePreview
- (instancetype)initWithFrame:(CGRect)frame{
if(self = [super initWithFrame:frame]){
self.backgroundColor = [UIColor clearColor];
[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];
[self.containerView addSubview:self.startLiveButton];
}
return self;
}
#pragma mark -- Public Method
- (void)requestAccessForVideo{
__weak typeof(self) _self = self;
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
switch (status) {
case AVAuthorizationStatusNotDetermined:{
// 许可对话没有出现,发起授权许可
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
dispatch_async(dispatch_get_main_queue(), ^{
[_self.session setRunning:YES];
});
}
}];
break;
}
case AVAuthorizationStatusAuthorized:{
// 已经开启授权,可继续
dispatch_async(dispatch_get_main_queue(), ^{
[_self.session setRunning:YES];
});
break;
}
case AVAuthorizationStatusDenied:
case AVAuthorizationStatusRestricted:
// 用户明确地拒绝授权,或者相机设备无法访问
break;
default:
break;
}
}
- (void)requestAccessForAudio{
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
switch (status) {
case AVAuthorizationStatusNotDetermined:{
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
}];
break;
}
case AVAuthorizationStatusAuthorized:{
break;
}
case AVAuthorizationStatusDenied:
case AVAuthorizationStatusRestricted:
break;
default:
break;
}
}
#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
- (LFLiveSession*)session{
if(!_session){
/***  默认分辨率368 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Medium2] liveType:LFLiveRTMP];
_session.delegate = self;
/**   自己定制单声道 */
/*
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
audioConfiguration.numberOfChannels = 1;
audioConfiguration.audioBitrate = LFLiveAudioBitRate_64Kbps;
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration] liveType:LFLiveRTMP];
*/
/**   自己定制高质量音频96K */
/*
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
audioConfiguration.numberOfChannels = 2;
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration] liveType:LFLiveRTMP];
*/
/**   自己定制高质量音频96K 分辨率设置为540*960 方向竖屏 */
/*
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
audioConfiguration.numberOfChannels = 2;
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
videoConfiguration.videoSize = CGSizeMake(540, 960);
videoConfiguration.videoBitRate = 800*1024;
videoConfiguration.videoMaxBitRate = 1000*1024;
videoConfiguration.videoMinBitRate = 500*1024;
videoConfiguration.videoFrameRate = 24;
videoConfiguration.videoMaxKeyframeInterval = 48;
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
videoConfiguration.sessionPreset = LFCaptureSessionPreset540x960;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
*/
/**   自己定制高质量音频128K 分辨率设置为720*1280 方向竖屏 */
/*
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
audioConfiguration.numberOfChannels = 2;
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
videoConfiguration.videoSize = CGSizeMake(720, 1280);
videoConfiguration.videoBitRate = 800*1024;
videoConfiguration.videoMaxBitRate = 1000*1024;
videoConfiguration.videoMinBitRate = 500*1024;
videoConfiguration.videoFrameRate = 15;
videoConfiguration.videoMaxKeyframeInterval = 30;
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
*/
/**   自己定制高质量音频128K 分辨率设置为720*1280 方向横屏 */
/*
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
audioConfiguration.numberOfChannels = 2;
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
videoConfiguration.videoSize = CGSizeMake(1280, 720);
videoConfiguration.videoBitRate = 800*1024;
videoConfiguration.videoMaxBitRate = 1000*1024;
videoConfiguration.videoMinBitRate = 500*1024;
videoConfiguration.videoFrameRate = 15;
videoConfiguration.videoMaxKeyframeInterval = 30;
videoConfiguration.orientation = UIInterfaceOrientationLandscapeLeft;
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
*/
_session.delegate = self;
_session.preView = self;
}
return _session;
}
- (UIView*)containerView{
if(!_containerView){
_containerView = [UIView new];
_containerView.frame = self.bounds;
_containerView.backgroundColor = [UIColor clearColor];
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
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];
_closeButton.size = CGSizeMake(44, 44);
_closeButton.left = self.width - 10 - _closeButton.width;
_closeButton.top = 20;
[_closeButton setImage:[UIImage imageNamed:@"close_preview"] forState:UIControlStateNormal];
_closeButton.exclusiveTouch = YES;
[_closeButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
}];
}
return _closeButton;
}
- (UIButton*)cameraButton{
if(!_cameraButton){
_cameraButton = [UIButton new];
_cameraButton.size = CGSizeMake(44, 44);
_cameraButton.origin = CGPointMake(_closeButton.left - 10 - _cameraButton.width, 20);
[_cameraButton setImage:[UIImage imageNamed:@"camra_preview"] forState:UIControlStateNormal];
_cameraButton.exclusiveTouch = YES;
__weak typeof(self) _self = self;
[_cameraButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
AVCaptureDevicePosition devicePositon = _self.session.captureDevicePosition;
_self.session.captureDevicePosition = (devicePositon == AVCaptureDevicePositionBack) ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
}];
}
return _cameraButton;
}
- (UIButton*)beautyButton{
if(!_beautyButton){
_beautyButton = [UIButton new];
_beautyButton.size = CGSizeMake(44, 44);
_beautyButton.origin = CGPointMake(_cameraButton.left - 10 - _beautyButton.width,20);
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty"] forState:UIControlStateSelected];
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty_close"] forState:UIControlStateNormal];
_beautyButton.exclusiveTouch = YES;
__weak typeof(self) _self = self;
[_beautyButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
_self.session.beautyFace = !_self.session.beautyFace;
_self.beautyButton.selected = !_self.session.beautyFace;
}];
}
return _beautyButton;
}
- (UIButton*)startLiveButton{
if(!_startLiveButton){
_startLiveButton = [UIButton new];
_startLiveButton.size = CGSizeMake(self.width - 60, 44);
_startLiveButton.left = 30;
_startLiveButton.bottom = self.height - 50;
_startLiveButton.layer.cornerRadius = _startLiveButton.height/2;
[_startLiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_startLiveButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
[_startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
[_startLiveButton setBackgroundColor:[UIColor colorWithRed:50 green:32 blue:245 alpha:1]];
_startLiveButton.exclusiveTouch = YES;
__weak typeof(self) _self = self;
[_startLiveButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
_self.startLiveButton.selected = !_self.startLiveButton.selected;
if(_self.startLiveButton.selected){
[_self.startLiveButton setTitle:@"结束直播" forState:UIControlStateNormal];
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream789";
//stream.url = @"rtmp://daniulive.com:1935/live/stream2399";
[_self.session startLive:stream];
}else{
[_self.startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
[_self.session stopLive];
}
}];
}
return _startLiveButton;
}
@end
+8
View File
@@ -0,0 +1,8 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios,'8.0'
target "LFLiveKitDemo" do
pod 'LFLiveKit', '~> 1.5.2'
end
@@ -0,0 +1,15 @@
//
// ViewController.h
// LFLiveKitDemo
//
// Created by admin on 16/6/8.
// Copyright © 2016年 admin. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
@@ -0,0 +1,39 @@
//
// ViewController.m
// LFLiveKitDemo
//
// Created by admin on 16/6/8.
// Copyright © 2016年 admin. All rights reserved.
//
#import "ViewController.h"
#import "LFLivePreview.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addSubview:[[LFLivePreview alloc] initWithFrame:self.view.bounds]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
@end
@@ -0,0 +1,71 @@
//
// UIControl+YYAdd.h
//
//
// Created by guoyaoyuan on 13-4-5.
// Copyright (c) 2013 live Interactive. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
Provides extensions for `UIControl`.
*/
@interface UIControl (YYAdd)
/**
Removes all targets and actions for a particular event (or events)
from an internal dispatch table.
*/
- (void)removeAllTargets;
/**
Adds or replaces a target and action for a particular event (or events)
to an internal dispatch table.
@param target The target object—that is, the object to which the
action message is sent. If this is nil, the responder
chain is searched for an object willing to respond to the
action message.
@param action A selector identifying an action message. It cannot be NULL.
@param controlEvents A bitmask specifying the control events for which the
action message is sent.
*/
- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
/**
Adds a block for a particular event (or events) to an internal dispatch table.
It will cause a strong reference to @a block.
@param block The block which is invoked then the action message is
sent (cannot be nil). The block is retained.
@param controlEvents A bitmask specifying the control events for which the
action message is sent.
*/
- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
/**
Adds or replaces a block for a particular event (or events) to an internal
dispatch table. It will cause a strong reference to @a block.
@param block The block which is invoked then the action message is
sent (cannot be nil). The block is retained.
@param controlEvents A bitmask specifying the control events for which the
action message is sent.
*/
- (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;
/**
Removes all blocks for a particular event (or events) from an internal
dispatch table.
@param controlEvents A bitmask specifying the control events for which the
action message is sent.
*/
- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;
@end
@@ -0,0 +1,105 @@
//
// UIControl+YYAdd.m
//
//
// Created by guoyaoyuan on 13-4-5.
// Copyright (c) 2013 live Interactive. All rights reserved.
//
#import "UIControl+YYAdd.h"
#import <objc/runtime.h>
static const int block_key;
@interface _LFUIControlBlockTarget : NSObject
@property (nonatomic, copy) void (^block)(id sender);
@property (nonatomic, assign) UIControlEvents events;
- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events;
- (void)invoke:(id)sender;
@end
@implementation _LFUIControlBlockTarget
- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events {
self = [super init];
if (self) {
self.block = block;
self.events = events;
}
return self;
}
- (void)invoke:(id)sender {
if (self.block) self.block(sender);
}
@end
@implementation UIControl (LFAdd)
- (void)removeAllTargets {
[[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) {
[self removeTarget:object
action:NULL
forControlEvents:UIControlEventAllEvents];
}];
}
- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
NSSet *targets = [self allTargets];
for (id currentTarget in targets) {
NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents];
for (NSString *currentAction in actions) {
[self removeTarget:currentTarget action:NSSelectorFromString(currentAction)
forControlEvents:controlEvents];
}
}
[self addTarget:target action:action forControlEvents:controlEvents];
}
- (void)addBlockForControlEvents:(UIControlEvents)controlEvents
block:(void (^)(id sender))block {
_LFUIControlBlockTarget *target = [[_LFUIControlBlockTarget alloc]
initWithBlock:block events:controlEvents];
[self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
NSMutableArray *targets = [self _lf_allUIControlBlockTargets];
[targets addObject:target];
}
- (void)setBlockForControlEvents:(UIControlEvents)controlEvents
block:(void (^)(id sender))block {
[self removeAllBlocksForControlEvents:controlEvents];
[self addBlockForControlEvents:controlEvents block:block];
}
- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents {
NSMutableArray *targets = [self _lf_allUIControlBlockTargets];
NSMutableArray *removes = [NSMutableArray array];
[targets enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
_LFUIControlBlockTarget *target = (_LFUIControlBlockTarget *)obj;
if (target.events == controlEvents) {
[removes addObject:target];
[self removeTarget:target
action:@selector(invoke:)
forControlEvents:controlEvents];
}
}];
[targets removeObjectsInArray:removes];
}
- (NSMutableArray *)_lf_allUIControlBlockTargets {
NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
if (!targets) {
targets = [NSMutableArray array];
objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return targets;
}
@end
@@ -0,0 +1,132 @@
//
// UIView+Add.h
//
//
// Created by guoyaoyuan on 13-4-3.
// Copyright (c) 2013 live Interactive. All rights reserved.
//
#import <UIKit/UIKit.h>
/**
Provides extensions for `UIView`.
*/
@interface UIView (YYAdd)
/**
Create a snapshot image of the complete view hierarchy.
This method should be called in main thread.
*/
- (UIImage *)snapshotImage;
/**
Create a snapshot PDF of the complete view hierarchy.
This method should be called in main thread.
*/
- (NSData *)snapshotPDF;
/**
Shortcut to set the view.layer's shadow
@param color Shadow Color
@param offset Shadow offset
@param radius Shadow radius
*/
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
/**
* 设置阴影 郭liyuan+
*/
- (void) makeInsetShadow;
- (void) makeInsetShadowWithRadius:(float)radius Alpha:(float)alpha;
- (void) makeInsetShadowWithRadius:(float)radius Color:(UIColor *)color Directions:(NSArray *)directions;
/**
Remove all subviews.
@warning Never call this method inside your view's drawRect: method.
*/
- (void)removeAllSubviews;
/**
Returns the view's view controller (may be nil).
*/
@property (nonatomic, readonly) UIViewController *viewController;
@property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
@property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
@property (nonatomic) CGFloat right; ///< Shortcut for frame.origin.x + frame.size.width
@property (nonatomic) CGFloat bottom; ///< Shortcut for frame.origin.y + frame.size.height
@property (nonatomic) CGFloat width; ///< Shortcut for frame.size.width.
@property (nonatomic) CGFloat height; ///< Shortcut for frame.size.height.
@property (nonatomic) CGFloat centerX; ///< Shortcut for center.x
@property (nonatomic) CGFloat centerY; ///< Shortcut for center.y
@property (nonatomic) CGPoint origin; ///< Shortcut for frame.origin.
@property (nonatomic) CGSize size; ///< Shortcut for frame.size.
@property (nonatomic, readonly) CGRect screenFrame; ///< View frame on the screen, taking into account scroll views.
/**
Returns the visible alpha on screen, taking into account superview and window.
*/
@property (nonatomic, readonly) CGFloat visibleAlpha;
/**
Converts a point from the receiver's coordinate system to that of the specified view or window.
@param point A point specified in the local coordinate system (bounds) of the receiver.
@param view The view or window into whose coordinate system point is to be converted.
If view is nil, this method instead converts to window base coordinates.
@return The point converted to the coordinate system of view.
*/
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view;
/**
Converts a point from the coordinate system of a given view or window to that of the receiver.
@param point A point specified in the local coordinate system (bounds) of view.
@param view The view or window with point in its coordinate system.
If view is nil, this method instead converts from window base coordinates.
@return The point converted to the local coordinate system (bounds) of the receiver.
*/
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view;
/**
Converts a rectangle from the receiver's coordinate system to that of another view or window.
@param rect A rectangle specified in the local coordinate system (bounds) of the receiver.
@param view The view or window that is the target of the conversion operation. If view is nil, this method instead converts to window base coordinates.
@return The converted rectangle.
*/
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(UIView *)view;
/**
Converts a rectangle from the coordinate system of another view or window to that of the receiver.
@param rect A rectangle specified in the local coordinate system (bounds) of view.
@param view The view or window with rect in its coordinate system.
If view is nil, this method instead converts from window base coordinates.
@return The converted rectangle.
*/
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view;
/**
* 返回响应者链上的任意Objc
*
* @param viewControllerCls 需要返回的Obj的类名,为nil时默认返回当前控制器
*
* @return viewController Or needCls
*/
- (nonnull id)viewControllerWithNeedViewOrViewController:(nullable Class)viewControllerCls
;
/// 移除所有子视图中 tableview、scrollview 的 delegate、datasource
- (void)clearScrollViewDelegate;
- (void)removeAllGestures;
- (void)removeAllGesturesWithSubViews;
/// 在 block 内禁用动画
+ (void)disableAnimationWithBlock:(void (^)(void))block;
@end
@@ -0,0 +1,464 @@
//
// UIView+Add.m
//
//
// Created by guoyaoyuan on 13-4-3.
// Copyright (c) 2013 live Interactive. All rights reserved.
//
#import "UIView+YYAdd.h"
#import <QuartzCore/QuartzCore.h>
@implementation UIView (YYAdd)
- (UIImage *)snapshotImage {
UIImage *image = nil;
if ([self respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}else{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
return image;
}
- (NSData *)snapshotPDF {
CGRect bounds = self.bounds;
NSMutableData* data = [NSMutableData data];
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data);
CGContextRef context = CGPDFContextCreate(consumer, &bounds, NULL);
CGDataConsumerRelease(consumer);
if (!context) return nil;
CGPDFContextBeginPage(context, NULL);
CGContextTranslateCTM(context, 0, bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
[self.layer renderInContext:context];
CGPDFContextEndPage(context);
CGPDFContextClose(context);
CGContextRelease(context);
return data;
}
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius {
self.layer.shadowColor = color.CGColor;
self.layer.shadowOffset = offset;
self.layer.shadowRadius = radius;
self.layer.shadowOpacity = 1;
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
}
#define kShadowViewTag 2132
#define kValidDirections [NSArray arrayWithObjects: @"top", @"bottom", @"left", @"right",nil]
- (void) makeInsetShadow
{
NSArray *shadowDirections = [NSArray arrayWithObjects:@"top", @"bottom", @"left" , @"right" , nil];
UIColor *color = [UIColor colorWithRed:(0.0) green:(0.0) blue:(0.0) alpha:0.5];
UIView *shadowView = [self createShadowViewWithRadius:3 Color:color Directions:shadowDirections];
shadowView.tag = kShadowViewTag;
[self addSubview:shadowView];
}
- (void) makeInsetShadowWithRadius:(float)radius Alpha:(float)alpha
{
NSArray *shadowDirections = [NSArray arrayWithObjects:@"top", @"bottom", @"left" , @"right" , nil];
UIColor *color = [UIColor colorWithRed:(0.0) green:(0.0) blue:(0.0) alpha:alpha];
UIView *shadowView = [self createShadowViewWithRadius:radius Color:color Directions:shadowDirections];
shadowView.tag = kShadowViewTag;
[self addSubview:shadowView];
}
- (void) makeInsetShadowWithRadius:(float)radius Color:(UIColor *)color Directions:(NSArray *)directions
{
UIView *shadowView = [self createShadowViewWithRadius:radius Color:color Directions:directions];
shadowView.tag = kShadowViewTag;
[self addSubview:shadowView];
}
- (UIView *) createShadowViewWithRadius:(float)radius Color:(UIColor *)color Directions:(NSArray *)directions
{
UIView *shadowView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
shadowView.backgroundColor = [UIColor clearColor];
// Ignore duplicate direction
NSMutableDictionary *directionDict = [[NSMutableDictionary alloc] init];
for (NSString *direction in directions) [directionDict setObject:@"1" forKey:direction];
// for (NSString *direction in directionDict) {
// // Ignore invalid direction
// if ([kValidDirections containsObject:direction])
// {
// CAGradientLayer *shadow = [CAGradientLayer layer];
// shadow.locations = @[@(0.0),@(0.5)];
//
// if ([direction isEqualToString:@"top"]) {
// [shadow setStartPoint:CGPointMake(0.5, 0.0)];
// [shadow setEndPoint:CGPointMake(0.5, 1.0)];
// shadow.frame = CGRectMake(-radius, -radius, self.bounds.size.width + radius*2, radius);
// shadow.colors = [NSArray arrayWithObjects:(id)[self.backgroundColor CGColor], (id)[color CGColor], nil];
// }
// else if ([direction isEqualToString:@"bottom"])
// {
// [shadow setStartPoint:CGPointMake(0.5, 1.0)];
// [shadow setEndPoint:CGPointMake(0.5, 0.0)];
// shadow.frame = CGRectMake(-radius, self.bounds.size.height, self.bounds.size.width + radius*2, radius);
// shadow.colors = [NSArray arrayWithObjects:(id)[self.backgroundColor CGColor] ,(id)[color CGColor], nil];
// } else if ([direction isEqualToString:@"left"])
// {
// shadow.frame = CGRectMake(-radius, -radius, radius, self.bounds.size.height + radius*2);
// [shadow setStartPoint:CGPointMake(0.0, 0.5)];
// [shadow setEndPoint:CGPointMake(1.0, 0.5)];
// shadow.colors = [NSArray arrayWithObjects:(id)[self.backgroundColor CGColor],(id)[color CGColor], nil];
//
// } else if ([direction isEqualToString:@"right"])
// {
// shadow.frame = CGRectMake(self.bounds.size.width, -radius, radius, self.bounds.size.height + radius*2);
// [shadow setStartPoint:CGPointMake(1.0, 0.5)];
// [shadow setEndPoint:CGPointMake(0.0, 0.5)];
// shadow.colors = [NSArray arrayWithObjects:(id)[self.backgroundColor CGColor],(id)[color CGColor], nil];
// }
// // 后边一个颜色要和所加视图背景颜色一样
//
// [shadowView.layer insertSublayer:shadow atIndex:0];
// }
// }
for (NSString *direction in directionDict) {
// Ignore invalid direction
if ([kValidDirections containsObject:direction])
{
CALayer *shadow = [CAGradientLayer layer];
shadow.backgroundColor = color.CGColor;
if ([direction isEqualToString:@"top"]) {
shadow.frame = CGRectMake(0, 0, self.bounds.size.width, radius);
}
else if ([direction isEqualToString:@"bottom"])
{
shadow.frame = CGRectMake(0, self.bounds.size.height, self.bounds.size.width, radius);
} else if ([direction isEqualToString:@"left"])
{
shadow.frame = CGRectMake(0, 0, radius, self.bounds.size.height );
} else if ([direction isEqualToString:@"right"])
{
shadow.frame = CGRectMake(self.bounds.size.width, 0, radius, self.bounds.size.height);
}
[shadowView.layer insertSublayer:shadow atIndex:0];
}
}
return shadowView;
}
- (void)removeAllSubviews {
while (self.subviews.count) {
[self.subviews.lastObject removeFromSuperview];
}
}
- (UIViewController *)viewController {
for (UIView *view = self; view; view = view.superview) {
UIResponder *nextResponder = [view nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)nextResponder;
}
}
return nil;
}
- (nonnull id)viewControllerWithNeedViewOrViewController:(nullable Class)viewControllerCls
{
UIViewController *result = nil;
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
UIView *frontView = self;
id nextResponse = [frontView nextResponder];
Class cls = viewControllerCls?viewControllerCls:UIViewController.class;
while (nextResponse) {
if ([nextResponse isKindOfClass:cls]) {
result = nextResponse;
break;
}
nextResponse = [nextResponse nextResponder];
}
if(!result) result = window.rootViewController;
return result;
}
- (CGFloat)left {
return self.frame.origin.x;
}
- (void)setLeft:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)top {
return self.frame.origin.y;
}
- (void)setTop:(CGFloat)y {
CGRect frame = self.frame;
frame.origin.y = y;
self.frame = frame;
}
- (CGFloat)right {
return self.frame.origin.x + self.frame.size.width;
}
- (void)setRight:(CGFloat)right {
CGRect frame = self.frame;
frame.origin.x = right - frame.size.width;
self.frame = frame;
}
- (CGFloat)bottom {
return self.frame.origin.y + self.frame.size.height;
}
- (void)setBottom:(CGFloat)bottom {
CGRect frame = self.frame;
frame.origin.y = bottom - frame.size.height;
self.frame = frame;
}
- (CGFloat)width {
return self.frame.size.width;
}
- (void)setWidth:(CGFloat)width {
CGRect frame = self.frame;
frame.size.width = width;
self.frame = frame;
}
- (CGFloat)height {
return self.frame.size.height;
}
- (void)setHeight:(CGFloat)height {
CGRect frame = self.frame;
frame.size.height = height;
self.frame = frame;
}
- (CGFloat)centerX {
return self.center.x;
}
- (void)setCenterX:(CGFloat)centerX {
self.center = CGPointMake(centerX, self.center.y);
}
- (CGFloat)centerY {
return self.center.y;
}
- (void)setCenterY:(CGFloat)centerY {
self.center = CGPointMake(self.center.x, centerY);
}
- (CGPoint)origin {
return self.frame.origin;
}
- (void)setOrigin:(CGPoint)origin {
CGRect frame = self.frame;
frame.origin = origin;
self.frame = frame;
}
- (CGSize)size {
return self.frame.size;
}
- (void)setSize:(CGSize)size {
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGRect)screenFrame {
CGPoint origin = CGPointZero;
for (UIView *view = self; view; view = view.superview) {
origin.x += view.left;
origin.y += view.top;
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView *scrollView = (UIScrollView *)view;
origin.x -= scrollView.contentOffset.x;
origin.y -= scrollView.contentOffset.y;
}
}
return CGRectMake(origin.x, origin.y, self.width, self.height);
}
- (CGFloat)visibleAlpha {
if ([self isKindOfClass:[UIWindow class]]) {
if (self.hidden) return 0;
return self.alpha;
}
if (!self.window) return 0;
CGFloat alpha = 1;
UIView *v = self;
while (v) {
if (v.hidden) {
alpha = 0;
break;
}
alpha *= v.alpha;
v = v.superview;
}
return alpha;
}
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view {
if (!view) {
if ([self isKindOfClass:[UIWindow class]]) {
return [((UIWindow *)self) convertPoint:point toWindow:nil];
} else {
return [self convertPoint:point toView:nil];
}
}
UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
if ((!from || !to) || (from == to)) return [self convertPoint:point toView:view];
point = [self convertPoint:point toView:from];
point = [to convertPoint:point fromWindow:from];
point = [view convertPoint:point fromView:to];
return point;
}
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view {
if (!view) {
if ([self isKindOfClass:[UIWindow class]]) {
return [((UIWindow *)self) convertPoint:point fromWindow:nil];
} else {
return [self convertPoint:point fromView:nil];
}
}
UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
if ((!from || !to) || (from == to)) return [self convertPoint:point fromView:view];
point = [from convertPoint:point fromView:view];
point = [to convertPoint:point fromWindow:from];
point = [self convertPoint:point fromView:to];
return point;
}
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(UIView *)view {
if (!view) {
if ([self isKindOfClass:[UIWindow class]]) {
return [((UIWindow *)self) convertRect:rect toWindow:nil];
} else {
return [self convertRect:rect toView:nil];
}
}
UIWindow *from = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
UIWindow *to = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
if (!from || !to) return [self convertRect:rect toView:view];
if (from == to) return [self convertRect:rect toView:view];
rect = [self convertRect:rect toView:from];
rect = [to convertRect:rect fromWindow:from];
rect = [view convertRect:rect fromView:to];
return rect;
}
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view {
if (!view) {
if ([self isKindOfClass:[UIWindow class]]) {
return [((UIWindow *)self) convertRect:rect fromWindow:nil];
} else {
return [self convertRect:rect fromView:nil];
}
}
UIWindow *from = [view isKindOfClass:[UIWindow class]] ? (id)view : view.window;
UIWindow *to = [self isKindOfClass:[UIWindow class]] ? (id)self : self.window;
if ((!from || !to) || (from == to)) return [self convertRect:rect fromView:view];
rect = [from convertRect:rect fromView:view];
rect = [to convertRect:rect fromWindow:from];
rect = [self convertRect:rect fromView:to];
return rect;
}
- (void)clearScrollViewDelegate {
if ([self isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)self).delegate = nil;
if ([self isKindOfClass:[UITableView class]]) {
((UITableView *)self).delegate = nil;
}
}
for (UIView *sub in self.subviews) {
[sub clearScrollViewDelegate];
}
}
- (void)removeAllGestures {
NSArray *gs = [self.gestureRecognizers copy];
for (UIGestureRecognizer *g in gs) {
[self removeGestureRecognizer:g];
}
}
- (void)removeAllGesturesWithSubViews {
[self removeAllGestures];
for (UIView *v in self.subviews) {
[v removeAllGesturesWithSubViews];
}
[UIView animateWithDuration:0 animations:^{
}];
}
+ (void)disableAnimationWithBlock:(void (^)(void))block {
if (!block) return;
BOOL aniEnabled = [CATransaction disableActions];
[CATransaction setDisableActions:YES];
block();
[CATransaction setDisableActions:aniEnabled];
}
@end
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+16
View File
@@ -0,0 +1,16 @@
//
// main.m
// LFLiveKitDemo
//
// Created by admin on 16/6/8.
// Copyright © 2016年 admin. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
+9
View File
@@ -0,0 +1,9 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios,'8.0'
target "LFLiveKitDemo" do
pod 'LFLiveKit', '~> 1.7.1'
pod 'YYDispatchQueuePool'
end
+2 -2
View File
@@ -4,7 +4,7 @@ platform :ios,'8.0'
target "LFLiveKit" do
pod 'CocoaAsyncSocket', '~> 7.4.1'
pod 'librtmp-iOS', '~> 1.1.0'
pod 'pili-librtmp', '~> 1.0.2'
pod 'LMGPUImage', '~> 0.1.9'
pod 'YYDispatchQueuePool'
end
+5 -5
View File
@@ -1,5 +1,5 @@
[![Build Status](https://travis-ci.org/chenliming777/LFLiveKit.svg)](https://travis-ci.org/chenliming777/LFLiveKit)&nbsp;
[![Build Status](https://travis-ci.org/LaiFengiOS/LFLiveKit.svg)](https://travis-ci.org/LaiFengiOS/LFLiveKit)&nbsp;
[![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/chenliming777/LFLiveKit/master/LICENSE)&nbsp;
[![CocoaPods](http://img.shields.io/cocoapods/v/LFLiveKit.svg?style=flat)](http://cocoapods.org/?q=LFLiveKit)&nbsp;
[![Support](https://img.shields.io/badge/support-ios8%2B-orange.svg)](https://www.apple.com/nl/ios/)&nbsp;
@@ -8,7 +8,7 @@
LFLiveKit
LFLiveKit IOS mobile phone push codeDefault format support RTMPAt the same time, the structure is very easy to extend.
LFLiveKit IOS mobile phone push codeDefault format support RTMP and FLVAt the same time, the structure is very easy to extend.
Podfile
To integrate LFLiveKit into your Xcode project using CocoaPods, specify it in your Podfile:
@@ -43,13 +43,13 @@ Architecture
capture: LFAudioCapture and LFVideoCapture
encode: LFHardwareAudioEncoder and LFHardwareVideoEncoder
publish: LFStreamRtmpSocket
publish: LFStreamRtmpSocket LFStreamTcpSocket
Usage
- (LFLiveSession*)session{
if(!_session){
_session = [[LFLiveSession alloc] initWithAudioConfiguration: [LFLiveAudioConfiguration defaultConfiguration] videoConfiguration: [LFLiveVideoConfiguration defaultConfiguration]];
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration] liveType:LFLiveRTMP];
_session.running = YES;
_session.preView = self;
}
@@ -73,7 +73,7 @@ Usage
videoConfiguration.orientation = UIInterfaceOrientationLandscapeLeft;
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
_session.running = YES;
_session.preView = self;
}