Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae5f68661e | |||
| e30467dc13 | |||
| a217868694 | |||
| 3053a16cd3 | |||
| d2d7140312 | |||
| e93549619e | |||
| 0196b1be79 | |||
| 23ab30e668 | |||
| 42bd5c1f6b | |||
| 41393ffed8 | |||
| ba48a45c0a | |||
| af09e79e74 | |||
| e4327de704 | |||
| 9760129763 | |||
| dc7f8d1d10 | |||
| 8f8bedb93d | |||
| 9428dc2c7f | |||
| e6c0d148ab | |||
| 0ca5c18c19 | |||
| cb98f0e70d | |||
| 06f1e40fba | |||
| dfbc4a51ff | |||
| f045bb14e4 | |||
| ebafc22eca | |||
| 6e3e92a6b9 | |||
| 26a47ffccc | |||
| e57d3e3806 | |||
| b73bfee6ac | |||
| 09398d0cb3 | |||
| f69b586d70 | |||
| edcb2efaa0 | |||
| 3842ff80bf | |||
| d3d5f6cb24 | |||
| 37bfd377d6 |
+2
-2
@@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7
|
||||
xcode_workspace: LFLiveKit.xcworkspace
|
||||
xcode_project: LFLiveKit.xcodeproj
|
||||
xcode_scheme: LFLiveKit
|
||||
|
||||
script:
|
||||
- xctool -workspace LFLiveKit.xcworkspace -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
- xctool -project LFLiveKit.xcodeproj -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
+3
-2
@@ -2,7 +2,7 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "LFLiveKit"
|
||||
s.version = "1.9.6"
|
||||
s.version = "2.1"
|
||||
s.summary = "LaiFeng ios Live. LFLiveKit."
|
||||
s.homepage = "https://github.com/chenliming777"
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
@@ -11,7 +11,8 @@ Pod::Spec.new do |s|
|
||||
s.ios.deployment_target = "7.0"
|
||||
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit.git", :tag => "#{s.version}" }
|
||||
s.source_files = "LFLiveKit/**/*.{h,m,mm,cpp,c}"
|
||||
s.public_header_files = "LFLiveKit/**/*.h"
|
||||
#s.public_header_files = "LFLiveKit/**/*.h"
|
||||
s.public_header_files = ['LFLiveKit/*.h', 'LFLiveKit/objects/*.h', 'LFLiveKit/configuration/*.h']
|
||||
|
||||
s.frameworks = "VideoToolbox", "AudioToolbox","AVFoundation","Foundation","UIKit"
|
||||
s.libraries = "c++", "z"
|
||||
|
||||
@@ -408,6 +408,14 @@
|
||||
843725011D4F260A002B398B /* rtmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 843723971D4F260A002B398B /* rtmp.c */; };
|
||||
843725021D4F260A002B398B /* rtmp.h in Headers */ = {isa = PBXBuildFile; fileRef = 843723981D4F260A002B398B /* rtmp.h */; };
|
||||
843725031D4F260A002B398B /* rtmp_sys.h in Headers */ = {isa = PBXBuildFile; fileRef = 843723991D4F260A002B398B /* rtmp_sys.h */; };
|
||||
B221C24F1D59D41A009615C3 /* LFAVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = B221C2471D59D41A009615C3 /* LFAVEncoder.h */; };
|
||||
B221C2501D59D41A009615C3 /* LFAVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = B221C2481D59D41A009615C3 /* LFAVEncoder.mm */; };
|
||||
B221C2511D59D41A009615C3 /* LFMP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = B221C2491D59D41A009615C3 /* LFMP4Atom.h */; };
|
||||
B221C2521D59D41A009615C3 /* LFMP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = B221C24A1D59D41A009615C3 /* LFMP4Atom.m */; };
|
||||
B221C2531D59D41A009615C3 /* LFNALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B221C24B1D59D41A009615C3 /* LFNALUnit.cpp */; };
|
||||
B221C2541D59D41A009615C3 /* LFNALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = B221C24C1D59D41A009615C3 /* LFNALUnit.h */; };
|
||||
B221C2551D59D41A009615C3 /* LFVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = B221C24D1D59D41A009615C3 /* LFVideoEncoder.h */; };
|
||||
B221C2561D59D41A009615C3 /* LFVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = B221C24E1D59D41A009615C3 /* LFVideoEncoder.m */; };
|
||||
B289F1DB1D3DE77F00D9C7A5 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = B289F1D41D3DE77F00D9C7A5 /* LFStreamingBuffer.h */; };
|
||||
B289F1DC1D3DE77F00D9C7A5 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = B289F1D51D3DE77F00D9C7A5 /* LFStreamingBuffer.m */; };
|
||||
B289F1DD1D3DE77F00D9C7A5 /* LFStreamRtmpSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = B289F1D61D3DE77F00D9C7A5 /* LFStreamRtmpSocket.h */; };
|
||||
@@ -415,15 +423,7 @@
|
||||
B289F1DF1D3DE77F00D9C7A5 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = B289F1D81D3DE77F00D9C7A5 /* LFStreamSocket.h */; };
|
||||
B289F1E01D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = B289F1D91D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.h */; };
|
||||
B289F1E11D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = B289F1DA1D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.m */; };
|
||||
B2CD146D1D45F18B008082E8 /* AVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CD14621D45F18B008082E8 /* AVEncoder.h */; };
|
||||
B2CD146E1D45F18B008082E8 /* AVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2CD14631D45F18B008082E8 /* AVEncoder.mm */; };
|
||||
B2CD146F1D45F18B008082E8 /* LICENSE.markdown in Sources */ = {isa = PBXBuildFile; fileRef = B2CD14641D45F18B008082E8 /* LICENSE.markdown */; };
|
||||
B2CD14701D45F18B008082E8 /* MP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CD14651D45F18B008082E8 /* MP4Atom.h */; };
|
||||
B2CD14711D45F18B008082E8 /* MP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = B2CD14661D45F18B008082E8 /* MP4Atom.m */; };
|
||||
B2CD14721D45F18B008082E8 /* NALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2CD14671D45F18B008082E8 /* NALUnit.cpp */; };
|
||||
B2CD14731D45F18B008082E8 /* NALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CD14681D45F18B008082E8 /* NALUnit.h */; };
|
||||
B2CD14741D45F18B008082E8 /* VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CD14691D45F18B008082E8 /* VideoEncoder.h */; };
|
||||
B2CD14751D45F18B008082E8 /* VideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = B2CD146A1D45F18B008082E8 /* VideoEncoder.m */; };
|
||||
B2CD14761D45F18B008082E8 /* LFH264VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = B2CD146B1D45F18B008082E8 /* LFH264VideoEncoder.h */; };
|
||||
B2CD14771D45F18B008082E8 /* LFH264VideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2CD146C1D45F18B008082E8 /* LFH264VideoEncoder.mm */; };
|
||||
/* End PBXBuildFile section */
|
||||
@@ -844,6 +844,14 @@
|
||||
843723971D4F260A002B398B /* rtmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtmp.c; sourceTree = "<group>"; };
|
||||
843723981D4F260A002B398B /* rtmp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtmp.h; sourceTree = "<group>"; };
|
||||
843723991D4F260A002B398B /* rtmp_sys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtmp_sys.h; sourceTree = "<group>"; };
|
||||
B221C2471D59D41A009615C3 /* LFAVEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAVEncoder.h; sourceTree = "<group>"; };
|
||||
B221C2481D59D41A009615C3 /* LFAVEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFAVEncoder.mm; sourceTree = "<group>"; };
|
||||
B221C2491D59D41A009615C3 /* LFMP4Atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFMP4Atom.h; sourceTree = "<group>"; };
|
||||
B221C24A1D59D41A009615C3 /* LFMP4Atom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFMP4Atom.m; sourceTree = "<group>"; };
|
||||
B221C24B1D59D41A009615C3 /* LFNALUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LFNALUnit.cpp; sourceTree = "<group>"; };
|
||||
B221C24C1D59D41A009615C3 /* LFNALUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFNALUnit.h; sourceTree = "<group>"; };
|
||||
B221C24D1D59D41A009615C3 /* LFVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoder.h; sourceTree = "<group>"; };
|
||||
B221C24E1D59D41A009615C3 /* LFVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoEncoder.m; sourceTree = "<group>"; };
|
||||
B289F1D41D3DE77F00D9C7A5 /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LFStreamingBuffer.h; path = LFLiveKit/publish/LFStreamingBuffer.h; sourceTree = SOURCE_ROOT; };
|
||||
B289F1D51D3DE77F00D9C7A5 /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LFStreamingBuffer.m; path = LFLiveKit/publish/LFStreamingBuffer.m; sourceTree = SOURCE_ROOT; };
|
||||
B289F1D61D3DE77F00D9C7A5 /* LFStreamRtmpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LFStreamRtmpSocket.h; path = LFLiveKit/publish/LFStreamRtmpSocket.h; sourceTree = SOURCE_ROOT; };
|
||||
@@ -851,15 +859,7 @@
|
||||
B289F1D81D3DE77F00D9C7A5 /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LFStreamSocket.h; path = LFLiveKit/publish/LFStreamSocket.h; sourceTree = SOURCE_ROOT; };
|
||||
B289F1D91D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSMutableArray+LFAdd.h"; path = "LFLiveKit/publish/NSMutableArray+LFAdd.h"; sourceTree = SOURCE_ROOT; };
|
||||
B289F1DA1D3DE77F00D9C7A5 /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSMutableArray+LFAdd.m"; path = "LFLiveKit/publish/NSMutableArray+LFAdd.m"; sourceTree = SOURCE_ROOT; };
|
||||
B2CD14621D45F18B008082E8 /* AVEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVEncoder.h; sourceTree = "<group>"; };
|
||||
B2CD14631D45F18B008082E8 /* AVEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AVEncoder.mm; sourceTree = "<group>"; };
|
||||
B2CD14641D45F18B008082E8 /* LICENSE.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.markdown; sourceTree = "<group>"; };
|
||||
B2CD14651D45F18B008082E8 /* MP4Atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MP4Atom.h; sourceTree = "<group>"; };
|
||||
B2CD14661D45F18B008082E8 /* MP4Atom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MP4Atom.m; sourceTree = "<group>"; };
|
||||
B2CD14671D45F18B008082E8 /* NALUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NALUnit.cpp; sourceTree = "<group>"; };
|
||||
B2CD14681D45F18B008082E8 /* NALUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NALUnit.h; sourceTree = "<group>"; };
|
||||
B2CD14691D45F18B008082E8 /* VideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoEncoder.h; sourceTree = "<group>"; };
|
||||
B2CD146A1D45F18B008082E8 /* VideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoEncoder.m; sourceTree = "<group>"; };
|
||||
B2CD146B1D45F18B008082E8 /* LFH264VideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFH264VideoEncoder.h; sourceTree = "<group>"; };
|
||||
B2CD146C1D45F18B008082E8 /* LFH264VideoEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFH264VideoEncoder.mm; sourceTree = "<group>"; };
|
||||
D0BB7E7CE5403C4911E026B9 /* 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>"; };
|
||||
@@ -1444,15 +1444,15 @@
|
||||
B2CD14611D45F18B008082E8 /* H264 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B2CD14621D45F18B008082E8 /* AVEncoder.h */,
|
||||
B2CD14631D45F18B008082E8 /* AVEncoder.mm */,
|
||||
B221C2471D59D41A009615C3 /* LFAVEncoder.h */,
|
||||
B221C2481D59D41A009615C3 /* LFAVEncoder.mm */,
|
||||
B221C2491D59D41A009615C3 /* LFMP4Atom.h */,
|
||||
B221C24A1D59D41A009615C3 /* LFMP4Atom.m */,
|
||||
B221C24B1D59D41A009615C3 /* LFNALUnit.cpp */,
|
||||
B221C24C1D59D41A009615C3 /* LFNALUnit.h */,
|
||||
B221C24D1D59D41A009615C3 /* LFVideoEncoder.h */,
|
||||
B221C24E1D59D41A009615C3 /* LFVideoEncoder.m */,
|
||||
B2CD14641D45F18B008082E8 /* LICENSE.markdown */,
|
||||
B2CD14651D45F18B008082E8 /* MP4Atom.h */,
|
||||
B2CD14661D45F18B008082E8 /* MP4Atom.m */,
|
||||
B2CD14671D45F18B008082E8 /* NALUnit.cpp */,
|
||||
B2CD14681D45F18B008082E8 /* NALUnit.h */,
|
||||
B2CD14691D45F18B008082E8 /* VideoEncoder.h */,
|
||||
B2CD146A1D45F18B008082E8 /* VideoEncoder.m */,
|
||||
);
|
||||
path = H264;
|
||||
sourceTree = "<group>";
|
||||
@@ -1465,6 +1465,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84001FE51D0016380026C63F /* LFAudioFrame.h in Headers */,
|
||||
B221C24F1D59D41A009615C3 /* LFAVEncoder.h in Headers */,
|
||||
843724711D4F260A002B398B /* GPUImagePerlinNoiseFilter.h in Headers */,
|
||||
843724F61D4F260A002B398B /* bytes.h in Headers */,
|
||||
84001FED1D0016380026C63F /* LFVideoFrame.h in Headers */,
|
||||
@@ -1500,7 +1501,6 @@
|
||||
843724991D4F260A002B398B /* GPUImageSharpenFilter.h in Headers */,
|
||||
84001FDD1D0016380026C63F /* LFLiveVideoConfiguration.h in Headers */,
|
||||
843724FB1D4F260A002B398B /* handshake.h in Headers */,
|
||||
B2CD14701D45F18B008082E8 /* MP4Atom.h in Headers */,
|
||||
843723F31D4F260A002B398B /* GPUImageFalseColorFilter.h in Headers */,
|
||||
843723B71D4F260A002B398B /* GPUImageCannyEdgeDetectionFilter.h in Headers */,
|
||||
843724151D4F260A002B398B /* GPUImageHazeFilter.h in Headers */,
|
||||
@@ -1549,6 +1549,7 @@
|
||||
843724251D4F260A002B398B /* GPUImageHSBFilter.h in Headers */,
|
||||
843724891D4F260A002B398B /* GPUImageRGBDilationFilter.h in Headers */,
|
||||
843724C31D4F260A002B398B /* GPUImageThresholdedNonMaximumSuppressionFilter.h in Headers */,
|
||||
B221C2511D59D41A009615C3 /* LFMP4Atom.h in Headers */,
|
||||
843723A71D4F260A002B398B /* GPUImageAmatorkaFilter.h in Headers */,
|
||||
8437245F1D4F260A002B398B /* GPUImageMultiplyBlendFilter.h in Headers */,
|
||||
84001FE91D0016380026C63F /* LFLiveDebug.h in Headers */,
|
||||
@@ -1562,6 +1563,7 @@
|
||||
843723F91D4F260A002B398B /* GPUImageFilterGroup.h in Headers */,
|
||||
843723C31D4F260A002B398B /* GPUImageColorBurnBlendFilter.h in Headers */,
|
||||
8437243B1D4F260A002B398B /* GPUImageLinearBurnBlendFilter.h in Headers */,
|
||||
B221C2551D59D41A009615C3 /* LFVideoEncoder.h in Headers */,
|
||||
843724011D4F260A002B398B /* GPUImageFramebufferCache.h in Headers */,
|
||||
8437247B1D4F260A002B398B /* GPUImagePolarPixellateFilter.h in Headers */,
|
||||
843724AB1D4F260A002B398B /* GPUImageSolarizeFilter.h in Headers */,
|
||||
@@ -1577,6 +1579,7 @@
|
||||
843723EB1D4F260A002B398B /* GPUImageEmbossFilter.h in Headers */,
|
||||
843724EC1D4F260A002B398B /* GPUImageMovieWriter.h in Headers */,
|
||||
843724451D4F260A002B398B /* GPUImageLuminanceRangeFilter.h in Headers */,
|
||||
B221C2541D59D41A009615C3 /* LFNALUnit.h in Headers */,
|
||||
843723D31D4F260A002B398B /* GPUImageColourFASTSamplingOperation.h in Headers */,
|
||||
8437243F1D4F260A002B398B /* GPUImageLocalBinaryPatternFilter.h in Headers */,
|
||||
843725021D4F260A002B398B /* rtmp.h in Headers */,
|
||||
@@ -1632,12 +1635,10 @@
|
||||
84001FDA1D0016380026C63F /* LFVideoEncoding.h in Headers */,
|
||||
843724BF1D4F260A002B398B /* GPUImageThreeInputFilter.h in Headers */,
|
||||
843724F71D4F260A002B398B /* dh.h in Headers */,
|
||||
B2CD14741D45F18B008082E8 /* VideoEncoder.h in Headers */,
|
||||
843725031D4F260A002B398B /* rtmp_sys.h in Headers */,
|
||||
843724691D4F260A002B398B /* GPUImageOpeningFilter.h in Headers */,
|
||||
843723C11D4F260A002B398B /* GPUImageColorBlendFilter.h in Headers */,
|
||||
8437249F1D4F260A002B398B /* GPUImageSketchFilter.h in Headers */,
|
||||
B2CD14731D45F18B008082E8 /* NALUnit.h in Headers */,
|
||||
84001FD81D0016380026C63F /* LFHardwareVideoEncoder.h in Headers */,
|
||||
843724A91D4F260A002B398B /* GPUImageSoftLightBlendFilter.h in Headers */,
|
||||
843723A91D4F260A002B398B /* GPUImageAverageColor.h in Headers */,
|
||||
@@ -1657,7 +1658,6 @@
|
||||
843723A11D4F260A002B398B /* GPUImageAdaptiveThresholdFilter.h in Headers */,
|
||||
843723CF1D4F260A002B398B /* GPUImageColorPackingFilter.h in Headers */,
|
||||
843723B91D4F260A002B398B /* GPUImageCGAColorspaceFilter.h in Headers */,
|
||||
B2CD146D1D45F18B008082E8 /* AVEncoder.h in Headers */,
|
||||
843724051D4F260A002B398B /* GPUImageGaussianBlurFilter.h in Headers */,
|
||||
843724B31D4F260A002B398B /* GPUImageStillCamera.h in Headers */,
|
||||
843724D51D4F260A002B398B /* GPUImageTwoPassTextureSamplingFilter.h in Headers */,
|
||||
@@ -1783,8 +1783,8 @@
|
||||
843724E41D4F260A002B398B /* GPUImageWhiteBalanceFilter.m in Sources */,
|
||||
843724101D4F260A002B398B /* GPUImageHalftoneFilter.m in Sources */,
|
||||
843724301D4F260A002B398B /* GPUImageKuwaharaFilter.m in Sources */,
|
||||
B2CD14711D45F18B008082E8 /* MP4Atom.m in Sources */,
|
||||
843724201D4F260A002B398B /* GPUImageHistogramFilter.m in Sources */,
|
||||
B221C2531D59D41A009615C3 /* LFNALUnit.cpp in Sources */,
|
||||
8437246E1D4F260A002B398B /* GPUImageOverlayBlendFilter.m in Sources */,
|
||||
843723A81D4F260A002B398B /* GPUImageAmatorkaFilter.m in Sources */,
|
||||
84001FE61D0016380026C63F /* LFAudioFrame.m in Sources */,
|
||||
@@ -1798,7 +1798,6 @@
|
||||
84001FD41D0016380026C63F /* LFVideoCapture.m in Sources */,
|
||||
843723B81D4F260A002B398B /* GPUImageCannyEdgeDetectionFilter.m in Sources */,
|
||||
84001FE81D0016380026C63F /* LFFrame.m in Sources */,
|
||||
B2CD14721D45F18B008082E8 /* NALUnit.cpp in Sources */,
|
||||
843724CE1D4F260A002B398B /* GPUImageTransformFilter.m in Sources */,
|
||||
843723E81D4F260A002B398B /* GPUImageDissolveBlendFilter.m in Sources */,
|
||||
843723D81D4F260A002B398B /* GPUImageCropFilter.m in Sources */,
|
||||
@@ -1850,10 +1849,10 @@
|
||||
843724B81D4F260A002B398B /* GPUImageSubtractBlendFilter.m in Sources */,
|
||||
843724741D4F260A002B398B /* GPUImagePinchDistortionFilter.m in Sources */,
|
||||
843724D61D4F260A002B398B /* GPUImageTwoPassTextureSamplingFilter.m in Sources */,
|
||||
B2CD14751D45F18B008082E8 /* VideoEncoder.m in Sources */,
|
||||
843723DA1D4F260A002B398B /* GPUImageCrosshairGenerator.m in Sources */,
|
||||
843724A01D4F260A002B398B /* GPUImageSketchFilter.m in Sources */,
|
||||
843723A01D4F260A002B398B /* GPUImage3x3TextureSamplingFilter.m in Sources */,
|
||||
B221C2561D59D41A009615C3 /* LFVideoEncoder.m in Sources */,
|
||||
8437249A1D4F260A002B398B /* GPUImageSharpenFilter.m in Sources */,
|
||||
843723C41D4F260A002B398B /* GPUImageColorBurnBlendFilter.m in Sources */,
|
||||
843724121D4F260A002B398B /* GPUImageHardLightBlendFilter.m in Sources */,
|
||||
@@ -1873,6 +1872,7 @@
|
||||
8437245C1D4F260A002B398B /* GPUImageMovie.m in Sources */,
|
||||
84001FD91D0016380026C63F /* LFHardwareVideoEncoder.m in Sources */,
|
||||
843724A61D4F260A002B398B /* GPUImageSobelEdgeDetectionFilter.m in Sources */,
|
||||
B221C2501D59D41A009615C3 /* LFAVEncoder.mm in Sources */,
|
||||
843724281D4F260A002B398B /* GPUImageHueBlendFilter.m in Sources */,
|
||||
843723B61D4F260A002B398B /* GPUImageBulgeDistortionFilter.m in Sources */,
|
||||
8437243A1D4F260A002B398B /* GPUImageLightenBlendFilter.m in Sources */,
|
||||
@@ -1885,6 +1885,7 @@
|
||||
843724961D4F260A002B398B /* GPUImageScreenBlendFilter.m in Sources */,
|
||||
843724541D4F260A002B398B /* GPUImageMonochromeFilter.m in Sources */,
|
||||
843723B41D4F260A002B398B /* GPUImageBuffer.m in Sources */,
|
||||
B221C2521D59D41A009615C3 /* LFMP4Atom.m in Sources */,
|
||||
8437239B1D4F260A002B398B /* GLProgram.m in Sources */,
|
||||
843724E81D4F260A002B398B /* GPUImageZoomBlurFilter.m in Sources */,
|
||||
84001FEC1D0016380026C63F /* LFLiveStreamInfo.m in Sources */,
|
||||
@@ -1969,7 +1970,6 @@
|
||||
84001FE01D0016380026C63F /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
843723FC1D4F260A002B398B /* GPUImageFilterPipeline.m in Sources */,
|
||||
843724441D4F260A002B398B /* GPUImageLowPassFilter.m in Sources */,
|
||||
B2CD146E1D45F18B008082E8 /* AVEncoder.mm in Sources */,
|
||||
843725011D4F260A002B398B /* rtmp.c in Sources */,
|
||||
843724221D4F260A002B398B /* GPUImageHistogramGenerator.m in Sources */,
|
||||
843724621D4F260A002B398B /* GPUImageNobleCornerDetectionFilter.m in Sources */,
|
||||
@@ -2095,6 +2095,7 @@
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
@@ -2105,14 +2106,21 @@
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public\"",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public/LMGPUImage\"",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public/pili-librtmp\"",
|
||||
"-fembed-bitcode",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-framework",
|
||||
"\"AVFoundation\"",
|
||||
"-framework",
|
||||
"\"CoreMedia\"",
|
||||
"-framework",
|
||||
"\"OpenGLES\"",
|
||||
"-framework",
|
||||
"\"QuartzCore\"",
|
||||
"-framework",
|
||||
"\"UIKit\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
@@ -2129,6 +2137,7 @@
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = YES;
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
@@ -2139,14 +2148,21 @@
|
||||
);
|
||||
OTHER_CFLAGS = (
|
||||
"$(inherited)",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public\"",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public/LMGPUImage\"",
|
||||
"-isystem",
|
||||
"\"${PODS_ROOT}/Headers/Public/pili-librtmp\"",
|
||||
"-fembed-bitcode",
|
||||
);
|
||||
OTHER_LDFLAGS = (
|
||||
"-ObjC",
|
||||
"-framework",
|
||||
"\"AVFoundation\"",
|
||||
"-framework",
|
||||
"\"CoreMedia\"",
|
||||
"-framework",
|
||||
"\"OpenGLES\"",
|
||||
"-framework",
|
||||
"\"QuartzCore\"",
|
||||
"-framework",
|
||||
"\"UIKit\"",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
||||
Generated
BIN
Binary file not shown.
Generated
BIN
Binary file not shown.
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.9.6</string>
|
||||
<string>2.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -15,6 +15,26 @@
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger,LFLiveCaptureType) {
|
||||
LFLiveCaptureAudio, //< capture only audio
|
||||
LFLiveCaptureVideo, //< capture onlt video
|
||||
LFLiveInputAudio, //< only audio (External input audio)
|
||||
LFLiveInputVideo, //< only video (External input video)
|
||||
};
|
||||
|
||||
|
||||
///< 用来控制采集类型(可以内部采集也可以外部传入等各种组合,支持单音频与单视频,外部输入适用于录屏,无人机等外设介入)
|
||||
typedef NS_ENUM(NSInteger,LFLiveCaptureTypeMask) {
|
||||
LFLiveCaptureMaskAudio = (1 << LFLiveCaptureAudio), ///< only inner capture audio (no video)
|
||||
LFLiveCaptureMaskVideo = (1 << LFLiveCaptureVideo), ///< only inner capture video (no audio)
|
||||
LFLiveInputMaskAudio = (1 << LFLiveInputAudio), ///< only outer input audio (no video)
|
||||
LFLiveInputMaskVideo = (1 << LFLiveInputVideo), ///< only outer input video (no audio)
|
||||
LFLiveCaptureMaskAll = (LFLiveCaptureMaskAudio | LFLiveCaptureMaskVideo), ///< inner capture audio and video
|
||||
LFLiveInputMaskAll = (LFLiveInputMaskAudio | LFLiveInputMaskVideo), ///< outer input audio and video(method see pushVideo and pushAudio)
|
||||
LFLiveCaptureMaskAudioInputVideo = (LFLiveCaptureMaskAudio | LFLiveInputMaskVideo), ///< inner capture audio and outer input video(method pushVideo and setRunning)
|
||||
LFLiveCaptureMaskVideoInputAudio = (LFLiveCaptureMaskVideo | LFLiveInputMaskAudio), ///< inner capture video and outer input audio(method pushAudio and setRunning)
|
||||
LFLiveCaptureDefaultMask = LFLiveCaptureMaskAll ///< default is inner capture audio and video
|
||||
};
|
||||
|
||||
@class LFLiveSession;
|
||||
@protocol LFLiveSessionDelegate <NSObject>
|
||||
@@ -51,10 +71,10 @@
|
||||
/** 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 */
|
||||
/** The beautyLevel control beautyFace Level. Default is 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 */
|
||||
/** The brightLevel control brightness Level, Default is 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 */
|
||||
@@ -69,12 +89,18 @@
|
||||
/** The muted control callbackAudioData,muted will memset 0.*/
|
||||
@property (nonatomic, assign) BOOL muted;
|
||||
|
||||
/* The adaptiveBitrate control auto adjust bitrate. Default is NO */
|
||||
@property (nonatomic, assign) BOOL adaptiveBitrate;
|
||||
|
||||
/** The stream control upload and package*/
|
||||
@property (nullable, nonatomic, strong, readonly) LFLiveStreamInfo *streamInfo;
|
||||
|
||||
/** The status of the stream .*/
|
||||
@property (nonatomic, assign, readonly) LFLiveState state;
|
||||
|
||||
/** The captureType control inner or outer audio and video .*/
|
||||
@property (nonatomic, assign, readonly) LFLiveCaptureTypeMask captureType;
|
||||
|
||||
/** The showDebugInfo control streamInfo and uploadInfo(1s) *.*/
|
||||
@property (nonatomic, assign) BOOL showDebugInfo;
|
||||
|
||||
@@ -84,6 +110,11 @@
|
||||
/** The reconnectCount control reconnect count (重连次数) *.*/
|
||||
@property (nonatomic, assign) NSUInteger reconnectCount;
|
||||
|
||||
/*** The warterMarkView control whether the watermark is displayed or not ,if set ni,will remove watermark,otherwise add.
|
||||
set alpha represent mix.Position relative to outVideoSize.
|
||||
*.*/
|
||||
@property (nonatomic, strong) UIView *warterMarkView;
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
/// @name Initializer
|
||||
@@ -97,12 +128,23 @@
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration captureType:(LFLiveCaptureTypeMask)captureType NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/** The start stream .*/
|
||||
- (void)startLive:(nonnull LFLiveStreamInfo *)streamInfo;
|
||||
|
||||
/** The stop stream .*/
|
||||
- (void)stopLive;
|
||||
|
||||
/** support outer input yuv or rgb video(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer;
|
||||
|
||||
/** support outer input pcm audio(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+89
-37
@@ -11,19 +11,18 @@
|
||||
#import "LFAudioCapture.h"
|
||||
#import "LFHardwareVideoEncoder.h"
|
||||
#import "LFHardwareAudioEncoder.h"
|
||||
#import "LFH264VideoEncoder.h"
|
||||
#import "LFStreamRTMPSocket.h"
|
||||
#import "LFLiveStreamInfo.h"
|
||||
#import "LFGPUImageBeautyFilter.h"
|
||||
#import "LFH264VideoEncoder.h"
|
||||
|
||||
#define LFLiveReportKey @"com.youku.liveSessionReport"
|
||||
|
||||
@interface LFLiveSession ()<LFAudioCaptureDelegate, LFVideoCaptureDelegate, LFAudioEncodingDelegate, LFVideoEncodingDelegate, LFStreamSocketDelegate>
|
||||
{
|
||||
dispatch_semaphore_t _lock;
|
||||
}
|
||||
///音频配置
|
||||
|
||||
/// 音频配置
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *audioConfiguration;
|
||||
///视频配置
|
||||
/// 视频配置
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
|
||||
/// 声音采集
|
||||
@property (nonatomic, strong) LFAudioCapture *audioCaptureSource;
|
||||
@@ -36,22 +35,28 @@
|
||||
/// 上传
|
||||
@property (nonatomic, strong) id<LFStreamSocket> socket;
|
||||
|
||||
|
||||
#pragma mark -- 内部标识
|
||||
/// 上报
|
||||
@property (nonatomic, copy) dispatch_block_t reportBlock;
|
||||
/// debugInfo
|
||||
/// 调试信息
|
||||
@property (nonatomic, strong) LFLiveDebug *debugInfo;
|
||||
/// streamInfo
|
||||
/// 流信息
|
||||
@property (nonatomic, strong) LFLiveStreamInfo *streamInfo;
|
||||
/// uploading
|
||||
/// 是否开始上传
|
||||
@property (nonatomic, assign) BOOL uploading;
|
||||
/// state
|
||||
/// 当前状态
|
||||
@property (nonatomic, assign, readwrite) LFLiveState state;
|
||||
/// 当前直播type
|
||||
@property (nonatomic, assign, readwrite) LFLiveCaptureTypeMask captureType;
|
||||
|
||||
/// 时间戳锁
|
||||
@property (nonatomic, strong) dispatch_semaphore_t lock;
|
||||
|
||||
@end
|
||||
|
||||
/** 时间戳 */
|
||||
#define NOW (CACurrentMediaTime()*1000)
|
||||
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
|
||||
|
||||
@interface LFLiveSession ()
|
||||
|
||||
@property (nonatomic, assign) uint64_t timestamp;
|
||||
@@ -64,18 +69,25 @@
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
- (instancetype)initWithAudioConfiguration:(LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(LFLiveVideoConfiguration *)videoConfiguration {
|
||||
if (!audioConfiguration || !videoConfiguration) @throw [NSException exceptionWithName:@"LFLiveSession init error" reason:@"audioConfiguration or videoConfiguration is nil " userInfo:nil];
|
||||
return [self initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration captureType:LFLiveCaptureDefaultMask];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration captureType:(LFLiveCaptureTypeMask)captureType{
|
||||
if((captureType & LFLiveCaptureMaskAudio || captureType & LFLiveInputMaskAudio) && !audioConfiguration) @throw [NSException exceptionWithName:@"LFLiveSession init error" reason:@"audioConfiguration is nil " userInfo:nil];
|
||||
if((captureType & LFLiveCaptureMaskVideo || captureType & LFLiveInputMaskVideo) && !videoConfiguration) @throw [NSException exceptionWithName:@"LFLiveSession init error" reason:@"videoConfiguration is nil " userInfo:nil];
|
||||
if (self = [super init]) {
|
||||
_audioConfiguration = audioConfiguration;
|
||||
_videoConfiguration = videoConfiguration;
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
_adaptiveBitrate = NO;
|
||||
_isFirstFrame = YES;
|
||||
_captureType = captureType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
self.audioCaptureSource.running = NO;
|
||||
self.videoCaptureSource.running = NO;
|
||||
self.audioCaptureSource.running = NO;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
@@ -84,6 +96,7 @@
|
||||
_streamInfo = streamInfo;
|
||||
_streamInfo.videoConfiguration = _videoConfiguration;
|
||||
_streamInfo.audioConfiguration = _audioConfiguration;
|
||||
_streamInfo.needDropFrame = (self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo) ? YES : NO;//< 有视频执行丢帧算法
|
||||
[self.socket start];
|
||||
}
|
||||
|
||||
@@ -93,12 +106,24 @@
|
||||
self.socket = nil;
|
||||
}
|
||||
|
||||
- (void)pushVideo:(CVPixelBufferRef)pixelBuffer{
|
||||
if(self.captureType & LFLiveInputMaskVideo){
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushAudio:(AudioBufferList)audioBufferList{
|
||||
if(self.captureType & LFLiveInputMaskAudio){
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioBufferList timeStamp:self.currentTimestamp];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- CaptureDelegate
|
||||
- (void)captureOutput:(nullable LFAudioCapture *)capture audioBuffer:(AudioBufferList)inBufferList {
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:inBufferList timeStamp:self.currentTimestamp];
|
||||
}
|
||||
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVImageBufferRef)pixelBuffer {
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVPixelBufferRef)pixelBuffer {
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
}
|
||||
|
||||
@@ -119,7 +144,7 @@
|
||||
self.isFirstFrame = YES;
|
||||
self.uploading = YES;
|
||||
}
|
||||
}else if(status == LFLiveStop || status == LFLiveError){
|
||||
} else if(status == LFLiveStop || status == LFLiveError){
|
||||
self.uploading = NO;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -150,16 +175,20 @@
|
||||
}
|
||||
|
||||
- (void)socketBufferStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveBuffferState)status {
|
||||
NSUInteger videoBitRate = [_videoEncoder videoBitRate];
|
||||
if (status == LFLiveBuffferDecline) {
|
||||
if (videoBitRate < _videoConfiguration.videoMaxBitRate) {
|
||||
videoBitRate = videoBitRate + 50 * 1000;
|
||||
[_videoEncoder setVideoBitRate:videoBitRate];
|
||||
}
|
||||
} else {
|
||||
if (videoBitRate > _videoConfiguration.videoMinBitRate) {
|
||||
videoBitRate = videoBitRate - 100 * 1000;
|
||||
[_videoEncoder setVideoBitRate:videoBitRate];
|
||||
if((self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo) && self.adaptiveBitrate){
|
||||
NSUInteger videoBitRate = [self.videoEncoder videoBitRate];
|
||||
if (status == LFLiveBuffferDecline) {
|
||||
if (videoBitRate < _videoConfiguration.videoMaxBitRate) {
|
||||
videoBitRate = videoBitRate + 50 * 1000;
|
||||
[self.videoEncoder setVideoBitRate:videoBitRate];
|
||||
NSLog(@"Increase bitrate %@", @(videoBitRate));
|
||||
}
|
||||
} else {
|
||||
if (videoBitRate > self.videoConfiguration.videoMinBitRate) {
|
||||
videoBitRate = videoBitRate - 100 * 1000;
|
||||
[self.videoEncoder setVideoBitRate:videoBitRate];
|
||||
NSLog(@"Decline bitrate %@", @(videoBitRate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,18 +293,30 @@
|
||||
return self.audioCaptureSource.muted;
|
||||
}
|
||||
|
||||
- (void)setWarterMarkView:(UIView *)warterMarkView{
|
||||
[self.videoCaptureSource setWarterMarkView:warterMarkView];
|
||||
}
|
||||
|
||||
- (UIView*)warterMarkView{
|
||||
return self.videoCaptureSource.warterMarkView;
|
||||
}
|
||||
|
||||
- (LFAudioCapture *)audioCaptureSource {
|
||||
if (!_audioCaptureSource) {
|
||||
_audioCaptureSource = [[LFAudioCapture alloc] initWithAudioConfiguration:_audioConfiguration];
|
||||
_audioCaptureSource.delegate = self;
|
||||
if(self.captureType & LFLiveCaptureMaskAudio){
|
||||
_audioCaptureSource = [[LFAudioCapture alloc] initWithAudioConfiguration:_audioConfiguration];
|
||||
_audioCaptureSource.delegate = self;
|
||||
}
|
||||
}
|
||||
return _audioCaptureSource;
|
||||
}
|
||||
|
||||
- (LFVideoCapture *)videoCaptureSource {
|
||||
if (!_videoCaptureSource) {
|
||||
_videoCaptureSource = [[LFVideoCapture alloc] initWithVideoConfiguration:_videoConfiguration];
|
||||
_videoCaptureSource.delegate = self;
|
||||
if(self.captureType & LFLiveCaptureMaskVideo){
|
||||
_videoCaptureSource = [[LFVideoCapture alloc] initWithVideoConfiguration:_videoConfiguration];
|
||||
_videoCaptureSource.delegate = self;
|
||||
}
|
||||
}
|
||||
return _videoCaptureSource;
|
||||
}
|
||||
@@ -290,7 +331,11 @@
|
||||
|
||||
- (id<LFVideoEncoding>)videoEncoder {
|
||||
if (!_videoEncoder) {
|
||||
_videoEncoder = [[LFHardwareVideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
if([[UIDevice currentDevice].systemVersion floatValue] < 8.0){
|
||||
_videoEncoder = [[LFH264VideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
}else{
|
||||
_videoEncoder = [[LFHardwareVideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
}
|
||||
[_videoEncoder setDelegate:self];
|
||||
}
|
||||
return _videoEncoder;
|
||||
@@ -298,7 +343,7 @@
|
||||
|
||||
- (id<LFStreamSocket>)socket {
|
||||
if (!_socket) {
|
||||
_socket = [[LFStreamRTMPSocket alloc] initWithStream:self.streamInfo videoSize:self.videoConfiguration.videoSize reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
|
||||
_socket = [[LFStreamRTMPSocket alloc] initWithStream:self.streamInfo reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
|
||||
[_socket setDelegate:self];
|
||||
}
|
||||
return _socket;
|
||||
@@ -311,17 +356,24 @@
|
||||
return _streamInfo;
|
||||
}
|
||||
|
||||
- (dispatch_semaphore_t)lock{
|
||||
if(!_lock){
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
}
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (uint64_t)currentTimestamp {
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
uint64_t currentts = 0;
|
||||
if (_isFirstFrame == true) {
|
||||
if (_isFirstFrame) {
|
||||
_timestamp = NOW;
|
||||
_isFirstFrame = false;
|
||||
_isFirstFrame = NO;
|
||||
currentts = 0;
|
||||
} else {
|
||||
currentts = NOW - _timestamp;
|
||||
}
|
||||
dispatch_semaphore_signal(_lock);
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
return currentts;
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -86,10 +86,10 @@
|
||||
|
||||
GLubyte *imageData = (GLubyte *) calloc(1, (int)layerPixelSize.width * (int)layerPixelSize.height * 4);
|
||||
|
||||
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
|
||||
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)layerPixelSize.width, (int)layerPixelSize.height, 8, (int)layerPixelSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
||||
// CGContextRotateCTM(imageContext, M_PI_2);
|
||||
CGContextTranslateCTM(imageContext, 0.0f, layerPixelSize.height);
|
||||
// CGContextRotateCTM(imageContext, M_PI_2);
|
||||
CGContextTranslateCTM(imageContext, 0.0f, layerPixelSize.height);
|
||||
CGContextScaleCTM(imageContext, layer.contentsScale, -layer.contentsScale);
|
||||
// CGContextSetBlendMode(imageContext, kCGBlendModeCopy); // From Technical Q&A QA1708: http://developer.apple.com/library/ios/#qa/qa1708/_index.html
|
||||
|
||||
@@ -100,13 +100,13 @@
|
||||
|
||||
// TODO: This may not work
|
||||
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:layerPixelSize textureOptions:self.outputTextureOptions onlyTexture:YES];
|
||||
|
||||
[outputFramebuffer disableReferenceCounting]; // Add this line, because GPUImageTwoInputFilter.m frametime updatedMovieFrameOppositeStillImage is YES, but the secondbuffer not lock
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
|
||||
// no need to use self.outputTextureOptions here, we always need these texture options
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)layerPixelSize.width, (int)layerPixelSize.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);
|
||||
|
||||
free(imageData);
|
||||
|
||||
for (id<GPUImageInput> currentTarget in targets)
|
||||
{
|
||||
if (currentTarget != self.targetToIgnoreForUpdates)
|
||||
@@ -115,9 +115,10 @@
|
||||
NSInteger textureIndexOfTarget = [[targetTextureIndices objectAtIndex:indexOfObject] integerValue];
|
||||
|
||||
[currentTarget setInputSize:layerPixelSize atIndex:textureIndexOfTarget];
|
||||
[currentTarget setInputFramebuffer:outputFramebuffer atIndex:textureIndexOfTarget]; // add this line, because the outputFramebuffer is update above
|
||||
[currentTarget newFrameReadyAtTime:frameTime atIndex:textureIndexOfTarget];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -124,6 +124,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
self.isRunning = YES;
|
||||
NSLog(@"MicrophoneSource: startRunning");
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
@class LFVideoCapture;
|
||||
/** LFVideoCapture callback videoData */
|
||||
@protocol LFVideoCaptureDelegate <NSObject>
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVImageBufferRef)pixelBuffer;
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVPixelBufferRef)pixelBuffer;
|
||||
@end
|
||||
|
||||
@interface LFVideoCapture : NSObject
|
||||
@@ -56,6 +56,9 @@
|
||||
/** The videoFrameRate control videoCapture output data count */
|
||||
@property (nonatomic, assign) NSInteger videoFrameRate;
|
||||
|
||||
/*** The warterMarkView control whether the watermark is displayed or not ,if set ni,will remove watermark,otherwise add *.*/
|
||||
@property (nonatomic, strong) UIView *warterMarkView;
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
/// @name Initializer
|
||||
|
||||
+165
-148
@@ -13,13 +13,17 @@
|
||||
|
||||
@interface LFVideoCapture ()
|
||||
|
||||
@property(nonatomic, strong) GPUImageVideoCamera *videoCamera;
|
||||
@property(nonatomic, weak) LFGPUImageBeautyFilter *beautyFilter;
|
||||
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
|
||||
@property(nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
|
||||
@property(nonatomic, strong) GPUImageCropFilter *cropfilter;
|
||||
@property(nonatomic, strong) GPUImageView *gpuImageView;
|
||||
@property(nonatomic, strong) LFLiveVideoConfiguration *configuration;
|
||||
@property (nonatomic, strong) GPUImageVideoCamera *videoCamera;
|
||||
@property (nonatomic, weak) LFGPUImageBeautyFilter *beautyFilter;
|
||||
@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *filter;
|
||||
@property (nonatomic, strong) GPUImageCropFilter *cropfilter;
|
||||
@property (nonatomic, strong) GPUImageOutput<GPUImageInput> *output;
|
||||
@property (nonatomic, strong) GPUImageView *gpuImageView;
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *configuration;
|
||||
|
||||
@property (nonatomic, strong) GPUImageAlphaBlendFilter *blendFilter;
|
||||
@property (nonatomic, strong) GPUImageUIElement *uiElementInput;
|
||||
@property (nonatomic, strong) UIView *waterMarkContentView;
|
||||
|
||||
@end
|
||||
|
||||
@@ -33,14 +37,32 @@
|
||||
- (instancetype)initWithVideoConfiguration:(LFLiveVideoConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
_configuration = configuration;
|
||||
if([self pixelBufferImageSize].width < configuration.videoSize.width || [self pixelBufferImageSize].height < configuration.videoSize.height){
|
||||
@throw [NSException exceptionWithName:@"当前videoSize大小出错" reason:@"LFLiveVideoConfiguration videoSize error" userInfo:nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
[[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;
|
||||
self.mirror = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self.videoCamera stopCameraCapture];
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
|
||||
- (GPUImageVideoCamera *)videoCamera{
|
||||
if(!_videoCamera){
|
||||
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:_configuration.avSessionPreset cameraPosition:AVCaptureDevicePositionFront];
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (configuration.landscape) {
|
||||
if (self.configuration.landscape) {
|
||||
if (statusBar != UIInterfaceOrientationLandscapeLeft && statusBar != UIInterfaceOrientationLandscapeRight) {
|
||||
@throw [NSException exceptionWithName:@"当前设置方向出错" reason:@"LFLiveVideoConfiguration landscape error" userInfo:nil];
|
||||
_videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
@@ -55,92 +77,69 @@
|
||||
_videoCamera.outputImageOrientation = statusBar;
|
||||
}
|
||||
}
|
||||
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
||||
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
|
||||
_gpuImageView = [[GPUImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
[_gpuImageView setFillMode:kGPUImageFillModePreserveAspectRatioAndFill];
|
||||
[_gpuImageView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
|
||||
|
||||
[[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;
|
||||
return _videoCamera;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[_videoCamera stopCameraCapture];
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
- (void)setRunning:(BOOL)running {
|
||||
if (_running == running) return;
|
||||
_running = running;
|
||||
|
||||
|
||||
if (!_running) {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[_videoCamera stopCameraCapture];
|
||||
[self.videoCamera stopCameraCapture];
|
||||
} else {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
[_videoCamera startCameraCapture];
|
||||
[self reloadFilter];
|
||||
[self.videoCamera startCameraCapture];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPreView:(UIView *)preView {
|
||||
if (_gpuImageView.superview) [_gpuImageView removeFromSuperview];
|
||||
[preView insertSubview:_gpuImageView atIndex:0];
|
||||
if (self.gpuImageView.superview) [self.gpuImageView removeFromSuperview];
|
||||
[preView insertSubview:self.gpuImageView atIndex:0];
|
||||
self.gpuImageView.frame = CGRectMake(0, 0, preView.frame.size.width, preView.frame.size.height);
|
||||
}
|
||||
|
||||
- (UIView *)preView {
|
||||
return _gpuImageView.superview;
|
||||
return self.gpuImageView.superview;
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
[self.videoCamera rotateCamera];
|
||||
self.videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
}
|
||||
|
||||
- (AVCaptureDevicePosition)captureDevicePosition {
|
||||
return [_videoCamera cameraPosition];
|
||||
return [self.videoCamera cameraPosition];
|
||||
}
|
||||
|
||||
- (void)setVideoFrameRate:(NSInteger)videoFrameRate {
|
||||
if (videoFrameRate <= 0) return;
|
||||
if (videoFrameRate == _videoCamera.frameRate) return;
|
||||
_videoCamera.frameRate = (uint32_t)videoFrameRate;
|
||||
if (videoFrameRate == self.videoCamera.frameRate) return;
|
||||
self.videoCamera.frameRate = (uint32_t)videoFrameRate;
|
||||
}
|
||||
|
||||
- (NSInteger)videoFrameRate {
|
||||
return _videoCamera.frameRate;
|
||||
return self.videoCamera.frameRate;
|
||||
}
|
||||
|
||||
- (void)setTorch:(BOOL)torch {
|
||||
BOOL ret;
|
||||
if (!_videoCamera.captureSession) return;
|
||||
AVCaptureSession *session = (AVCaptureSession *)_videoCamera.captureSession;
|
||||
if (!self.videoCamera.captureSession) return;
|
||||
AVCaptureSession *session = (AVCaptureSession *)self.videoCamera.captureSession;
|
||||
[session beginConfiguration];
|
||||
if (_videoCamera.inputCamera) {
|
||||
if (_videoCamera.inputCamera.torchAvailable) {
|
||||
if (self.videoCamera.inputCamera) {
|
||||
if (self.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);
|
||||
if ([self.videoCamera.inputCamera lockForConfiguration:&err]) {
|
||||
[self.videoCamera.inputCamera setTorchMode:(torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff) ];
|
||||
[self.videoCamera.inputCamera unlockForConfiguration];
|
||||
ret = (self.videoCamera.inputCamera.torchMode == AVCaptureTorchModeOn);
|
||||
} else {
|
||||
NSLog(@"Error while locking device for torch: %@", err);
|
||||
ret = false;
|
||||
@@ -154,22 +153,23 @@
|
||||
}
|
||||
|
||||
- (BOOL)torch {
|
||||
return _videoCamera.inputCamera.torchMode;
|
||||
return self.videoCamera.inputCamera.torchMode;
|
||||
}
|
||||
|
||||
- (void)setMirror:(BOOL)mirror {
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = mirror;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = mirror;
|
||||
_mirror = mirror;
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = mirror;
|
||||
}
|
||||
|
||||
- (BOOL)mirror {
|
||||
return _videoCamera.horizontallyMirrorFrontFacingCamera;
|
||||
- (void)setBeautyFace:(BOOL)beautyFace{
|
||||
_beautyFace = beautyFace;
|
||||
[self reloadFilter];
|
||||
}
|
||||
|
||||
- (void)setBeautyLevel:(CGFloat)beautyLevel {
|
||||
_beautyLevel = beautyLevel;
|
||||
if (_beautyFilter) {
|
||||
[_beautyFilter setBeautyLevel:_beautyLevel];
|
||||
if (self.beautyFilter) {
|
||||
[self.beautyFilter setBeautyLevel:_beautyLevel];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,8 +179,8 @@
|
||||
|
||||
- (void)setBrightLevel:(CGFloat)brightLevel {
|
||||
_brightLevel = brightLevel;
|
||||
if (_beautyFilter) {
|
||||
[_beautyFilter setBrightLevel:brightLevel];
|
||||
if (self.beautyFilter) {
|
||||
[self.beautyFilter setBrightLevel:brightLevel];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,54 +203,49 @@
|
||||
return _zoomScale;
|
||||
}
|
||||
|
||||
- (void)setBeautyFace:(BOOL)beautyFace {
|
||||
|
||||
_beautyFace = beautyFace;
|
||||
[_filter removeAllTargets];
|
||||
[_cropfilter removeAllTargets];
|
||||
[_videoCamera removeAllTargets];
|
||||
|
||||
if (_beautyFace) {
|
||||
_output = [[LFGPUImageEmptyFilter alloc] init];
|
||||
_filter = [[LFGPUImageBeautyFilter alloc] init];
|
||||
_beautyFilter = _filter;
|
||||
__weak typeof(self) _self = self;
|
||||
[_output setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
|
||||
[_self processVideo:output];
|
||||
}];
|
||||
} else {
|
||||
_filter = [[LFGPUImageEmptyFilter alloc] init];
|
||||
_beautyFilter = nil;
|
||||
__weak typeof(self) _self = self;
|
||||
[_filter setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
|
||||
[_self processVideo:output];
|
||||
}];
|
||||
- (void)setWarterMarkView:(UIView *)warterMarkView{
|
||||
if(_warterMarkView && _warterMarkView.superview){
|
||||
[_warterMarkView removeFromSuperview];
|
||||
_warterMarkView = nil;
|
||||
}
|
||||
_warterMarkView = warterMarkView;
|
||||
self.blendFilter.mix = warterMarkView.alpha;
|
||||
[self.waterMarkContentView addSubview:_warterMarkView];
|
||||
[self reloadFilter];
|
||||
}
|
||||
|
||||
CGSize imageSize = [self pixelBufferImageSize];
|
||||
CGFloat cropLeft = (imageSize.width - self.configuration.videoSize.width)/2.0/imageSize.width;
|
||||
CGFloat cropTop = (imageSize.height - self.configuration.videoSize.height)/2.0/imageSize.height;
|
||||
|
||||
if(cropLeft == 0 && cropTop == 0){
|
||||
[_videoCamera addTarget:_filter];
|
||||
}else{
|
||||
_cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(cropLeft, cropTop, 1 - cropLeft*2, 1 - cropTop*2)];
|
||||
[_videoCamera addTarget:_cropfilter];
|
||||
[_cropfilter addTarget:_filter];
|
||||
}
|
||||
|
||||
if (_beautyFace) {
|
||||
[_filter addTarget:_output];
|
||||
[_output addTarget:_gpuImageView];
|
||||
} else {
|
||||
[_filter addTarget:_gpuImageView];
|
||||
- (GPUImageUIElement *)uiElementInput{
|
||||
if(!_uiElementInput){
|
||||
_uiElementInput = [[GPUImageUIElement alloc] initWithView:self.waterMarkContentView];
|
||||
}
|
||||
return _uiElementInput;
|
||||
}
|
||||
|
||||
if (_videoCamera.cameraPosition == AVCaptureDevicePositionFront) {
|
||||
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
|
||||
} else {
|
||||
[_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
|
||||
- (GPUImageAlphaBlendFilter *)blendFilter{
|
||||
if(!_blendFilter){
|
||||
_blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
|
||||
_blendFilter.mix = 1.0;
|
||||
[_blendFilter disableSecondFrameCheck];
|
||||
}
|
||||
return _blendFilter;
|
||||
}
|
||||
|
||||
- (UIView *)waterMarkContentView{
|
||||
if(!_waterMarkContentView){
|
||||
_waterMarkContentView = [UIView new];
|
||||
_waterMarkContentView.frame = CGRectMake(0, 0, self.configuration.videoSize.width, self.configuration.videoSize.height);
|
||||
_waterMarkContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
return _waterMarkContentView;
|
||||
}
|
||||
|
||||
- (GPUImageView *)gpuImageView{
|
||||
if(!_gpuImageView){
|
||||
_gpuImageView = [[GPUImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
[_gpuImageView setFillMode:kGPUImageFillModePreserveAspectRatioAndFill];
|
||||
[_gpuImageView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
}
|
||||
return _gpuImageView;
|
||||
}
|
||||
|
||||
#pragma mark -- Custom Method
|
||||
@@ -259,33 +254,85 @@
|
||||
@autoreleasepool {
|
||||
GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
|
||||
CVPixelBufferRef pixelBuffer = [imageFramebuffer pixelBuffer];
|
||||
|
||||
if (pixelBuffer && _self.delegate && [_self.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:)]) {
|
||||
[_self.delegate captureOutput:_self pixelBuffer:pixelBuffer];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)reloadFilter{
|
||||
[self.filter removeAllTargets];
|
||||
[self.blendFilter removeAllTargets];
|
||||
[self.uiElementInput removeAllTargets];
|
||||
[self.videoCamera removeAllTargets];
|
||||
[self.output removeAllTargets];
|
||||
[self.cropfilter removeAllTargets];
|
||||
|
||||
if (self.beautyFace) {
|
||||
self.output = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.filter = [[LFGPUImageBeautyFilter alloc] init];
|
||||
self.beautyFilter = self.filter;
|
||||
} else {
|
||||
self.output = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.filter = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.beautyFilter = nil;
|
||||
}
|
||||
|
||||
//< 480*640 比例为4:3 强制转换为16:9
|
||||
if([self.configuration.avSessionPreset isEqualToString:AVCaptureSessionPreset640x480]){
|
||||
CGRect cropRect = self.configuration.landscape ? CGRectMake(0, 0.125, 1, 0.75) : CGRectMake(0.125, 0, 0.75, 1);
|
||||
self.cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:cropRect];
|
||||
[self.videoCamera addTarget:self.cropfilter];
|
||||
[self.cropfilter addTarget:self.filter];
|
||||
}else{
|
||||
[self.videoCamera addTarget:self.filter];
|
||||
}
|
||||
|
||||
//< 添加水印
|
||||
if(self.warterMarkView){
|
||||
[self.filter addTarget:self.blendFilter];
|
||||
[self.uiElementInput addTarget:self.blendFilter];
|
||||
[self.blendFilter addTarget:self.gpuImageView];
|
||||
[self.filter addTarget:self.output];
|
||||
[self.uiElementInput update];
|
||||
}else{
|
||||
[self.filter addTarget:self.output];
|
||||
[self.output addTarget:self.gpuImageView];
|
||||
}
|
||||
|
||||
[self.filter forceProcessingAtSize:self.configuration.videoSize];
|
||||
[self.output forceProcessingAtSize:self.configuration.videoSize];
|
||||
[self.blendFilter forceProcessingAtSize:self.configuration.videoSize];
|
||||
[self.uiElementInput forceProcessingAtSize:self.configuration.videoSize];
|
||||
|
||||
//< 输出数据
|
||||
__weak typeof(self) _self = self;
|
||||
[self.output setFrameProcessingCompletionBlock:^(GPUImageOutput *output, CMTime time) {
|
||||
[_self processVideo:output];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark Notification
|
||||
|
||||
- (void)willEnterBackground:(NSNotification *)notification {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[_videoCamera pauseCameraCapture];
|
||||
[self.videoCamera pauseCameraCapture];
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
glFinish();
|
||||
});
|
||||
}
|
||||
|
||||
- (void)willEnterForeground:(NSNotification *)notification {
|
||||
[_videoCamera resumeCameraCapture];
|
||||
[self.videoCamera resumeCameraCapture];
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
}
|
||||
|
||||
- (void)statusBarChanged:(NSNotification *)notification {
|
||||
NSLog(@"UIApplicationWillChangeStatusBarOrientationNotification. UserInfo: %@", notification.userInfo);
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (_configuration.landscape) {
|
||||
if (self.configuration.landscape) {
|
||||
if (statusBar == UIInterfaceOrientationLandscapeLeft) {
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeRight;
|
||||
} else if (statusBar == UIInterfaceOrientationLandscapeRight) {
|
||||
@@ -300,34 +347,4 @@
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark --
|
||||
- (CGSize)pixelBufferImageSize{
|
||||
CGSize videoSize = CGSizeZero;
|
||||
switch (self.configuration.sessionPreset) {
|
||||
case LFCaptureSessionPreset360x640:
|
||||
{
|
||||
videoSize = CGSizeMake(480, 640);
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:
|
||||
{
|
||||
videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:
|
||||
{
|
||||
videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(self.configuration.landscape){
|
||||
return CGSizeMake(videoSize.height, videoSize.width);
|
||||
}
|
||||
return videoSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,17 +12,17 @@
|
||||
#import <AVFoundation/AVMediaFormat.h>
|
||||
#import <AVFoundation/AVVideoSettings.h>
|
||||
#import "sys/stat.h"
|
||||
#import "VideoEncoder.h"
|
||||
#import "MP4Atom.h"
|
||||
#import "LFVideoEncoder.h"
|
||||
#import "LFMP4Atom.h"
|
||||
|
||||
typedef int (^encoder_handler_t)(NSArray *data, CMTimeValue ptsValue);
|
||||
typedef int (^param_handler_t)(NSData *params);
|
||||
|
||||
@interface AVEncoder : NSObject
|
||||
@interface LFAVEncoder : NSObject
|
||||
|
||||
@property (atomic) NSUInteger bitrate;
|
||||
|
||||
+ (AVEncoder *)encoderForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate;
|
||||
+ (LFAVEncoder *)encoderForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate;
|
||||
|
||||
- (void)encodeWithBlock:(encoder_handler_t)block onParams:(param_handler_t)paramsHandler;
|
||||
- (void)encodeFrame:(CMSampleBufferRef)sampleBuffer;
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "AVEncoder.h"
|
||||
#import "NALUnit.h"
|
||||
#import "LFAVEncoder.h"
|
||||
#import "LFNALUnit.h"
|
||||
|
||||
static void *AVEncoderContext = &AVEncoderContext;
|
||||
|
||||
@@ -19,14 +19,14 @@ static unsigned int to_host(unsigned char *p){
|
||||
#define MAX_FILENAME_INDEX 5 // filenames "capture1.mp4" wraps at capture5.mp4
|
||||
|
||||
|
||||
@interface AVEncoder ()
|
||||
@interface LFAVEncoder ()
|
||||
|
||||
{
|
||||
// initial writer, used to obtain SPS/PPS from header
|
||||
VideoEncoder *_headerWriter;
|
||||
LFVideoEncoder *_headerWriter;
|
||||
|
||||
// main encoder/writer
|
||||
VideoEncoder *_writer;
|
||||
LFVideoEncoder *_writer;
|
||||
|
||||
// writer output file (input to our extractor) and monitoring
|
||||
NSFileHandle *_inputFile;
|
||||
@@ -70,12 +70,12 @@ static unsigned int to_host(unsigned char *p){
|
||||
|
||||
@end
|
||||
|
||||
@implementation AVEncoder
|
||||
@implementation LFAVEncoder
|
||||
|
||||
@synthesize bitspersecond = _bitspersecond;
|
||||
|
||||
+ (AVEncoder *)encoderForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
AVEncoder *enc = [AVEncoder alloc];
|
||||
+ (LFAVEncoder *)encoderForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
LFAVEncoder *enc = [LFAVEncoder alloc];
|
||||
[enc initForHeight:height andWidth:width bitrate:bitrate];
|
||||
return enc;
|
||||
}
|
||||
@@ -91,12 +91,12 @@ static unsigned int to_host(unsigned char *p){
|
||||
_width = width;
|
||||
_bitrate = bitrate;
|
||||
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"params.mp4"];
|
||||
_headerWriter = [VideoEncoder encoderForPath:path Height:height andWidth:width bitrate:self.bitrate];
|
||||
_headerWriter = [LFVideoEncoder encoderForPath:path Height:height andWidth:width bitrate:self.bitrate];
|
||||
_times = [NSMutableArray arrayWithCapacity:10];
|
||||
|
||||
// swap between 3 filenames
|
||||
_currentFile = 1;
|
||||
_writer = [VideoEncoder encoderForPath:[self makeFilename] Height:height andWidth:width bitrate:self.bitrate];
|
||||
_writer = [LFVideoEncoder encoderForPath:[self makeFilename] Height:height andWidth:width bitrate:self.bitrate];
|
||||
|
||||
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(bitrate)) options:0 context:AVEncoderContext];
|
||||
}
|
||||
@@ -123,9 +123,9 @@ static unsigned int to_host(unsigned char *p){
|
||||
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
struct stat s;
|
||||
fstat([file fileDescriptor], &s);
|
||||
MP4Atom *movie = [MP4Atom atomAt:0 size:s.st_size type:(OSType)('file') inFile:file];
|
||||
MP4Atom *moov = [movie childOfType:(OSType)('moov') startAt:0];
|
||||
MP4Atom *trak = nil;
|
||||
LFMP4Atom *movie = [LFMP4Atom atomAt:0 size:s.st_size type:(OSType)('file') inFile:file];
|
||||
LFMP4Atom *moov = [movie childOfType:(OSType)('moov') startAt:0];
|
||||
LFMP4Atom *trak = nil;
|
||||
if (moov != nil) {
|
||||
for (;; ) {
|
||||
trak = [moov nextChild];
|
||||
@@ -134,7 +134,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
}
|
||||
|
||||
if (trak.type == (OSType)('trak')) {
|
||||
MP4Atom *tkhd = [trak childOfType:(OSType)('tkhd') startAt:0];
|
||||
LFMP4Atom *tkhd = [trak childOfType:(OSType)('tkhd') startAt:0];
|
||||
NSData *verflags = [tkhd readAt:0 size:4];
|
||||
unsigned char *p = (unsigned char *)[verflags bytes];
|
||||
if (p[3] & 1) {
|
||||
@@ -145,13 +145,13 @@ static unsigned int to_host(unsigned char *p){
|
||||
}
|
||||
}
|
||||
}
|
||||
MP4Atom *stsd = nil;
|
||||
LFMP4Atom *stsd = nil;
|
||||
if (trak != nil) {
|
||||
MP4Atom *media = [trak childOfType:(OSType)('mdia') startAt:0];
|
||||
LFMP4Atom *media = [trak childOfType:(OSType)('mdia') startAt:0];
|
||||
if (media != nil) {
|
||||
MP4Atom *minf = [media childOfType:(OSType)('minf') startAt:0];
|
||||
LFMP4Atom *minf = [media childOfType:(OSType)('minf') startAt:0];
|
||||
if (minf != nil) {
|
||||
MP4Atom *stbl = [minf childOfType:(OSType)('stbl') startAt:0];
|
||||
LFMP4Atom *stbl = [minf childOfType:(OSType)('stbl') startAt:0];
|
||||
if (stbl != nil) {
|
||||
stsd = [stbl childOfType:(OSType)('stsd') startAt:0];
|
||||
}
|
||||
@@ -159,9 +159,9 @@ static unsigned int to_host(unsigned char *p){
|
||||
}
|
||||
}
|
||||
if (stsd != nil) {
|
||||
MP4Atom *avc1 = [stsd childOfType:(OSType)('avc1') startAt:8];
|
||||
LFMP4Atom *avc1 = [stsd childOfType:(OSType)('avc1') startAt:8];
|
||||
if (avc1 != nil) {
|
||||
MP4Atom *esd = [avc1 childOfType:(OSType)('avcC') startAt:78];
|
||||
LFMP4Atom *esd = [avc1 childOfType:(OSType)('avcC') startAt:78];
|
||||
if (esd != nil) {
|
||||
// this is the avcC record that we are looking for
|
||||
_avcC = [esd readAt:0 size:esd.length];
|
||||
@@ -229,14 +229,14 @@ static unsigned int to_host(unsigned char *p){
|
||||
if (st.st_size > OUTPUT_FILE_SWITCH_POINT || self.bitrateChanged) {
|
||||
self.bitrateChanged = NO;
|
||||
_swapping = YES;
|
||||
VideoEncoder *oldVideo = _writer;
|
||||
LFVideoEncoder *oldVideo = _writer;
|
||||
|
||||
// construct a new writer to the next filename
|
||||
if (++_currentFile > MAX_FILENAME_INDEX) {
|
||||
_currentFile = 1;
|
||||
}
|
||||
//NSLog(@"Swap to file %d", _currentFile);
|
||||
_writer = [VideoEncoder encoderForPath:[self makeFilename] Height:_height andWidth:_width bitrate:self.bitrate];
|
||||
_writer = [LFVideoEncoder encoderForPath:[self makeFilename] Height:_height andWidth:_width bitrate:self.bitrate];
|
||||
|
||||
// to do this seamlessly requires a few steps in the right order
|
||||
// first, suspend the read source
|
||||
@@ -385,7 +385,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
int naltype = pNal[0] & 0x1f;
|
||||
|
||||
if (_pendingNALU) {
|
||||
NALUnit nal(pNal, [nalu length]);
|
||||
LFNALUnit nal(pNal, [nalu length]);
|
||||
|
||||
// we have existing data —is this the same frame?
|
||||
// typically there are a couple of NALUs per frame in iOS encoding.
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// MP4Atom.h
|
||||
// LFMP4Atom.h
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 15/01/2013.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MP4Atom : NSObject
|
||||
@interface LFMP4Atom : NSObject
|
||||
|
||||
{
|
||||
NSFileHandle *_file;
|
||||
@@ -20,11 +20,11 @@
|
||||
@property OSType type;
|
||||
@property int64_t length;
|
||||
|
||||
+ (MP4Atom *)atomAt:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle;
|
||||
+ (LFMP4Atom *)atomAt:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle;
|
||||
- (BOOL)init:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle;
|
||||
- (NSData *)readAt:(int64_t)offset size:(int)length;
|
||||
- (BOOL)setChildOffset:(int64_t)offset;
|
||||
- (MP4Atom *)nextChild;
|
||||
- (MP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset;
|
||||
- (LFMP4Atom *)nextChild;
|
||||
- (LFMP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset;
|
||||
|
||||
@end
|
||||
@@ -1,24 +1,24 @@
|
||||
//
|
||||
// MP4Atom.m
|
||||
// LFMP4Atom.m
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 15/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "MP4Atom.h"
|
||||
#import "LFMP4Atom.h"
|
||||
|
||||
static unsigned int to_host(unsigned char *p){
|
||||
return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||||
}
|
||||
|
||||
@implementation MP4Atom
|
||||
@implementation LFMP4Atom
|
||||
|
||||
@synthesize type = _type;
|
||||
@synthesize length = _length;
|
||||
|
||||
+ (MP4Atom *)atomAt:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle {
|
||||
MP4Atom *atom = [MP4Atom alloc];
|
||||
+ (LFMP4Atom *)atomAt:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle {
|
||||
LFMP4Atom *atom = [LFMP4Atom alloc];
|
||||
if (![atom init:offset size:length type:fourcc inFile:handle]) {
|
||||
return nil;
|
||||
}
|
||||
@@ -45,7 +45,7 @@ static unsigned int to_host(unsigned char *p){
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (MP4Atom *)nextChild {
|
||||
- (LFMP4Atom *)nextChild {
|
||||
if (_nextChild <= (_length - 8)) {
|
||||
[_file seekToFileOffset:_offset + _nextChild];
|
||||
NSData *data = [_file readDataOfLength:8];
|
||||
@@ -73,14 +73,14 @@ static unsigned int to_host(unsigned char *p){
|
||||
int64_t offset = _nextChild + cHeader;
|
||||
_nextChild += len;
|
||||
len -= cHeader;
|
||||
return [MP4Atom atomAt:offset+_offset size:len type:fourcc inFile:_file];
|
||||
return [LFMP4Atom atomAt:offset+_offset size:len type:fourcc inFile:_file];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (MP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset {
|
||||
- (LFMP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset {
|
||||
[self setChildOffset:offset];
|
||||
MP4Atom *child = nil;
|
||||
LFMP4Atom *child = nil;
|
||||
do {
|
||||
child = [self nextChild];
|
||||
} while ((child != nil) && (child.type != fourcc));
|
||||
@@ -10,18 +10,18 @@
|
||||
|
||||
|
||||
|
||||
#include "NALUnit.h"
|
||||
#include "LFNALUnit.h"
|
||||
|
||||
|
||||
// --- core NAL Unit implementation ------------------------------
|
||||
|
||||
NALUnit::NALUnit()
|
||||
LFNALUnit::LFNALUnit()
|
||||
: m_pStart(NULL),
|
||||
m_cBytes(0){
|
||||
}
|
||||
|
||||
bool
|
||||
NALUnit::GetStartCode(const BYTE *& pBegin, const BYTE *& pStart, int& cRemain){
|
||||
LFNALUnit::GetStartCode(const BYTE *& pBegin, const BYTE *& pStart, int& cRemain){
|
||||
// start code is any number of 00 followed by 00 00 01
|
||||
// We need to record the first 00 in pBegin and the first byte
|
||||
// following the startcode in pStart.
|
||||
@@ -54,7 +54,7 @@ NALUnit::GetStartCode(const BYTE *& pBegin, const BYTE *& pStart, int& cRemain){
|
||||
}
|
||||
|
||||
bool
|
||||
NALUnit::Parse(const BYTE *pBuffer, int cSpace, int LengthSize, bool bEnd){
|
||||
LFNALUnit::Parse(const BYTE *pBuffer, int cSpace, int LengthSize, bool bEnd){
|
||||
// if we get the start code but not the whole
|
||||
// NALU, we can return false but still have the length property valid
|
||||
m_cBytes = 0;
|
||||
@@ -102,14 +102,14 @@ NALUnit::Parse(const BYTE *pBuffer, int cSpace, int LengthSize, bool bEnd){
|
||||
|
||||
// bitwise access to data
|
||||
void
|
||||
NALUnit::ResetBitstream(){
|
||||
LFNALUnit::ResetBitstream(){
|
||||
m_idx = 0;
|
||||
m_nBits = 0;
|
||||
m_cZeros = 0;
|
||||
}
|
||||
|
||||
void
|
||||
NALUnit::Skip(int nBits){
|
||||
LFNALUnit::Skip(int nBits){
|
||||
if (nBits < m_nBits) {
|
||||
m_nBits -= nBits;
|
||||
} else {
|
||||
@@ -129,7 +129,7 @@ NALUnit::Skip(int nBits){
|
||||
|
||||
// get the next byte, removing emulation prevention bytes
|
||||
BYTE
|
||||
NALUnit::GetBYTE(){
|
||||
LFNALUnit::GetBYTE(){
|
||||
if (m_idx >= m_cBytes) {
|
||||
return 0;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ NALUnit::GetBYTE(){
|
||||
}
|
||||
|
||||
unsigned long
|
||||
NALUnit::GetBit(){
|
||||
LFNALUnit::GetBit(){
|
||||
if (m_nBits == 0) {
|
||||
m_byte = GetBYTE();
|
||||
m_nBits = 8;
|
||||
@@ -161,7 +161,7 @@ NALUnit::GetBit(){
|
||||
}
|
||||
|
||||
unsigned long
|
||||
NALUnit::GetWord(int nBits){
|
||||
LFNALUnit::GetWord(int nBits){
|
||||
unsigned long u = 0;
|
||||
while (nBits > 0) {
|
||||
u <<= 1;
|
||||
@@ -172,7 +172,7 @@ NALUnit::GetWord(int nBits){
|
||||
}
|
||||
|
||||
unsigned long
|
||||
NALUnit::GetUE(){
|
||||
LFNALUnit::GetUE(){
|
||||
// Exp-Golomb entropy coding: leading zeros, then a one, then
|
||||
// the data bits. The number of leading zeros is the number of
|
||||
// data bits, counting up from that number of 1s as the base.
|
||||
@@ -188,7 +188,7 @@ NALUnit::GetUE(){
|
||||
}
|
||||
|
||||
long
|
||||
NALUnit::GetSE(){
|
||||
LFNALUnit::GetSE(){
|
||||
// same as UE but signed.
|
||||
// basically the unsigned numbers are used as codes to indicate signed numbers in pairs
|
||||
// in increasing value. Thus the encoded values
|
||||
@@ -206,7 +206,7 @@ NALUnit::GetSE(){
|
||||
}
|
||||
|
||||
// --- sequence params parsing ---------------
|
||||
SeqParamSet::SeqParamSet()
|
||||
LFSeqParamSet::LFSeqParamSet()
|
||||
: m_cx(0),
|
||||
m_cy(0),
|
||||
m_FrameBits(0){
|
||||
@@ -214,7 +214,7 @@ SeqParamSet::SeqParamSet()
|
||||
}
|
||||
|
||||
void
|
||||
ScalingList(int size, NALUnit *pnalu){
|
||||
ScalingList(int size, LFNALUnit *pnalu){
|
||||
long lastScale = 8;
|
||||
long nextScale = 8;
|
||||
for (int j = 0; j < size; j++) {
|
||||
@@ -228,8 +228,8 @@ ScalingList(int size, NALUnit *pnalu){
|
||||
}
|
||||
|
||||
bool
|
||||
SeqParamSet::Parse(NALUnit *pnalu){
|
||||
if (pnalu->Type() != NALUnit::NAL_Sequence_Params) {
|
||||
LFSeqParamSet::Parse(LFNALUnit *pnalu){
|
||||
if (pnalu->Type() != LFNALUnit::NAL_Sequence_Params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -339,11 +339,11 @@ SeqParamSet::Parse(NALUnit *pnalu){
|
||||
|
||||
// --- slice header --------------------
|
||||
bool
|
||||
SliceHeader::Parse(NALUnit *pnalu){
|
||||
LFSliceHeader::Parse(LFNALUnit *pnalu){
|
||||
switch (pnalu->Type()) {
|
||||
case NALUnit::NAL_IDR_Slice:
|
||||
case NALUnit::NAL_Slice:
|
||||
case NALUnit::NAL_PartitionA:
|
||||
case LFNALUnit::NAL_IDR_Slice:
|
||||
case LFNALUnit::NAL_Slice:
|
||||
case LFNALUnit::NAL_PartitionA:
|
||||
// all these begin with a slice header
|
||||
break;
|
||||
|
||||
@@ -366,7 +366,7 @@ SliceHeader::Parse(NALUnit *pnalu){
|
||||
// --- SEI ----------------------
|
||||
|
||||
|
||||
SEIMessage::SEIMessage(NALUnit *pnalu){
|
||||
LFSEIMessage::LFSEIMessage(LFNALUnit *pnalu){
|
||||
m_pnalu = pnalu;
|
||||
const BYTE *p = pnalu->Start();
|
||||
p++; // nalu type byte
|
||||
@@ -387,7 +387,7 @@ SEIMessage::SEIMessage(NALUnit *pnalu){
|
||||
m_idxPayload = int(p - m_pnalu->Start());
|
||||
}
|
||||
|
||||
avcCHeader::avcCHeader(const BYTE *header, int cBytes){
|
||||
LFavcCHeader::LFavcCHeader(const BYTE *header, int cBytes){
|
||||
if (cBytes < 8) {
|
||||
return;
|
||||
}
|
||||
@@ -405,7 +405,7 @@ avcCHeader::avcCHeader(const BYTE *header, int cBytes){
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
NALUnit n(header, cThis);
|
||||
LFNALUnit n(header, cThis);
|
||||
m_sps = n;
|
||||
}
|
||||
header += cThis;
|
||||
@@ -417,7 +417,7 @@ avcCHeader::avcCHeader(const BYTE *header, int cBytes){
|
||||
if (cPPS > 0) {
|
||||
int cThis = (header[1] << 8) + header[2];
|
||||
header += 3;
|
||||
NALUnit n(header, cThis);
|
||||
LFNALUnit n(header, cThis);
|
||||
m_pps = n;
|
||||
}
|
||||
}
|
||||
@@ -18,25 +18,25 @@ typedef unsigned long ULONG;
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
class NALUnit
|
||||
class LFNALUnit
|
||||
{
|
||||
public:
|
||||
NALUnit();
|
||||
NALUnit(const BYTE* pStart, int len){
|
||||
LFNALUnit();
|
||||
LFNALUnit(const BYTE* pStart, int len){
|
||||
m_pStart = m_pStartCodeStart = pStart;
|
||||
m_cBytes = len;
|
||||
ResetBitstream();
|
||||
}
|
||||
virtual ~NALUnit() {
|
||||
virtual ~LFNALUnit() {
|
||||
}
|
||||
|
||||
// assignment copies a pointer into a fixed buffer managed elsewhere. We do not copy the data
|
||||
NALUnit(const NALUnit &r){
|
||||
LFNALUnit(const LFNALUnit &r){
|
||||
m_pStart = r.m_pStart;
|
||||
m_cBytes = r.m_cBytes;
|
||||
ResetBitstream();
|
||||
}
|
||||
const NALUnit& operator = (const NALUnit &r)
|
||||
const LFNALUnit& operator = (const LFNALUnit &r)
|
||||
{
|
||||
m_pStart = r.m_pStart;
|
||||
m_cBytes = r.m_cBytes;
|
||||
@@ -109,11 +109,11 @@ private:
|
||||
|
||||
|
||||
// simple parser for the Sequence parameter set things that we need
|
||||
class SeqParamSet
|
||||
class LFSeqParamSet
|
||||
{
|
||||
public:
|
||||
SeqParamSet();
|
||||
bool Parse(NALUnit *pnalu);
|
||||
LFSeqParamSet();
|
||||
bool Parse(LFNALUnit *pnalu);
|
||||
int FrameBits(){
|
||||
return m_FrameBits;
|
||||
}
|
||||
@@ -162,12 +162,12 @@ public:
|
||||
return m_Compatibility;
|
||||
}
|
||||
|
||||
NALUnit *NALU() {
|
||||
LFNALUnit *NALU() {
|
||||
return &m_nalu;
|
||||
}
|
||||
|
||||
private:
|
||||
NALUnit m_nalu;
|
||||
LFNALUnit m_nalu;
|
||||
int m_FrameBits;
|
||||
long m_cx;
|
||||
long m_cy;
|
||||
@@ -180,15 +180,15 @@ private:
|
||||
};
|
||||
|
||||
// extract frame num from slice headers
|
||||
class SliceHeader
|
||||
class LFSliceHeader
|
||||
{
|
||||
public:
|
||||
SliceHeader(int nBitsFrame)
|
||||
LFSliceHeader(int nBitsFrame)
|
||||
: m_framenum(0),
|
||||
m_nBitsFrame(nBitsFrame){
|
||||
}
|
||||
|
||||
bool Parse(NALUnit *pnalu);
|
||||
bool Parse(LFNALUnit *pnalu);
|
||||
int FrameNum(){
|
||||
return m_framenum;
|
||||
}
|
||||
@@ -199,10 +199,10 @@ private:
|
||||
};
|
||||
|
||||
// SEI message structure
|
||||
class SEIMessage
|
||||
class LFSEIMessage
|
||||
{
|
||||
public:
|
||||
SEIMessage(NALUnit* pnalu);
|
||||
LFSEIMessage(LFNALUnit* pnalu);
|
||||
int Type() {
|
||||
return m_type;
|
||||
}
|
||||
@@ -216,27 +216,27 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
NALUnit *m_pnalu;
|
||||
LFNALUnit *m_pnalu;
|
||||
int m_type;
|
||||
int m_length;
|
||||
int m_idxPayload;
|
||||
};
|
||||
|
||||
// avcC structure from MP4
|
||||
class avcCHeader
|
||||
class LFavcCHeader
|
||||
{
|
||||
public:
|
||||
avcCHeader(const BYTE* header, int cBytes);
|
||||
NALUnit *sps() {
|
||||
LFavcCHeader(const BYTE* header, int cBytes);
|
||||
LFNALUnit *sps() {
|
||||
return &m_sps;
|
||||
}
|
||||
|
||||
NALUnit *pps() {
|
||||
LFNALUnit *pps() {
|
||||
return &m_pps;
|
||||
}
|
||||
|
||||
private:
|
||||
NALUnit m_sps;
|
||||
NALUnit m_pps;
|
||||
LFNALUnit m_sps;
|
||||
LFNALUnit m_pps;
|
||||
};
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#import "AVFoundation/AVMediaFormat.h"
|
||||
#import "AVFoundation/AVVideoSettings.h"
|
||||
|
||||
@interface VideoEncoder : NSObject
|
||||
@interface LFVideoEncoder : NSObject
|
||||
|
||||
|
||||
@property NSString *path;
|
||||
@property (nonatomic, readonly) NSUInteger bitrate;
|
||||
|
||||
+ (VideoEncoder *)encoderForPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate;
|
||||
+ (LFVideoEncoder *)encoderForPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate;
|
||||
|
||||
- (void)initPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate;
|
||||
- (void)finishWithCompletionHandler:(void (^)(void))handler;
|
||||
@@ -1,14 +1,14 @@
|
||||
//
|
||||
// VideoEncoder.m
|
||||
// LFVideoEncoder.m
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 14/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "VideoEncoder.h"
|
||||
#import "LFVideoEncoder.h"
|
||||
|
||||
@implementation VideoEncoder
|
||||
@implementation LFVideoEncoder
|
||||
{
|
||||
AVAssetWriter *_writer;
|
||||
AVAssetWriterInput *_writerInput;
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
@synthesize path = _path;
|
||||
|
||||
+ (VideoEncoder *)encoderForPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
VideoEncoder *enc = [VideoEncoder alloc];
|
||||
+ (LFVideoEncoder *)encoderForPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
LFVideoEncoder *enc = [LFVideoEncoder alloc];
|
||||
[enc initPath:path Height:height andWidth:width bitrate:bitrate];
|
||||
return enc;
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
#import <mach/mach_time.h>
|
||||
#import "NALUnit.h"
|
||||
#import "AVEncoder.h"
|
||||
#import "LFNALUnit.h"
|
||||
#import "LFAVEncoder.h"
|
||||
#import "LFH264VideoEncoder.h"
|
||||
#import "LFVideoFrame.h"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
@property (nonatomic) NSInteger currentVideoBitRate;
|
||||
@property (nonatomic, strong) dispatch_queue_t sendQueue;
|
||||
|
||||
@property (nonatomic, strong) AVEncoder *encoder;
|
||||
@property (nonatomic, strong) LFAVEncoder *encoder;
|
||||
|
||||
@property (nonatomic, strong) NSData *naluStartCode;
|
||||
@property (nonatomic, strong) NSMutableData *videoSPSandPPS;
|
||||
@@ -60,7 +60,7 @@
|
||||
[self initForFilePath];
|
||||
#endif
|
||||
|
||||
_encoder = [AVEncoder encoderForHeight:_configuration.videoSize.height andWidth:_configuration.videoSize.width bitrate:_configuration.videoBitRate];
|
||||
_encoder = [LFAVEncoder encoderForHeight:_configuration.videoSize.height andWidth:_configuration.videoSize.width bitrate:_configuration.videoBitRate];
|
||||
[_encoder encodeWithBlock:^int(NSArray* dataArray, CMTimeValue ptsValue) {
|
||||
[self incomingVideoFrames:dataArray ptsValue:ptsValue];
|
||||
return 0;
|
||||
@@ -85,8 +85,8 @@
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
avcCHeader avcC((const BYTE*)[config bytes], [config length]);
|
||||
SeqParamSet seqParams;
|
||||
LFavcCHeader avcC((const BYTE*)[config bytes], [config length]);
|
||||
LFSeqParamSet seqParams;
|
||||
seqParams.Parse(avcC.sps());
|
||||
|
||||
NSData* spsData = [NSData dataWithBytes:avcC.sps()->Start() length:avcC.sps()->Length()];
|
||||
|
||||
@@ -66,9 +66,9 @@
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(_configuration.videoBitRate));
|
||||
NSArray *limit = @[@(_configuration.videoBitRate * 1.5/8), @(1)];
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)limit);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanFalse);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Main_AutoLevel);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanFalse);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, kCFBooleanTrue);
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_H264EntropyMode, kVTH264EntropyMode_CABAC);
|
||||
VTCompressionSessionPrepareToEncodeFrames(compressionSession);
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
}
|
||||
|
||||
#pragma mark -- LFVideoEncoder
|
||||
- (void)encodeVideoData:(CVImageBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp {
|
||||
- (void)encodeVideoData:(CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp {
|
||||
if (_isBackGround) return;
|
||||
|
||||
frameCount++;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
/// 编码器抽象的接口
|
||||
@protocol LFVideoEncoding <NSObject>
|
||||
@required
|
||||
- (void)encodeVideoData:(nullable CVImageBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp;
|
||||
- (void)encodeVideoData:(nullable CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp;
|
||||
- (void)stopEncoder;
|
||||
@optional
|
||||
@property (nonatomic, assign) NSInteger videoBitRate;
|
||||
|
||||
@@ -57,9 +57,12 @@ typedef NS_ENUM (NSUInteger, LFLiveVideoQuality){
|
||||
///=============================================================================
|
||||
/// @name Attribute
|
||||
///=============================================================================
|
||||
/// 视频的分辨率,宽高务必设定为 2 的倍数,否则解码播放时可能出现绿边
|
||||
/// 视频的分辨率,宽高务必设定为 2 的倍数,否则解码播放时可能出现绿边(这个videoSizeRespectingAspectRatio设置为YES则可能会改变)
|
||||
@property (nonatomic, assign) CGSize videoSize;
|
||||
|
||||
/// 输出图像是否等比例,默认为NO
|
||||
@property (nonatomic, assign) BOOL videoSizeRespectingAspectRatio;
|
||||
|
||||
/// 视频输出方向
|
||||
@property (nonatomic, assign) BOOL landscape;
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
|
||||
@implementation LFLiveVideoConfiguration
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
|
||||
+ (instancetype)defaultConfiguration {
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Default];
|
||||
return configuration;
|
||||
@@ -25,8 +27,7 @@
|
||||
+ (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;
|
||||
@@ -36,9 +37,8 @@
|
||||
configuration.videoMinBitRate = 400 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low2:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_Low2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
@@ -48,9 +48,8 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low3:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_Low3: {
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
@@ -60,9 +59,8 @@
|
||||
configuration.videoMinBitRate = 600 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium1:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium1:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
@@ -72,9 +70,8 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium2:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
@@ -84,9 +81,8 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium3:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium3:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
@@ -96,9 +92,8 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High1:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_High1:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
@@ -108,9 +103,8 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High2:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_High2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
@@ -120,9 +114,8 @@
|
||||
configuration.videoMinBitRate = 800 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High3:
|
||||
{
|
||||
break;
|
||||
case LFLiveVideoQuality_High3:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
@@ -132,7 +125,7 @@
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -146,35 +139,40 @@
|
||||
configuration.videoSize = CGSizeMake(size.width, size.height);
|
||||
}
|
||||
return configuration;
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
- (NSString *)avSessionPreset {
|
||||
NSString *avSessionPreset = nil;
|
||||
switch (self.sessionPreset) {
|
||||
case LFCaptureSessionPreset360x640:
|
||||
{
|
||||
case LFCaptureSessionPreset360x640:{
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:
|
||||
{
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:{
|
||||
avSessionPreset = AVCaptureSessionPresetiFrame960x540;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:
|
||||
{
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:{
|
||||
avSessionPreset = AVCaptureSessionPreset1280x720;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default: {
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return avSessionPreset;
|
||||
}
|
||||
|
||||
- (CGSize)videoSize{
|
||||
if(_videoSizeRespectingAspectRatio){
|
||||
return self.aspectRatioVideoSize;
|
||||
}
|
||||
return _videoSize;
|
||||
}
|
||||
|
||||
- (void)setVideoMaxBitRate:(NSUInteger)videoMaxBitRate {
|
||||
if (videoMaxBitRate <= _videoBitRate) return;
|
||||
_videoMaxBitRate = videoMaxBitRate;
|
||||
@@ -195,15 +193,31 @@
|
||||
_videoMinFrameRate = videoMinFrameRate;
|
||||
}
|
||||
|
||||
- (void)setSessionPreset:(LFLiveVideoSessionPreset)sessionPreset{
|
||||
_sessionPreset = sessionPreset;
|
||||
_sessionPreset = [self supportSessionPreset:sessionPreset];
|
||||
}
|
||||
|
||||
#pragma mark -- Custom Method
|
||||
- (LFLiveVideoSessionPreset)supportSessionPreset:(LFLiveVideoSessionPreset)sessionPreset {
|
||||
NSString *avSessionPreset = [self avSessionPreset];
|
||||
AVCaptureSession *session = [[AVCaptureSession alloc] init];
|
||||
|
||||
if (![session canSetSessionPreset:avSessionPreset]) {
|
||||
AVCaptureDevice *inputCamera;
|
||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
for (AVCaptureDevice *device in devices){
|
||||
if ([device position] == AVCaptureDevicePositionFront){
|
||||
inputCamera = device;
|
||||
}
|
||||
}
|
||||
AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:inputCamera error:nil];
|
||||
|
||||
if ([session canAddInput:videoInput]){
|
||||
[session addInput:videoInput];
|
||||
}
|
||||
|
||||
if (![session canSetSessionPreset:self.avSessionPreset]) {
|
||||
if (sessionPreset == LFCaptureSessionPreset720x1280) {
|
||||
sessionPreset = LFCaptureSessionPreset540x960;
|
||||
if (![session canSetSessionPreset:avSessionPreset]) {
|
||||
if (![session canSetSessionPreset:self.avSessionPreset]) {
|
||||
sessionPreset = LFCaptureSessionPreset360x640;
|
||||
}
|
||||
} else if (sessionPreset == LFCaptureSessionPreset540x960) {
|
||||
@@ -213,24 +227,71 @@
|
||||
return sessionPreset;
|
||||
}
|
||||
|
||||
- (CGSize)captureOutVideoSize{
|
||||
CGSize videoSize = CGSizeZero;
|
||||
switch (_sessionPreset) {
|
||||
case LFCaptureSessionPreset360x640:{
|
||||
videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:{
|
||||
videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:{
|
||||
videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
|
||||
default:{
|
||||
videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(self.landscape){
|
||||
return CGSizeMake(videoSize.height, videoSize.width);
|
||||
}
|
||||
return videoSize;
|
||||
}
|
||||
|
||||
- (CGSize)aspectRatioVideoSize{
|
||||
CGSize size = AVMakeRectWithAspectRatioInsideRect(self.captureOutVideoSize, CGRectMake(0, 0, _videoSize.width, _videoSize.height)).size;
|
||||
NSInteger width = ceil(size.width);
|
||||
NSInteger height = ceil(size.height);
|
||||
if(width %2 != 0) width = width - 1;
|
||||
if(height %2 != 0) height = height - 1;
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
#pragma mark -- encoder
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:[NSValue valueWithCGSize:self.videoSize] forKey:@"videoSize"];
|
||||
[aCoder encodeObject:@(self.videoFrameRate) forKey:@"videoFrameRate"];
|
||||
[aCoder encodeObject:@(self.videoMaxFrameRate) forKey:@"videoMaxFrameRate"];
|
||||
[aCoder encodeObject:@(self.videoMinFrameRate) forKey:@"videoMinFrameRate"];
|
||||
[aCoder encodeObject:@(self.videoMaxKeyframeInterval) forKey:@"videoMaxKeyframeInterval"];
|
||||
[aCoder encodeObject:@(self.videoBitRate) forKey:@"videoBitRate"];
|
||||
[aCoder encodeObject:@(self.videoMaxBitRate) forKey:@"videoMaxBitRate"];
|
||||
[aCoder encodeObject:@(self.videoMinBitRate) forKey:@"videoMinBitRate"];
|
||||
[aCoder encodeObject:@(self.sessionPreset) forKey:@"sessionPreset"];
|
||||
[aCoder encodeObject:@(self.landscape) forKey:@"landscape"];
|
||||
[aCoder encodeObject:@(self.videoSizeRespectingAspectRatio) forKey:@"videoSizeRespectingAspectRatio"];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super init];
|
||||
_videoSize = [[aDecoder decodeObjectForKey:@"videoSize"] CGSizeValue];
|
||||
_videoFrameRate = [[aDecoder decodeObjectForKey:@"videoFrameRate"] unsignedIntegerValue];
|
||||
_videoMaxFrameRate = [[aDecoder decodeObjectForKey:@"videoMaxFrameRate"] unsignedIntegerValue];
|
||||
_videoMinFrameRate = [[aDecoder decodeObjectForKey:@"videoMinFrameRate"] unsignedIntegerValue];
|
||||
_videoMaxKeyframeInterval = [[aDecoder decodeObjectForKey:@"videoMaxKeyframeInterval"] unsignedIntegerValue];
|
||||
_videoBitRate = [[aDecoder decodeObjectForKey:@"videoBitRate"] unsignedIntegerValue];
|
||||
_videoMaxBitRate = [[aDecoder decodeObjectForKey:@"videoMaxBitRate"] unsignedIntegerValue];
|
||||
_videoMinBitRate = [[aDecoder decodeObjectForKey:@"videoMinBitRate"] unsignedIntegerValue];
|
||||
_sessionPreset = [[aDecoder decodeObjectForKey:@"sessionPreset"] unsignedIntegerValue];
|
||||
_landscape = [[aDecoder decodeObjectForKey:@"landscape"] unsignedIntegerValue];
|
||||
_videoSizeRespectingAspectRatio = [[aDecoder decodeObjectForKey:@"videoSizeRespectingAspectRatio"] unsignedIntegerValue];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -246,7 +307,8 @@
|
||||
@(self.videoMinBitRate),
|
||||
self.avSessionPreset,
|
||||
@(self.sessionPreset),
|
||||
@(self.landscape), ];
|
||||
@(self.landscape),
|
||||
@(self.videoSizeRespectingAspectRatio)];
|
||||
|
||||
for (NSObject *value in values) {
|
||||
hash ^= value.hash;
|
||||
@@ -271,7 +333,8 @@
|
||||
object.videoMinBitRate == self.videoMinBitRate &&
|
||||
[object.avSessionPreset isEqualToString:self.avSessionPreset] &&
|
||||
object.sessionPreset == self.sessionPreset &&
|
||||
object.landscape == self.landscape;
|
||||
object.landscape == self.landscape &&
|
||||
object.videoSizeRespectingAspectRatio == self.videoSizeRespectingAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,6 +347,7 @@
|
||||
NSMutableString *desc = @"".mutableCopy;
|
||||
[desc appendFormat:@"<LFLiveVideoConfiguration: %p>", self];
|
||||
[desc appendFormat:@" videoSize:%@", NSStringFromCGSize(self.videoSize)];
|
||||
[desc appendFormat:@" videoSizeRespectingAspectRatio:%zi",self.videoSizeRespectingAspectRatio];
|
||||
[desc appendFormat:@" videoFrameRate:%zi", self.videoFrameRate];
|
||||
[desc appendFormat:@" videoMaxFrameRate:%zi", self.videoMaxFrameRate];
|
||||
[desc appendFormat:@" videoMinFrameRate:%zi", self.videoMinFrameRate];
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef NS_ENUM (NSUInteger, LFLiveSocketErrorCode) {
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *audioConfiguration;
|
||||
///视频配置
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
|
||||
|
||||
///是否丢帧
|
||||
@property (nonatomic, assign) BOOL needDropFrame;
|
||||
|
||||
@end
|
||||
|
||||
@@ -69,13 +69,17 @@ SAVC(mp4a);
|
||||
@implementation LFStreamRTMPSocket
|
||||
|
||||
#pragma mark -- LFStreamSocket
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream videoSize:(CGSize)videoSize reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount {
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream{
|
||||
return [self initWithStream:stream reconnectInterval:0 reconnectCount:0];
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream 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;
|
||||
|
||||
@@ -252,6 +256,7 @@ SAVC(mp4a);
|
||||
_rtmp->m_userData = (__bridge void *)self;
|
||||
_rtmp->m_msgCounter = 1;
|
||||
_rtmp->Link.timeout = RTMP_RECEIVE_TIMEOUT;
|
||||
|
||||
//设置可写,即发布流,这个函数必须在连接前使用,否则无效
|
||||
PILI_RTMP_EnableWrite(_rtmp);
|
||||
|
||||
@@ -533,6 +538,7 @@ void ConnectionTimeCallback(PILI_CONNECTION_TIME *conn_time, void *userData) {
|
||||
if (!_buffer) {
|
||||
_buffer = [[LFStreamingBuffer alloc] init];
|
||||
_buffer.delegate = self;
|
||||
_buffer.needDropFrame = self.stream.needDropFrame;
|
||||
}
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,5 @@
|
||||
- (void)setDelegate:(nullable id <LFStreamSocketDelegate>)delegate;
|
||||
@optional
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream;
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream videoSize:(CGSize)videoSize;
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream videoSize:(CGSize)videoSize reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount;
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount;
|
||||
@end
|
||||
|
||||
@@ -27,6 +27,9 @@ typedef NS_ENUM (NSUInteger, LFLiveBuffferState) {
|
||||
|
||||
@interface LFStreamingBuffer : NSObject
|
||||
|
||||
/** The needDropFrame control Dynamic frame loss ,default is YES */
|
||||
@property (nonatomic, assign) BOOL needDropFrame;
|
||||
|
||||
/** The delegate of the buffer. buffer callback */
|
||||
@property (nullable, nonatomic, weak) id <LFStreamingBufferDelegate> delegate;
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
self.maxCount = defaultSendBufferMaxCount;
|
||||
self.lastDropFrames = 0;
|
||||
self.startTimer = NO;
|
||||
self.needDropFrame = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -91,21 +92,26 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
- (void)removeExpireFrame {
|
||||
if (self.list.count < self.maxCount) return;
|
||||
|
||||
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
|
||||
self.lastDropFrames += [pFrames count];
|
||||
if (pFrames && pFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:pFrames];
|
||||
return;
|
||||
if(self.needDropFrame){
|
||||
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
|
||||
self.lastDropFrames += [pFrames count];
|
||||
if (pFrames && pFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:pFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
|
||||
self.lastDropFrames += [iFrames count];
|
||||
if (iFrames) {
|
||||
[self.list removeObjectsInArray:iFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.list removeAllObjects];
|
||||
}else{
|
||||
[self.list lfPopFirstObject];
|
||||
}
|
||||
|
||||
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
|
||||
self.lastDropFrames += [iFrames count];
|
||||
if (iFrames) {
|
||||
[self.list removeObjectsInArray:iFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
[self.list removeAllObjects];
|
||||
|
||||
}
|
||||
|
||||
- (NSArray *)expirePFrames {
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
81E848D8BD2C446C2DD4876A /* libPods-LFLiveKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */; };
|
||||
84C7AFA71D52F75C00614703 /* ios-29x29.png in Resources */ = {isa = PBXBuildFile; fileRef = 84C7AFA61D52F75C00614703 /* ios-29x29.png */; };
|
||||
A9DB2F10F7A29BE365D7CA5A /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 91E73D3676F527F2A7BD7C6C /* libPods.a */; };
|
||||
B2D23E7F1D348F3D00B34CA8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E7E1D348F3D00B34CA8 /* main.m */; };
|
||||
B2D23E821D348F3D00B34CA8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E811D348F3D00B34CA8 /* AppDelegate.m */; };
|
||||
B2D23E851D348F3D00B34CA8 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B2D23E841D348F3D00B34CA8 /* ViewController.m */; };
|
||||
@@ -31,7 +33,9 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84C7AFA61D52F75C00614703 /* ios-29x29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ios-29x29.png"; sourceTree = "<group>"; };
|
||||
8FAAEBE1A4F099C69588B394 /* 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>"; };
|
||||
91E73D3676F527F2A7BD7C6C /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AFD491825C5DB2AD871189B5 /* 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>"; };
|
||||
B2D23E7A1D348F3D00B34CA8 /* LFLiveKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LFLiveKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B2D23E7E1D348F3D00B34CA8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
@@ -67,6 +71,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
81E848D8BD2C446C2DD4876A /* libPods-LFLiveKitDemo.a in Frameworks */,
|
||||
A9DB2F10F7A29BE365D7CA5A /* libPods.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -160,6 +165,7 @@
|
||||
B2D23EA51D348F7100B34CA8 /* camra_preview@3x.png */,
|
||||
B2D23EA61D348F7100B34CA8 /* close_preview@2x.png */,
|
||||
B2D23EA71D348F7100B34CA8 /* close_preview@3x.png */,
|
||||
84C7AFA61D52F75C00614703 /* ios-29x29.png */,
|
||||
);
|
||||
path = images;
|
||||
sourceTree = "<group>";
|
||||
@@ -168,6 +174,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6FD9F92833FE7856CDDD3CED /* libPods-LFLiveKitDemo.a */,
|
||||
91E73D3676F527F2A7BD7C6C /* libPods.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -179,12 +186,11 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B2D23E911D348F3D00B34CA8 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
|
||||
buildPhases = (
|
||||
6A9D2ED37E623D4A31A8D2C9 /* 📦 Check Pods Manifest.lock */,
|
||||
D4A28B8E7B3F14FE7B5CE784 /* Check Pods Manifest.lock */,
|
||||
B2D23E761D348F3D00B34CA8 /* Sources */,
|
||||
B2D23E771D348F3D00B34CA8 /* Frameworks */,
|
||||
B2D23E781D348F3D00B34CA8 /* Resources */,
|
||||
34EEB2C8F5E0D371D13B66CA /* 📦 Copy Pods Resources */,
|
||||
7336E9C92EDCA6C7449F2624 /* 📦 Embed Pods Frameworks */,
|
||||
3E1A58B9B801624E131D1416 /* Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -234,6 +240,7 @@
|
||||
files = (
|
||||
B2D23E8D1D348F3D00B34CA8 /* LaunchScreen.storyboard in Resources */,
|
||||
B2D23EAA1D348F7100B34CA8 /* Assets.xcassets in Resources */,
|
||||
84C7AFA71D52F75C00614703 /* ios-29x29.png in Resources */,
|
||||
B2D23EAC1D348F7100B34CA8 /* Main.storyboard in Resources */,
|
||||
B2D23EAB1D348F7100B34CA8 /* LaunchScreen.storyboard in Resources */,
|
||||
B2D23EB21D348F7100B34CA8 /* camra_beauty_close@3x.png in Resources */,
|
||||
@@ -251,29 +258,29 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
34EEB2C8F5E0D371D13B66CA /* 📦 Copy Pods Resources */ = {
|
||||
3E1A58B9B801624E131D1416 /* Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
name = "Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-resources.sh\"\n";
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
6A9D2ED37E623D4A31A8D2C9 /* 📦 Check Pods Manifest.lock */ = {
|
||||
D4A28B8E7B3F14FE7B5CE784 /* Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
name = "Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -281,21 +288,6 @@
|
||||
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;
|
||||
};
|
||||
7336E9C92EDCA6C7449F2624 /* 📦 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 */
|
||||
|
||||
Generated
BIN
Binary file not shown.
-5
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
</Bucket>
|
||||
Generated
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -156,7 +156,7 @@ inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
|
||||
|
||||
/*** 默认分辨率368 * 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Medium3 landscape:NO]];
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Low2 landscape:NO] captureType:LFLiveCaptureDefaultMask];
|
||||
|
||||
/** 自己定制单声道 */
|
||||
/*
|
||||
@@ -213,8 +213,8 @@ inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
videoConfiguration.landscape = NO;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
@@ -239,11 +239,18 @@ inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
*/
|
||||
|
||||
_session.delegate = self;
|
||||
_session.showDebugInfo = NO;
|
||||
_session.preView = self;
|
||||
|
||||
UIImageView *imageView = [[UIImageView alloc] init];
|
||||
imageView.alpha = 0.8;
|
||||
imageView.frame = CGRectMake(100, 100, 29, 29);
|
||||
imageView.image = [UIImage imageNamed:@"ios-29x29"];
|
||||
_session.warterMarkView = imageView;
|
||||
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
@@ -304,8 +311,8 @@ inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
_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 setImage:[UIImage imageNamed:@"camra_beauty"] forState:UIControlStateNormal];
|
||||
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty_close"] forState:UIControlStateSelected];
|
||||
_beautyButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_beautyButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
@@ -334,7 +341,7 @@ inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
if (_self.startLiveButton.selected) {
|
||||
[_self.startLiveButton setTitle:@"结束直播" forState:UIControlStateNormal];
|
||||
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
|
||||
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream123";
|
||||
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream153";
|
||||
[_self.session startLive:stream];
|
||||
} else {
|
||||
[_self.startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
@@ -2,6 +2,7 @@ source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios,'7.0'
|
||||
|
||||
target 'LFLiveKitDemo' do
|
||||
pod 'LFLiveKit', path: '../'
|
||||
|
||||
end
|
||||
|
||||
pod 'LFLiveKit', path: '../'
|
||||
|
||||
BIN
Binary file not shown.
@@ -1,10 +1,12 @@
|
||||
LFLiveKit
|
||||
==============
|
||||

|
||||
|
||||
|
||||
[](https://travis-ci.org/LaiFengiOS/LFLiveKit)
|
||||
[](https://raw.githubusercontent.com/chenliming777/LFLiveKit/master/LICENSE)
|
||||
[](http://cocoapods.org/?q=LFLiveKit)
|
||||
[](https://www.apple.com/nl/ios/)
|
||||
[](https://www.apple.com/nl/ios/)
|
||||

|
||||
|
||||
|
||||
@@ -24,9 +26,15 @@ LFLiveKit
|
||||
- [x] Switch camera position
|
||||
- [x] Audio Mute
|
||||
- [x] Support Send Buffer
|
||||
- [x] Support WaterMark
|
||||
- [x] Swift Support
|
||||
- [x] Support Single Video or Audio
|
||||
- [x] Support External input video or audio(Screen recording or Peripheral)
|
||||
- [ ] ~~FLV package and send~~
|
||||
|
||||
## Requirements
|
||||
- iOS 7.0+
|
||||
- Xcode 7.3
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -34,93 +42,96 @@ LFLiveKit
|
||||
# To integrate LFLiveKit into your Xcode project using CocoaPods, specify it in your Podfile:
|
||||
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '8.0'
|
||||
platform :ios, '7.0'
|
||||
pod 'LFLiveKit'
|
||||
|
||||
# Then, run the following command:
|
||||
$ pod install
|
||||
|
||||
|
||||
### Manually
|
||||
#### Carthage
|
||||
1. Add `github "LaiFengiOS/LFLiveKit"` to your Cartfile.
|
||||
2. Run `carthage update --platform ios` and add the framework to your project.
|
||||
3. Import \<LFLiveKit/LFLiveKit.h\>.
|
||||
|
||||
1. Download all the files in the `LFLiveKit` subdirectory.
|
||||
2. Add the source files to your Xcode project.
|
||||
3. Link with required frameworks:
|
||||
* UIKit
|
||||
* Foundation
|
||||
* AVFoundation
|
||||
* VideoToolbox
|
||||
* AudioToolbox
|
||||
* libz
|
||||
5. Add `LMGPUImage and pili-librtmp`(static library) to your Xcode project.
|
||||
|
||||
## Architecture:
|
||||
#### Manually
|
||||
|
||||
capture: LFAudioCapture and LFVideoCapture
|
||||
encode: LFHardwareAudioEncoder and LFHardwareVideoEncoder
|
||||
publish: LFStreamRtmpSocket
|
||||
1. Download all the files in the `LFLiveKit` subdirectory.
|
||||
2. Add the source files to your Xcode project.
|
||||
3. Link with required frameworks:
|
||||
* UIKit
|
||||
* Foundation
|
||||
* AVFoundation
|
||||
* VideoToolbox
|
||||
* AudioToolbox
|
||||
* libz
|
||||
|
||||
## Usage:
|
||||
## Usage example
|
||||
|
||||
#### Objective-C
|
||||
```
|
||||
- (LFLiveSession*)session {
|
||||
if (!_session) {
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
_session.preView = self;
|
||||
_session.delegate = self;
|
||||
|
||||
- (LFLiveSession*)session {
|
||||
if (!_session) {
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
_session.preView = self;
|
||||
_session.delegate = self;
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (void)startLive {
|
||||
LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
|
||||
streamInfo.url = @"your server rtmp url";
|
||||
[self.session startLive:streamInfo];
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (void)startLive {
|
||||
LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
|
||||
streamInfo.url = @"your server rtmp url";
|
||||
[self.session startLive:streamInfo];
|
||||
}
|
||||
|
||||
- (void)stopLive {
|
||||
[self.session stopLive];
|
||||
}
|
||||
- (void)stopLive {
|
||||
[self.session stopLive];
|
||||
}
|
||||
|
||||
//MARK: - CallBack:
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange: (LFLiveState)state;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
|
||||
//MARK: - CallBack:
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange: (LFLiveState)state;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
|
||||
```
|
||||
#### Swift
|
||||
|
||||
```
|
||||
// import LFLiveKit in [ProjectName]-Bridging-Header.h
|
||||
import <LFLiveKit.h>
|
||||
// import LFLiveKit in [ProjectName]-Bridging-Header.h
|
||||
import <LFLiveKit.h>
|
||||
|
||||
//MARK: - Getters and Setters
|
||||
lazy var session: LFLiveSession = {
|
||||
let audioConfiguration = LFLiveAudioConfiguration.defaultConfiguration()
|
||||
let videoConfiguration = LFLiveVideoConfiguration.defaultConfigurationForQuality(LFLiveVideoQuality.Low3, landscape: false)
|
||||
let session = LFLiveSession(audioConfiguration: audioConfiguration, videoConfiguration: videoConfiguration)
|
||||
|
||||
session?.delegate = self
|
||||
session?.preView = self.view
|
||||
return session!
|
||||
}()
|
||||
//MARK: - Getters and Setters
|
||||
lazy var session: LFLiveSession = {
|
||||
let audioConfiguration = LFLiveAudioConfiguration.defaultConfiguration()
|
||||
let videoConfiguration = LFLiveVideoConfiguration.defaultConfigurationForQuality(LFLiveVideoQuality.Low3, landscape: false)
|
||||
let session = LFLiveSession(audioConfiguration: audioConfiguration, videoConfiguration: videoConfiguration)
|
||||
|
||||
session?.delegate = self
|
||||
session?.preView = self.view
|
||||
return session!
|
||||
}()
|
||||
|
||||
//MARK: - Event
|
||||
func startLive() -> Void {
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "your server rtmp url";
|
||||
session.startLive(stream)
|
||||
}
|
||||
//MARK: - Event
|
||||
func startLive() -> Void {
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "your server rtmp url";
|
||||
session.startLive(stream)
|
||||
}
|
||||
|
||||
func stopLive() -> Void {
|
||||
session.stopLive()
|
||||
}
|
||||
func stopLive() -> Void {
|
||||
session.stopLive()
|
||||
}
|
||||
|
||||
//MARK: - Callback
|
||||
func liveSession(session: LFLiveSession?, debugInfo: LFLiveDebug?)
|
||||
func liveSession(session: LFLiveSession?, errorCode: LFLiveSocketErrorCode)
|
||||
func liveSession(session: LFLiveSession?, liveStateDidChange state: LFLiveState)
|
||||
|
||||
|
||||
## Release History
|
||||
* 2.0.0
|
||||
* CHANGE: modify bugs,support ios7 live.
|
||||
|
||||
//MARK: - Callback
|
||||
func liveSession(session: LFLiveSession?, debugInfo: LFLiveDebug?)
|
||||
func liveSession(session: LFLiveSession?, errorCode: LFLiveSocketErrorCode)
|
||||
func liveSession(session: LFLiveSession?, liveStateDidChange state: LFLiveState)
|
||||
```
|
||||
|
||||
## License
|
||||
**LFLiveKit is released under the MIT license. See LICENSE for details.**
|
||||
|
||||
Reference in New Issue
Block a user