Compare commits
162 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a805106ed2 | |||
| e1b8812b25 | |||
| a130058c5d | |||
| 3f804634c5 | |||
| 8b39f68a48 | |||
| 1d7b1f7073 | |||
| 47f35058f3 | |||
| a1a7e9aeea | |||
| fabae8ddd8 | |||
| 12e1066cae | |||
| 05ca0f4f4b | |||
| 9e536d2291 | |||
| 7bb976d4ae | |||
| 934d3f29ad | |||
| 87b3244ba5 | |||
| 23824e2b74 | |||
| 71d68c3e6e | |||
| d9887180c3 | |||
| 30eac1282c | |||
| 77d6a5b85b | |||
| 73c9adeb71 | |||
| 7dcda23bf4 | |||
| aa4f259edc | |||
| bc5dcef3b7 | |||
| 782b0c3c71 | |||
| 34a2fdd3e2 | |||
| ae128ab66b | |||
| cb164ed1fe | |||
| c40b99c19a | |||
| 2a48333a9a | |||
| 3c0c2eecb8 | |||
| 442f04124d | |||
| c03bd61f37 | |||
| 161c0acd68 | |||
| b7be132a30 | |||
| d30aecc802 | |||
| b612be76bc | |||
| a322e2aa3f | |||
| b0e88e182a | |||
| 3ebd933b6c | |||
| db0814ca4c | |||
| 3a9e0efb73 | |||
| 7bcc82a03e | |||
| 293e021cf6 | |||
| 340ab086d2 | |||
| f025f807f4 | |||
| 90b086c7a3 | |||
| cf56d72598 | |||
| b22f61c4e2 | |||
| 7d1311311c | |||
| a508cecc32 | |||
| 7657d27854 | |||
| 7c3aae8003 | |||
| 8c2596c23e | |||
| 681b1cd107 | |||
| 13094108e3 | |||
| abd55c5511 | |||
| fc52abe7bd | |||
| fa10e28281 | |||
| c624fbe78c | |||
| 19a355e697 | |||
| 7799f0f613 | |||
| ecf3b557cf | |||
| 58d83ed0dc | |||
| b167bda396 | |||
| 336a6e2432 | |||
| 8acddcda90 | |||
| cf2fc51fea | |||
| ae5f68661e | |||
| e30467dc13 | |||
| a217868694 | |||
| 3053a16cd3 | |||
| d2d7140312 | |||
| e93549619e | |||
| 0196b1be79 | |||
| 23ab30e668 | |||
| 42bd5c1f6b | |||
| 41393ffed8 | |||
| 2b236b2a35 | |||
| e59699b7fd | |||
| e9f3c66a3b | |||
| dc1dc18824 | |||
| 014e73f44c | |||
| ee7c25727b | |||
| 79f0ba930b | |||
| c5edbfba8e | |||
| 91c689a41f | |||
| ba48a45c0a | |||
| af09e79e74 | |||
| e4327de704 | |||
| 9760129763 | |||
| dc7f8d1d10 | |||
| 8f8bedb93d | |||
| 9428dc2c7f | |||
| e6c0d148ab | |||
| 0ca5c18c19 | |||
| cb98f0e70d | |||
| 06f1e40fba | |||
| dfbc4a51ff | |||
| f045bb14e4 | |||
| ebafc22eca | |||
| 6e3e92a6b9 | |||
| 26a47ffccc | |||
| e57d3e3806 | |||
| b73bfee6ac | |||
| 09398d0cb3 | |||
| f69b586d70 | |||
| cfb84d31fb | |||
| 984bcb8e15 | |||
| d7164f8b76 | |||
| fb7ad31bf0 | |||
| ec61b1f7ec | |||
| ba1280af3a | |||
| 9e99357113 | |||
| 8057a3e013 | |||
| 981b0dd2cd | |||
| d93d4b9bf5 | |||
| df6164fed1 | |||
| ba19663059 | |||
| 0967800b23 | |||
| d0ef23d887 | |||
| 807d83c263 | |||
| 28d20814f6 | |||
| 4c385f6e89 | |||
| 8708e04c0d | |||
| edcb2efaa0 | |||
| e47f3154a8 | |||
| 3842ff80bf | |||
| d3d5f6cb24 | |||
| 7062cdcf7c | |||
| 37bfd377d6 | |||
| bbe11292de | |||
| 2b51c69007 | |||
| eb0edf85d2 | |||
| 5b097680f9 | |||
| fb9ecaabad | |||
| 6a971f872f | |||
| c86a88487d | |||
| beac14592c | |||
| 24f8b42880 | |||
| 11848599b5 | |||
| d45e3770d6 | |||
| d883f023ca | |||
| 0d269dcf25 | |||
| 3b7ad944af | |||
| 3e92282448 | |||
| f2f25ea19d | |||
| b910e120ff | |||
| 3d5c88416b | |||
| 79744c0096 | |||
| 191a603f98 | |||
| fff7d4513d | |||
| 4f58fd019e | |||
| a440270bb0 | |||
| d57d987e67 | |||
| 204aaa6d09 | |||
| 3c58ff7e49 | |||
| 320307bc2a | |||
| 0e7b2475d7 | |||
| 531c92df51 | |||
| ba1f7a383c | |||
| 519b685855 |
@@ -1,4 +1,25 @@
|
||||
# infer
|
||||
infer-out/
|
||||
|
||||
#CocoaPods
|
||||
# Xcode
|
||||
.DS_Store
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
*.xcworkspace
|
||||
!default.xcworkspace
|
||||
xcuserdata
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
.idea/
|
||||
|
||||
# CocoaPods
|
||||
Pods/
|
||||
Podfile.lock
|
||||
@@ -1,7 +1,7 @@
|
||||
language: objective-c
|
||||
osx_image: xcode7
|
||||
xcode_workspace: LFLiveKit.xcworkspace
|
||||
xcode_project: FrameWork/LFLiveKit.xcodeproj
|
||||
xcode_scheme: LFLiveKit
|
||||
|
||||
script:
|
||||
- xctool -workspace LFLiveKit.xcworkspace -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
- xctool -project FrameWork/LFLiveKit.xcodeproj -scheme 'LFLiveKit' -configuration Release -sdk iphonesimulator -arch i386 build
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.7.3</string>
|
||||
<string>2.4.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@@ -0,0 +1,894 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
84D003751DB8FE1000560583 /* LFLiveKitFramework-universal */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 84D003761DB8FE1000560583 /* Build configuration list for PBXAggregateTarget "LFLiveKitFramework-universal" */;
|
||||
buildPhases = (
|
||||
84D0037B1DB8FE1C00560583 /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
84D0037A1DB8FE1800560583 /* PBXTargetDependency */,
|
||||
);
|
||||
name = "LFLiveKitFramework-universal";
|
||||
productName = "LFLiveKitFramework-universal";
|
||||
};
|
||||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8495F66F1DB8F14600542124 /* LFLiveKitFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6731DB8F1EE00542124 /* LFAudioCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5851D768B6E00752B56 /* LFAudioCapture.h */; };
|
||||
8495F6741DB8F1EE00542124 /* LFVideoCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5871D768B6E00752B56 /* LFVideoCapture.h */; };
|
||||
8495F6751DB8F1EE00542124 /* LFAVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */; };
|
||||
8495F6761DB8F1EE00542124 /* LFMP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */; };
|
||||
8495F6771DB8F1EE00542124 /* LFNALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5901D768B6E00752B56 /* LFNALUnit.h */; };
|
||||
8495F6781DB8F1EE00542124 /* LFVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */; };
|
||||
8495F6791DB8F1EE00542124 /* LFAudioEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */; };
|
||||
8495F67A1DB8F1EE00542124 /* LFH264VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */; };
|
||||
8495F67B1DB8F1EE00542124 /* LFHardwareAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */; };
|
||||
8495F67C1DB8F1EE00542124 /* LFHardwareVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */; };
|
||||
8495F67D1DB8F1EE00542124 /* LFVideoEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */; };
|
||||
8495F67E1DB8F1EE00542124 /* LFLiveAudioConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F67F1DB8F1EE00542124 /* LFLiveVideoConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6801DB8F1EE00542124 /* LFGPUImageBeautyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */; };
|
||||
8495F6811DB8F1EE00542124 /* LFGPUImageEmptyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */; };
|
||||
8495F6831DB8F1EE00542124 /* LFLiveSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A61D768B6E00752B56 /* LFLiveSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6841DB8F1EE00542124 /* LFAudioFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6851DB8F1EE00542124 /* LFFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AB1D768B6E00752B56 /* LFFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6861DB8F1EE00542124 /* LFLiveDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6871DB8F1EE00542124 /* LFLiveStreamInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6881DB8F1EE00542124 /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8495F6891DB8F1EE00542124 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */; };
|
||||
8495F68A1DB8F1EE00542124 /* LFStreamRTMPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */; };
|
||||
8495F68B1DB8F1EE00542124 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */; };
|
||||
8495F68C1DB8F1EE00542124 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */; };
|
||||
8495F68D1DB8F27000542124 /* LFAudioCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5861D768B6E00752B56 /* LFAudioCapture.m */; };
|
||||
8495F68E1DB8F27000542124 /* LFVideoCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5881D768B6E00752B56 /* LFVideoCapture.m */; };
|
||||
8495F68F1DB8F27000542124 /* LFAVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */; };
|
||||
8495F6901DB8F27000542124 /* LFMP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */; };
|
||||
8495F6911DB8F27000542124 /* LFVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */; };
|
||||
8495F6921DB8F27000542124 /* LFH264VideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */; };
|
||||
8495F6931DB8F27000542124 /* LFHardwareAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */; };
|
||||
8495F6941DB8F27000542124 /* LFHardwareVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */; };
|
||||
8495F6951DB8F27000542124 /* LFLiveAudioConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */; };
|
||||
8495F6961DB8F27000542124 /* LFLiveVideoConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */; };
|
||||
8495F6971DB8F27000542124 /* LFGPUImageBeautyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */; };
|
||||
8495F6981DB8F27000542124 /* LFGPUImageEmptyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */; };
|
||||
8495F6991DB8F27000542124 /* LFLiveSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A71D768B6E00752B56 /* LFLiveSession.m */; };
|
||||
8495F69A1DB8F27000542124 /* LFAudioFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */; };
|
||||
8495F69B1DB8F27000542124 /* LFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AC1D768B6E00752B56 /* LFFrame.m */; };
|
||||
8495F69C1DB8F27000542124 /* LFLiveDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */; };
|
||||
8495F69D1DB8F27000542124 /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */; };
|
||||
8495F69E1DB8F27000542124 /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */; };
|
||||
8495F69F1DB8F27000542124 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */; };
|
||||
8495F6A01DB8F27000542124 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */; };
|
||||
8495F6A11DB8F27000542124 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */; };
|
||||
84D0036F1DB8F88F00560583 /* LFNALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */; };
|
||||
84D8B4BF1D757EB800752B56 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */; };
|
||||
84D8B4C11D757EBE00752B56 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */; };
|
||||
84D8B4C31D757EC400752B56 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C21D757EC400752B56 /* AVFoundation.framework */; };
|
||||
84D8B4C51D757EC800752B56 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C41D757EC800752B56 /* Foundation.framework */; };
|
||||
84D8B4C71D757ECC00752B56 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4C61D757ECC00752B56 /* UIKit.framework */; };
|
||||
84D8B5BB1D768B6E00752B56 /* LFAudioCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5851D768B6E00752B56 /* LFAudioCapture.h */; };
|
||||
84D8B5BC1D768B6E00752B56 /* LFAudioCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5861D768B6E00752B56 /* LFAudioCapture.m */; };
|
||||
84D8B5BD1D768B6E00752B56 /* LFVideoCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5871D768B6E00752B56 /* LFVideoCapture.h */; };
|
||||
84D8B5BE1D768B6E00752B56 /* LFVideoCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5881D768B6E00752B56 /* LFVideoCapture.m */; };
|
||||
84D8B5BF1D768B6E00752B56 /* LFAVEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */; };
|
||||
84D8B5C01D768B6E00752B56 /* LFAVEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */; };
|
||||
84D8B5C11D768B6E00752B56 /* LFMP4Atom.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */; };
|
||||
84D8B5C21D768B6E00752B56 /* LFMP4Atom.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */; };
|
||||
84D8B5C31D768B6E00752B56 /* LFNALUnit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */; };
|
||||
84D8B5C41D768B6E00752B56 /* LFNALUnit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5901D768B6E00752B56 /* LFNALUnit.h */; };
|
||||
84D8B5C51D768B6E00752B56 /* LFVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */; };
|
||||
84D8B5C61D768B6E00752B56 /* LFVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */; };
|
||||
84D8B5C71D768B6E00752B56 /* LFAudioEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */; };
|
||||
84D8B5C81D768B6E00752B56 /* LFH264VideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */; };
|
||||
84D8B5C91D768B6E00752B56 /* LFH264VideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */; };
|
||||
84D8B5CA1D768B6E00752B56 /* LFHardwareAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */; };
|
||||
84D8B5CB1D768B6E00752B56 /* LFHardwareAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */; };
|
||||
84D8B5CC1D768B6E00752B56 /* LFHardwareVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */; };
|
||||
84D8B5CD1D768B6E00752B56 /* LFHardwareVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */; };
|
||||
84D8B5CE1D768B6E00752B56 /* LFVideoEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */; };
|
||||
84D8B5CF1D768B6E00752B56 /* LFLiveAudioConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D01D768B6E00752B56 /* LFLiveAudioConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */; };
|
||||
84D8B5D11D768B6E00752B56 /* LFLiveVideoConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D21D768B6E00752B56 /* LFLiveVideoConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */; };
|
||||
84D8B5D31D768B6E00752B56 /* LFGPUImageBeautyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */; };
|
||||
84D8B5D41D768B6E00752B56 /* LFGPUImageBeautyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */; };
|
||||
84D8B5D51D768B6E00752B56 /* LFGPUImageEmptyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */; };
|
||||
84D8B5D61D768B6E00752B56 /* LFGPUImageEmptyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */; };
|
||||
84D8B5D71D768B6E00752B56 /* LFLiveKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A51D768B6E00752B56 /* LFLiveKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D81D768B6E00752B56 /* LFLiveSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A61D768B6E00752B56 /* LFLiveSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5D91D768B6E00752B56 /* LFLiveSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5A71D768B6E00752B56 /* LFLiveSession.m */; };
|
||||
84D8B5DA1D768B6E00752B56 /* LFAudioFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DB1D768B6E00752B56 /* LFAudioFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */; };
|
||||
84D8B5DC1D768B6E00752B56 /* LFFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AB1D768B6E00752B56 /* LFFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DD1D768B6E00752B56 /* LFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AC1D768B6E00752B56 /* LFFrame.m */; };
|
||||
84D8B5DE1D768B6E00752B56 /* LFLiveDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5DF1D768B6E00752B56 /* LFLiveDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */; };
|
||||
84D8B5E01D768B6E00752B56 /* LFLiveStreamInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5E11D768B6E00752B56 /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */; };
|
||||
84D8B5E21D768B6E00752B56 /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84D8B5E31D768B6E00752B56 /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */; };
|
||||
84D8B5E41D768B6E00752B56 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */; };
|
||||
84D8B5E51D768B6E00752B56 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */; };
|
||||
84D8B5E61D768B6E00752B56 /* LFStreamRTMPSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */; };
|
||||
84D8B5E71D768B6E00752B56 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */; };
|
||||
84D8B5E81D768B6E00752B56 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */; };
|
||||
84D8B5E91D768B6E00752B56 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */; };
|
||||
84D8B5EA1D768B6E00752B56 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
84D003791DB8FE1800560583 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84D8B3871D7574D600752B56 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8495F66A1DB8F14600542124;
|
||||
remoteInfo = LFLiveKitFramework;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8495F66B1DB8F14600542124 /* LFLiveKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LFLiveKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LFLiveKitFramework.h; sourceTree = "<group>"; };
|
||||
8495F66E1DB8F14600542124 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
84D8B3901D7574D600752B56 /* LFLiveKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LFLiveKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C21D757EC400752B56 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C41D757EC800752B56 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C61D757ECC00752B56 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
84D8B4C81D757ED100752B56 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
|
||||
84D8B4CA1D757ED600752B56 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
84D8B5851D768B6E00752B56 /* LFAudioCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioCapture.h; sourceTree = "<group>"; };
|
||||
84D8B5861D768B6E00752B56 /* LFAudioCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioCapture.m; sourceTree = "<group>"; };
|
||||
84D8B5871D768B6E00752B56 /* LFVideoCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoCapture.h; sourceTree = "<group>"; };
|
||||
84D8B5881D768B6E00752B56 /* LFVideoCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoCapture.m; sourceTree = "<group>"; };
|
||||
84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAVEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFAVEncoder.mm; sourceTree = "<group>"; };
|
||||
84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFMP4Atom.h; sourceTree = "<group>"; };
|
||||
84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFMP4Atom.m; sourceTree = "<group>"; };
|
||||
84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LFNALUnit.cpp; sourceTree = "<group>"; };
|
||||
84D8B5901D768B6E00752B56 /* LFNALUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFNALUnit.h; sourceTree = "<group>"; };
|
||||
84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioEncoding.h; sourceTree = "<group>"; };
|
||||
84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFH264VideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LFH264VideoEncoder.mm; sourceTree = "<group>"; };
|
||||
84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareAudioEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareAudioEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareVideoEncoder.h; sourceTree = "<group>"; };
|
||||
84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareVideoEncoder.m; sourceTree = "<group>"; };
|
||||
84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoding.h; sourceTree = "<group>"; };
|
||||
84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveAudioConfiguration.h; sourceTree = "<group>"; };
|
||||
84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveAudioConfiguration.m; sourceTree = "<group>"; };
|
||||
84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveVideoConfiguration.h; sourceTree = "<group>"; };
|
||||
84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveVideoConfiguration.m; sourceTree = "<group>"; };
|
||||
84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageBeautyFilter.h; sourceTree = "<group>"; };
|
||||
84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageBeautyFilter.m; sourceTree = "<group>"; };
|
||||
84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageEmptyFilter.h; sourceTree = "<group>"; };
|
||||
84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageEmptyFilter.m; sourceTree = "<group>"; };
|
||||
84D8B5A51D768B6E00752B56 /* LFLiveKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveKit.h; sourceTree = "<group>"; };
|
||||
84D8B5A61D768B6E00752B56 /* LFLiveSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveSession.h; sourceTree = "<group>"; };
|
||||
84D8B5A71D768B6E00752B56 /* LFLiveSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveSession.m; sourceTree = "<group>"; };
|
||||
84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5AB1D768B6E00752B56 /* LFFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5AC1D768B6E00752B56 /* LFFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveDebug.h; sourceTree = "<group>"; };
|
||||
84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveDebug.m; sourceTree = "<group>"; };
|
||||
84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveStreamInfo.h; sourceTree = "<group>"; };
|
||||
84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveStreamInfo.m; sourceTree = "<group>"; };
|
||||
84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoFrame.h; sourceTree = "<group>"; };
|
||||
84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoFrame.m; sourceTree = "<group>"; };
|
||||
84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamingBuffer.h; sourceTree = "<group>"; };
|
||||
84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamingBuffer.m; sourceTree = "<group>"; };
|
||||
84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamRTMPSocket.h; sourceTree = "<group>"; };
|
||||
84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamRtmpSocket.m; sourceTree = "<group>"; };
|
||||
84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamSocket.h; sourceTree = "<group>"; };
|
||||
84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+LFAdd.h"; sourceTree = "<group>"; };
|
||||
84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+LFAdd.m"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8495F6671DB8F14600542124 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38C1D7574D600752B56 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B4C71D757ECC00752B56 /* UIKit.framework in Frameworks */,
|
||||
84D8B4C51D757EC800752B56 /* Foundation.framework in Frameworks */,
|
||||
84D8B4C31D757EC400752B56 /* AVFoundation.framework in Frameworks */,
|
||||
84D8B4C11D757EBE00752B56 /* AudioToolbox.framework in Frameworks */,
|
||||
84D8B4BF1D757EB800752B56 /* VideoToolbox.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
8495F66C1DB8F14600542124 /* LFLiveKitFramework */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8495F66D1DB8F14600542124 /* LFLiveKitFramework.h */,
|
||||
8495F66E1DB8F14600542124 /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKitFramework;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B3861D7574D600752B56 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5831D768B6E00752B56 /* LFLiveKit */,
|
||||
84D8B4CA1D757ED600752B56 /* libz.tbd */,
|
||||
84D8B4C81D757ED100752B56 /* libstdc++.tbd */,
|
||||
84D8B4C61D757ECC00752B56 /* UIKit.framework */,
|
||||
84D8B4C41D757EC800752B56 /* Foundation.framework */,
|
||||
84D8B4C21D757EC400752B56 /* AVFoundation.framework */,
|
||||
84D8B4C01D757EBE00752B56 /* AudioToolbox.framework */,
|
||||
84D8B4BE1D757EB800752B56 /* VideoToolbox.framework */,
|
||||
8495F66C1DB8F14600542124 /* LFLiveKitFramework */,
|
||||
84D8B3911D7574D600752B56 /* Products */,
|
||||
9ABACAFFC334034AA0115426 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B3911D7574D600752B56 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B3901D7574D600752B56 /* LFLiveKit.framework */,
|
||||
8495F66B1DB8F14600542124 /* LFLiveKit.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5831D768B6E00752B56 /* LFLiveKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5841D768B6E00752B56 /* capture */,
|
||||
84D8B5891D768B6E00752B56 /* coder */,
|
||||
84D8B59B1D768B6E00752B56 /* configuration */,
|
||||
84D8B5A01D768B6E00752B56 /* filter */,
|
||||
84D8B5A51D768B6E00752B56 /* LFLiveKit.h */,
|
||||
84D8B5A61D768B6E00752B56 /* LFLiveSession.h */,
|
||||
84D8B5A71D768B6E00752B56 /* LFLiveSession.m */,
|
||||
84D8B5A81D768B6E00752B56 /* objects */,
|
||||
84D8B5B31D768B6E00752B56 /* publish */,
|
||||
);
|
||||
name = LFLiveKit;
|
||||
path = ../LFLiveKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5841D768B6E00752B56 /* capture */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5851D768B6E00752B56 /* LFAudioCapture.h */,
|
||||
84D8B5861D768B6E00752B56 /* LFAudioCapture.m */,
|
||||
84D8B5871D768B6E00752B56 /* LFVideoCapture.h */,
|
||||
84D8B5881D768B6E00752B56 /* LFVideoCapture.m */,
|
||||
);
|
||||
path = capture;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5891D768B6E00752B56 /* coder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B58A1D768B6E00752B56 /* H264 */,
|
||||
84D8B5931D768B6E00752B56 /* LFAudioEncoding.h */,
|
||||
84D8B5941D768B6E00752B56 /* LFH264VideoEncoder.h */,
|
||||
84D8B5951D768B6E00752B56 /* LFH264VideoEncoder.mm */,
|
||||
84D8B5961D768B6E00752B56 /* LFHardwareAudioEncoder.h */,
|
||||
84D8B5971D768B6E00752B56 /* LFHardwareAudioEncoder.m */,
|
||||
84D8B5981D768B6E00752B56 /* LFHardwareVideoEncoder.h */,
|
||||
84D8B5991D768B6E00752B56 /* LFHardwareVideoEncoder.m */,
|
||||
84D8B59A1D768B6E00752B56 /* LFVideoEncoding.h */,
|
||||
);
|
||||
path = coder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B58A1D768B6E00752B56 /* H264 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B58B1D768B6E00752B56 /* LFAVEncoder.h */,
|
||||
84D8B58C1D768B6E00752B56 /* LFAVEncoder.mm */,
|
||||
84D8B58D1D768B6E00752B56 /* LFMP4Atom.h */,
|
||||
84D8B58E1D768B6E00752B56 /* LFMP4Atom.m */,
|
||||
84D8B58F1D768B6E00752B56 /* LFNALUnit.cpp */,
|
||||
84D8B5901D768B6E00752B56 /* LFNALUnit.h */,
|
||||
84D8B5911D768B6E00752B56 /* LFVideoEncoder.h */,
|
||||
84D8B5921D768B6E00752B56 /* LFVideoEncoder.m */,
|
||||
);
|
||||
path = H264;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B59B1D768B6E00752B56 /* configuration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B59C1D768B6E00752B56 /* LFLiveAudioConfiguration.h */,
|
||||
84D8B59D1D768B6E00752B56 /* LFLiveAudioConfiguration.m */,
|
||||
84D8B59E1D768B6E00752B56 /* LFLiveVideoConfiguration.h */,
|
||||
84D8B59F1D768B6E00752B56 /* LFLiveVideoConfiguration.m */,
|
||||
);
|
||||
path = configuration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5A01D768B6E00752B56 /* filter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5A11D768B6E00752B56 /* LFGPUImageBeautyFilter.h */,
|
||||
84D8B5A21D768B6E00752B56 /* LFGPUImageBeautyFilter.m */,
|
||||
84D8B5A31D768B6E00752B56 /* LFGPUImageEmptyFilter.h */,
|
||||
84D8B5A41D768B6E00752B56 /* LFGPUImageEmptyFilter.m */,
|
||||
);
|
||||
path = filter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5A81D768B6E00752B56 /* objects */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5A91D768B6E00752B56 /* LFAudioFrame.h */,
|
||||
84D8B5AA1D768B6E00752B56 /* LFAudioFrame.m */,
|
||||
84D8B5AB1D768B6E00752B56 /* LFFrame.h */,
|
||||
84D8B5AC1D768B6E00752B56 /* LFFrame.m */,
|
||||
84D8B5AD1D768B6E00752B56 /* LFLiveDebug.h */,
|
||||
84D8B5AE1D768B6E00752B56 /* LFLiveDebug.m */,
|
||||
84D8B5AF1D768B6E00752B56 /* LFLiveStreamInfo.h */,
|
||||
84D8B5B01D768B6E00752B56 /* LFLiveStreamInfo.m */,
|
||||
84D8B5B11D768B6E00752B56 /* LFVideoFrame.h */,
|
||||
84D8B5B21D768B6E00752B56 /* LFVideoFrame.m */,
|
||||
);
|
||||
path = objects;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B5B31D768B6E00752B56 /* publish */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84D8B5B41D768B6E00752B56 /* LFStreamingBuffer.h */,
|
||||
84D8B5B51D768B6E00752B56 /* LFStreamingBuffer.m */,
|
||||
84D8B5B61D768B6E00752B56 /* LFStreamRTMPSocket.h */,
|
||||
84D8B5B71D768B6E00752B56 /* LFStreamRtmpSocket.m */,
|
||||
84D8B5B81D768B6E00752B56 /* LFStreamSocket.h */,
|
||||
84D8B5B91D768B6E00752B56 /* NSMutableArray+LFAdd.h */,
|
||||
84D8B5BA1D768B6E00752B56 /* NSMutableArray+LFAdd.m */,
|
||||
);
|
||||
path = publish;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9ABACAFFC334034AA0115426 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
8495F6681DB8F14600542124 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8495F6861DB8F1EE00542124 /* LFLiveDebug.h in Headers */,
|
||||
8495F6881DB8F1EE00542124 /* LFVideoFrame.h in Headers */,
|
||||
8495F6871DB8F1EE00542124 /* LFLiveStreamInfo.h in Headers */,
|
||||
8495F6851DB8F1EE00542124 /* LFFrame.h in Headers */,
|
||||
8495F6841DB8F1EE00542124 /* LFAudioFrame.h in Headers */,
|
||||
8495F67F1DB8F1EE00542124 /* LFLiveVideoConfiguration.h in Headers */,
|
||||
8495F67E1DB8F1EE00542124 /* LFLiveAudioConfiguration.h in Headers */,
|
||||
8495F6831DB8F1EE00542124 /* LFLiveSession.h in Headers */,
|
||||
8495F66F1DB8F14600542124 /* LFLiveKitFramework.h in Headers */,
|
||||
8495F6731DB8F1EE00542124 /* LFAudioCapture.h in Headers */,
|
||||
8495F6741DB8F1EE00542124 /* LFVideoCapture.h in Headers */,
|
||||
8495F6751DB8F1EE00542124 /* LFAVEncoder.h in Headers */,
|
||||
8495F6761DB8F1EE00542124 /* LFMP4Atom.h in Headers */,
|
||||
8495F6771DB8F1EE00542124 /* LFNALUnit.h in Headers */,
|
||||
8495F6781DB8F1EE00542124 /* LFVideoEncoder.h in Headers */,
|
||||
8495F6791DB8F1EE00542124 /* LFAudioEncoding.h in Headers */,
|
||||
8495F67A1DB8F1EE00542124 /* LFH264VideoEncoder.h in Headers */,
|
||||
8495F67B1DB8F1EE00542124 /* LFHardwareAudioEncoder.h in Headers */,
|
||||
8495F67C1DB8F1EE00542124 /* LFHardwareVideoEncoder.h in Headers */,
|
||||
8495F67D1DB8F1EE00542124 /* LFVideoEncoding.h in Headers */,
|
||||
8495F6801DB8F1EE00542124 /* LFGPUImageBeautyFilter.h in Headers */,
|
||||
8495F6811DB8F1EE00542124 /* LFGPUImageEmptyFilter.h in Headers */,
|
||||
8495F6891DB8F1EE00542124 /* LFStreamingBuffer.h in Headers */,
|
||||
8495F68A1DB8F1EE00542124 /* LFStreamRTMPSocket.h in Headers */,
|
||||
8495F68B1DB8F1EE00542124 /* LFStreamSocket.h in Headers */,
|
||||
8495F68C1DB8F1EE00542124 /* NSMutableArray+LFAdd.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38D1D7574D600752B56 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B5DE1D768B6E00752B56 /* LFLiveDebug.h in Headers */,
|
||||
84D8B5CF1D768B6E00752B56 /* LFLiveAudioConfiguration.h in Headers */,
|
||||
84D8B5DA1D768B6E00752B56 /* LFAudioFrame.h in Headers */,
|
||||
84D8B5E01D768B6E00752B56 /* LFLiveStreamInfo.h in Headers */,
|
||||
84D8B5D11D768B6E00752B56 /* LFLiveVideoConfiguration.h in Headers */,
|
||||
84D8B5DC1D768B6E00752B56 /* LFFrame.h in Headers */,
|
||||
84D8B5D71D768B6E00752B56 /* LFLiveKit.h in Headers */,
|
||||
84D8B5D81D768B6E00752B56 /* LFLiveSession.h in Headers */,
|
||||
84D8B5E21D768B6E00752B56 /* LFVideoFrame.h in Headers */,
|
||||
84D8B5BB1D768B6E00752B56 /* LFAudioCapture.h in Headers */,
|
||||
84D8B5E61D768B6E00752B56 /* LFStreamRTMPSocket.h in Headers */,
|
||||
84D8B5C11D768B6E00752B56 /* LFMP4Atom.h in Headers */,
|
||||
84D8B5D31D768B6E00752B56 /* LFGPUImageBeautyFilter.h in Headers */,
|
||||
84D8B5BF1D768B6E00752B56 /* LFAVEncoder.h in Headers */,
|
||||
84D8B5C51D768B6E00752B56 /* LFVideoEncoder.h in Headers */,
|
||||
84D8B5D51D768B6E00752B56 /* LFGPUImageEmptyFilter.h in Headers */,
|
||||
84D8B5C71D768B6E00752B56 /* LFAudioEncoding.h in Headers */,
|
||||
84D8B5E91D768B6E00752B56 /* NSMutableArray+LFAdd.h in Headers */,
|
||||
84D8B5CC1D768B6E00752B56 /* LFHardwareVideoEncoder.h in Headers */,
|
||||
84D8B5BD1D768B6E00752B56 /* LFVideoCapture.h in Headers */,
|
||||
84D8B5E81D768B6E00752B56 /* LFStreamSocket.h in Headers */,
|
||||
84D8B5C41D768B6E00752B56 /* LFNALUnit.h in Headers */,
|
||||
84D8B5CA1D768B6E00752B56 /* LFHardwareAudioEncoder.h in Headers */,
|
||||
84D8B5CE1D768B6E00752B56 /* LFVideoEncoding.h in Headers */,
|
||||
84D8B5E41D768B6E00752B56 /* LFStreamingBuffer.h in Headers */,
|
||||
84D8B5C81D768B6E00752B56 /* LFH264VideoEncoder.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8495F66A1DB8F14600542124 /* LFLiveKitFramework */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 8495F6701DB8F14600542124 /* Build configuration list for PBXNativeTarget "LFLiveKitFramework" */;
|
||||
buildPhases = (
|
||||
8495F6661DB8F14600542124 /* Sources */,
|
||||
8495F6671DB8F14600542124 /* Frameworks */,
|
||||
8495F6681DB8F14600542124 /* Headers */,
|
||||
8495F6691DB8F14600542124 /* Resources */,
|
||||
84D0037D1DB9023F00560583 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKitFramework;
|
||||
productName = LFLiveKitFramework;
|
||||
productReference = 8495F66B1DB8F14600542124 /* LFLiveKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
84D8B38F1D7574D600752B56 /* LFLiveKit */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 84D8B3981D7574D600752B56 /* Build configuration list for PBXNativeTarget "LFLiveKit" */;
|
||||
buildPhases = (
|
||||
84D8B38B1D7574D600752B56 /* Sources */,
|
||||
84D8B38C1D7574D600752B56 /* Frameworks */,
|
||||
84D8B38D1D7574D600752B56 /* Headers */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKit;
|
||||
productName = LFLiveKit;
|
||||
productReference = 84D8B3901D7574D600752B56 /* LFLiveKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
84D8B3871D7574D600752B56 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = admin;
|
||||
TargetAttributes = {
|
||||
8495F66A1DB8F14600542124 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
84D003751DB8FE1000560583 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
DevelopmentTeam = G497YX6CBT;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
84D8B38F1D7574D600752B56 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 84D8B38A1D7574D600752B56 /* Build configuration list for PBXProject "LFLiveKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 84D8B3861D7574D600752B56;
|
||||
productRefGroup = 84D8B3911D7574D600752B56 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
84D8B38F1D7574D600752B56 /* LFLiveKit */,
|
||||
8495F66A1DB8F14600542124 /* LFLiveKitFramework */,
|
||||
84D003751DB8FE1000560583 /* LFLiveKitFramework-universal */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8495F6691DB8F14600542124 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
84D0037B1DB8FE1C00560583 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../scripts/build-universal-framework.sh\n";
|
||||
};
|
||||
84D0037D1DB9023F00560583 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "echo \"${env}\"";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8495F6661DB8F14600542124 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D0036F1DB8F88F00560583 /* LFNALUnit.cpp in Sources */,
|
||||
8495F68D1DB8F27000542124 /* LFAudioCapture.m in Sources */,
|
||||
8495F68E1DB8F27000542124 /* LFVideoCapture.m in Sources */,
|
||||
8495F68F1DB8F27000542124 /* LFAVEncoder.mm in Sources */,
|
||||
8495F6901DB8F27000542124 /* LFMP4Atom.m in Sources */,
|
||||
8495F6911DB8F27000542124 /* LFVideoEncoder.m in Sources */,
|
||||
8495F6921DB8F27000542124 /* LFH264VideoEncoder.mm in Sources */,
|
||||
8495F6931DB8F27000542124 /* LFHardwareAudioEncoder.m in Sources */,
|
||||
8495F6941DB8F27000542124 /* LFHardwareVideoEncoder.m in Sources */,
|
||||
8495F6951DB8F27000542124 /* LFLiveAudioConfiguration.m in Sources */,
|
||||
8495F6961DB8F27000542124 /* LFLiveVideoConfiguration.m in Sources */,
|
||||
8495F6971DB8F27000542124 /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
8495F6981DB8F27000542124 /* LFGPUImageEmptyFilter.m in Sources */,
|
||||
8495F6991DB8F27000542124 /* LFLiveSession.m in Sources */,
|
||||
8495F69A1DB8F27000542124 /* LFAudioFrame.m in Sources */,
|
||||
8495F69B1DB8F27000542124 /* LFFrame.m in Sources */,
|
||||
8495F69C1DB8F27000542124 /* LFLiveDebug.m in Sources */,
|
||||
8495F69D1DB8F27000542124 /* LFLiveStreamInfo.m in Sources */,
|
||||
8495F69E1DB8F27000542124 /* LFVideoFrame.m in Sources */,
|
||||
8495F69F1DB8F27000542124 /* LFStreamingBuffer.m in Sources */,
|
||||
8495F6A01DB8F27000542124 /* LFStreamRtmpSocket.m in Sources */,
|
||||
8495F6A11DB8F27000542124 /* NSMutableArray+LFAdd.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84D8B38B1D7574D600752B56 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84D8B5D41D768B6E00752B56 /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
84D8B5DD1D768B6E00752B56 /* LFFrame.m in Sources */,
|
||||
84D8B5DF1D768B6E00752B56 /* LFLiveDebug.m in Sources */,
|
||||
84D8B5BE1D768B6E00752B56 /* LFVideoCapture.m in Sources */,
|
||||
84D8B5DB1D768B6E00752B56 /* LFAudioFrame.m in Sources */,
|
||||
84D8B5E11D768B6E00752B56 /* LFLiveStreamInfo.m in Sources */,
|
||||
84D8B5C31D768B6E00752B56 /* LFNALUnit.cpp in Sources */,
|
||||
84D8B5C01D768B6E00752B56 /* LFAVEncoder.mm in Sources */,
|
||||
84D8B5C21D768B6E00752B56 /* LFMP4Atom.m in Sources */,
|
||||
84D8B5D21D768B6E00752B56 /* LFLiveVideoConfiguration.m in Sources */,
|
||||
84D8B5C61D768B6E00752B56 /* LFVideoEncoder.m in Sources */,
|
||||
84D8B5D61D768B6E00752B56 /* LFGPUImageEmptyFilter.m in Sources */,
|
||||
84D8B5D91D768B6E00752B56 /* LFLiveSession.m in Sources */,
|
||||
84D8B5E71D768B6E00752B56 /* LFStreamRtmpSocket.m in Sources */,
|
||||
84D8B5D01D768B6E00752B56 /* LFLiveAudioConfiguration.m in Sources */,
|
||||
84D8B5CB1D768B6E00752B56 /* LFHardwareAudioEncoder.m in Sources */,
|
||||
84D8B5C91D768B6E00752B56 /* LFH264VideoEncoder.mm in Sources */,
|
||||
84D8B5E51D768B6E00752B56 /* LFStreamingBuffer.m in Sources */,
|
||||
84D8B5CD1D768B6E00752B56 /* LFHardwareVideoEncoder.m in Sources */,
|
||||
84D8B5E31D768B6E00752B56 /* LFVideoFrame.m in Sources */,
|
||||
84D8B5BC1D768B6E00752B56 /* LFAudioCapture.m in Sources */,
|
||||
84D8B5EA1D768B6E00752B56 /* NSMutableArray+LFAdd.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
84D0037A1DB8FE1800560583 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 8495F66A1DB8F14600542124 /* LFLiveKitFramework */;
|
||||
targetProxy = 84D003791DB8FE1800560583 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
8495F6711DB8F14600542124 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework/Headers\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework/Headers\"",
|
||||
);
|
||||
INFOPLIST_FILE = LFLiveKitFramework/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = LFLiveKit;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8495F6721DB8F14600542124 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework\"",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/GPUImage.framework/Headers\"",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitFrameworkDemo/vendors/pili-librtmp.framework/Headers\"",
|
||||
);
|
||||
INFOPLIST_FILE = LFLiveKitFramework/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = LFLiveKit;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D003771DB8FE1000560583 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D003781DB8FE1000560583 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D8B3961D7574D600752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B3971D7574D600752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84D8B3991D7574D600752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitDemo/Pods\"/**",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84D8B39A1D7574D600752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"\"$(SRCROOT)/../samples/LFLiveKitDemo/Pods\"/**",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
MACH_O_TYPE = staticlib;
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
8495F6701DB8F14600542124 /* Build configuration list for PBXNativeTarget "LFLiveKitFramework" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
8495F6711DB8F14600542124 /* Debug */,
|
||||
8495F6721DB8F14600542124 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D003761DB8FE1000560583 /* Build configuration list for PBXAggregateTarget "LFLiveKitFramework-universal" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D003771DB8FE1000560583 /* Debug */,
|
||||
84D003781DB8FE1000560583 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D8B38A1D7574D600752B56 /* Build configuration list for PBXProject "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B3961D7574D600752B56 /* Debug */,
|
||||
84D8B3971D7574D600752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84D8B3981D7574D600752B56 /* Build configuration list for PBXNativeTarget "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84D8B3991D7574D600752B56 /* Debug */,
|
||||
84D8B39A1D7574D600752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 84D8B3871D7574D600752B56 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84D8B38F1D7574D600752B56"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -13,12 +13,12 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<string>2.4.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// LFLiveKitFramework.h
|
||||
// LFLiveKitFramework
|
||||
//
|
||||
// Created by admin on 2016/10/20.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for LFLiveKitFramework.
|
||||
FOUNDATION_EXPORT double LFLiveKitFrameworkVersionNumber;
|
||||
|
||||
//! Project version string for LFLiveKitFramework.
|
||||
FOUNDATION_EXPORT const unsigned char LFLiveKitFrameworkVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <LFLiveKitFramework/PublicHeader.h>
|
||||
|
||||
#import <LFLiveKit/LFLiveSession.h>
|
||||
#import <LFLiveKit/LFLiveAudioConfiguration.h>
|
||||
#import <LFLiveKit/LFLiveVideoConfiguration.h>
|
||||
#import <LFLiveKit/LFAudioFrame.h>
|
||||
#import <LFLiveKit/LFFrame.h>
|
||||
#import <LFLiveKit/LFLiveStreamInfo.h>
|
||||
#import <LFLiveKit/LFVideoFrame.h>
|
||||
#import <LFLiveKit/LFLiveDebug.h>
|
||||
@@ -2,25 +2,21 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = "LFLiveKit"
|
||||
s.version = "1.7.3"
|
||||
s.version = "2.4.3"
|
||||
s.summary = "LaiFeng ios Live. LFLiveKit."
|
||||
s.homepage = "https://github.com/chenliming777"
|
||||
s.license = { :type => "MIT", :file => "LICENSE" }
|
||||
s.author = { "chenliming" => "chenliming777@qq.com" }
|
||||
s.platform = :ios, "8.0"
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.platform = :ios, "7.0"
|
||||
s.ios.deployment_target = "7.0"
|
||||
s.source = { :git => "https://github.com/LaiFengiOS/LFLiveKit.git", :tag => "#{s.version}" }
|
||||
s.source_files = "LFLiveKit/**/*.{h,m}"
|
||||
s.public_header_files = "LFLiveKit/**/*.h"
|
||||
s.source_files = "LFLiveKit/**/*.{h,m,mm,cpp,c}"
|
||||
s.public_header_files = ['LFLiveKit/*.h', 'LFLiveKit/objects/*.h', 'LFLiveKit/configuration/*.h']
|
||||
|
||||
s.frameworks = "VideoToolbox", "AudioToolbox","AVFoundation","Foundation","UIKit"
|
||||
s.library = "z"
|
||||
s.libraries = "c++", "z"
|
||||
|
||||
s.requires_arc = true
|
||||
|
||||
s.dependency "CocoaAsyncSocket", "~> 7.4.1"
|
||||
s.dependency 'LMGPUImage', '~> 0.1.9'
|
||||
s.dependency "pili-librtmp", "~> 1.0.2"
|
||||
s.dependency "YYDispatchQueuePool"
|
||||
|
||||
s.dependency 'GPUImage'
|
||||
s.dependency 'pili-librtmp', '1.0.3.1'
|
||||
end
|
||||
|
||||
@@ -1,678 +0,0 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
84001F8E1D0015D10026C63F /* LFLiveKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001F8D1D0015D10026C63F /* LFLiveKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001F951D0015D10026C63F /* LFLiveKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001F8A1D0015D10026C63F /* LFLiveKit.framework */; };
|
||||
84001F9A1D0015D10026C63F /* LFLiveKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001F991D0015D10026C63F /* LFLiveKitTests.m */; };
|
||||
84001FD11D0016380026C63F /* LFAudioCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FA51D0016380026C63F /* LFAudioCapture.h */; };
|
||||
84001FD21D0016380026C63F /* LFAudioCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FA61D0016380026C63F /* LFAudioCapture.m */; };
|
||||
84001FD31D0016380026C63F /* LFVideoCapture.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FA71D0016380026C63F /* LFVideoCapture.h */; };
|
||||
84001FD41D0016380026C63F /* LFVideoCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FA81D0016380026C63F /* LFVideoCapture.m */; };
|
||||
84001FD51D0016380026C63F /* LFAudioEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FAA1D0016380026C63F /* LFAudioEncoding.h */; };
|
||||
84001FD61D0016380026C63F /* LFHardwareAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FAB1D0016380026C63F /* LFHardwareAudioEncoder.h */; };
|
||||
84001FD71D0016380026C63F /* LFHardwareAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FAC1D0016380026C63F /* LFHardwareAudioEncoder.m */; };
|
||||
84001FD81D0016380026C63F /* LFHardwareVideoEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FAD1D0016380026C63F /* LFHardwareVideoEncoder.h */; };
|
||||
84001FD91D0016380026C63F /* LFHardwareVideoEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FAE1D0016380026C63F /* LFHardwareVideoEncoder.m */; };
|
||||
84001FDA1D0016380026C63F /* LFVideoEncoding.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FAF1D0016380026C63F /* LFVideoEncoding.h */; };
|
||||
84001FDB1D0016380026C63F /* LFLiveAudioConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FB11D0016380026C63F /* LFLiveAudioConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001FDC1D0016380026C63F /* LFLiveAudioConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FB21D0016380026C63F /* LFLiveAudioConfiguration.m */; };
|
||||
84001FDD1D0016380026C63F /* LFLiveVideoConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FB31D0016380026C63F /* LFLiveVideoConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001FDE1D0016380026C63F /* LFLiveVideoConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FB41D0016380026C63F /* LFLiveVideoConfiguration.m */; };
|
||||
84001FDF1D0016380026C63F /* LFGPUImageBeautyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FB61D0016380026C63F /* LFGPUImageBeautyFilter.h */; };
|
||||
84001FE01D0016380026C63F /* LFGPUImageBeautyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FB71D0016380026C63F /* LFGPUImageBeautyFilter.m */; };
|
||||
84001FE11D0016380026C63F /* LFGPUImageEmptyFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FB81D0016380026C63F /* LFGPUImageEmptyFilter.h */; };
|
||||
84001FE21D0016380026C63F /* LFGPUImageEmptyFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FB91D0016380026C63F /* LFGPUImageEmptyFilter.m */; };
|
||||
84001FE31D0016380026C63F /* LFLiveSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FBA1D0016380026C63F /* LFLiveSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001FE41D0016380026C63F /* LFLiveSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FBB1D0016380026C63F /* LFLiveSession.m */; };
|
||||
84001FE51D0016380026C63F /* LFAudioFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FBD1D0016380026C63F /* LFAudioFrame.h */; };
|
||||
84001FE61D0016380026C63F /* LFAudioFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FBE1D0016380026C63F /* LFAudioFrame.m */; };
|
||||
84001FE71D0016380026C63F /* LFFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FBF1D0016380026C63F /* LFFrame.h */; };
|
||||
84001FE81D0016380026C63F /* LFFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC01D0016380026C63F /* LFFrame.m */; };
|
||||
84001FE91D0016380026C63F /* LFLiveDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FC11D0016380026C63F /* LFLiveDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001FEA1D0016380026C63F /* LFLiveDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC21D0016380026C63F /* LFLiveDebug.m */; };
|
||||
84001FEB1D0016380026C63F /* LFLiveStreamInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FC31D0016380026C63F /* LFLiveStreamInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
84001FEC1D0016380026C63F /* LFLiveStreamInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC41D0016380026C63F /* LFLiveStreamInfo.m */; };
|
||||
84001FED1D0016380026C63F /* LFVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 84001FC51D0016380026C63F /* LFVideoFrame.h */; };
|
||||
84001FEE1D0016380026C63F /* LFVideoFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 84001FC61D0016380026C63F /* LFVideoFrame.m */; };
|
||||
84001FF71D0017590026C63F /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FF61D0017590026C63F /* AVFoundation.framework */; };
|
||||
84001FF91D00175D0026C63F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FF81D00175D0026C63F /* Foundation.framework */; };
|
||||
84001FFB1D0017630026C63F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFA1D0017630026C63F /* UIKit.framework */; };
|
||||
84001FFD1D0017680026C63F /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFC1D0017680026C63F /* AudioToolbox.framework */; };
|
||||
84001FFF1D00176C0026C63F /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84001FFE1D00176C0026C63F /* VideoToolbox.framework */; };
|
||||
840020011D0017850026C63F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 840020001D0017850026C63F /* libz.tbd */; };
|
||||
8493627A1D38B542002C8F13 /* LFStreamingBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362701D38B542002C8F13 /* LFStreamingBuffer.h */; };
|
||||
8493627B1D38B542002C8F13 /* LFStreamingBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362711D38B542002C8F13 /* LFStreamingBuffer.m */; };
|
||||
8493627C1D38B542002C8F13 /* LFStreamRtmpSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */; };
|
||||
8493627D1D38B542002C8F13 /* LFStreamRtmpSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */; };
|
||||
8493627E1D38B542002C8F13 /* LFStreamSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362741D38B542002C8F13 /* LFStreamSocket.h */; };
|
||||
849362811D38B542002C8F13 /* NSMutableArray+LFAdd.h in Headers */ = {isa = PBXBuildFile; fileRef = 849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */; };
|
||||
849362821D38B542002C8F13 /* NSMutableArray+LFAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */; };
|
||||
AD7F89B4621A7EFEBEA72D49 /* libPods-LFLiveKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B8CB02D2A92EA1F5A262F154 /* libPods-LFLiveKit.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
84001F961D0015D10026C63F /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 84001F811D0015D10026C63F /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 84001F891D0015D10026C63F;
|
||||
remoteInfo = LFLiveKit;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
84001F8A1D0015D10026C63F /* LFLiveKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LFLiveKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84001F8D1D0015D10026C63F /* LFLiveKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LFLiveKit.h; sourceTree = "<group>"; };
|
||||
84001F8F1D0015D10026C63F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
84001F941D0015D10026C63F /* LFLiveKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LFLiveKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84001F991D0015D10026C63F /* LFLiveKitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LFLiveKitTests.m; sourceTree = "<group>"; };
|
||||
84001F9B1D0015D10026C63F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
84001FA51D0016380026C63F /* LFAudioCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioCapture.h; sourceTree = "<group>"; };
|
||||
84001FA61D0016380026C63F /* LFAudioCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioCapture.m; sourceTree = "<group>"; };
|
||||
84001FA71D0016380026C63F /* LFVideoCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoCapture.h; sourceTree = "<group>"; };
|
||||
84001FA81D0016380026C63F /* LFVideoCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoCapture.m; sourceTree = "<group>"; };
|
||||
84001FAA1D0016380026C63F /* LFAudioEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioEncoding.h; sourceTree = "<group>"; };
|
||||
84001FAB1D0016380026C63F /* LFHardwareAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareAudioEncoder.h; sourceTree = "<group>"; };
|
||||
84001FAC1D0016380026C63F /* LFHardwareAudioEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareAudioEncoder.m; sourceTree = "<group>"; };
|
||||
84001FAD1D0016380026C63F /* LFHardwareVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFHardwareVideoEncoder.h; sourceTree = "<group>"; };
|
||||
84001FAE1D0016380026C63F /* LFHardwareVideoEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFHardwareVideoEncoder.m; sourceTree = "<group>"; };
|
||||
84001FAF1D0016380026C63F /* LFVideoEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoEncoding.h; sourceTree = "<group>"; };
|
||||
84001FB11D0016380026C63F /* LFLiveAudioConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveAudioConfiguration.h; sourceTree = "<group>"; };
|
||||
84001FB21D0016380026C63F /* LFLiveAudioConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveAudioConfiguration.m; sourceTree = "<group>"; };
|
||||
84001FB31D0016380026C63F /* LFLiveVideoConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveVideoConfiguration.h; sourceTree = "<group>"; };
|
||||
84001FB41D0016380026C63F /* LFLiveVideoConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveVideoConfiguration.m; sourceTree = "<group>"; };
|
||||
84001FB61D0016380026C63F /* LFGPUImageBeautyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageBeautyFilter.h; sourceTree = "<group>"; };
|
||||
84001FB71D0016380026C63F /* LFGPUImageBeautyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageBeautyFilter.m; sourceTree = "<group>"; };
|
||||
84001FB81D0016380026C63F /* LFGPUImageEmptyFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFGPUImageEmptyFilter.h; sourceTree = "<group>"; };
|
||||
84001FB91D0016380026C63F /* LFGPUImageEmptyFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFGPUImageEmptyFilter.m; sourceTree = "<group>"; };
|
||||
84001FBA1D0016380026C63F /* LFLiveSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveSession.h; sourceTree = "<group>"; };
|
||||
84001FBB1D0016380026C63F /* LFLiveSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveSession.m; sourceTree = "<group>"; };
|
||||
84001FBD1D0016380026C63F /* LFAudioFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFAudioFrame.h; sourceTree = "<group>"; };
|
||||
84001FBE1D0016380026C63F /* LFAudioFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFAudioFrame.m; sourceTree = "<group>"; };
|
||||
84001FBF1D0016380026C63F /* LFFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFFrame.h; sourceTree = "<group>"; };
|
||||
84001FC01D0016380026C63F /* LFFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFFrame.m; sourceTree = "<group>"; };
|
||||
84001FC11D0016380026C63F /* LFLiveDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveDebug.h; sourceTree = "<group>"; };
|
||||
84001FC21D0016380026C63F /* LFLiveDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveDebug.m; sourceTree = "<group>"; };
|
||||
84001FC31D0016380026C63F /* LFLiveStreamInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLiveStreamInfo.h; sourceTree = "<group>"; };
|
||||
84001FC41D0016380026C63F /* LFLiveStreamInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLiveStreamInfo.m; sourceTree = "<group>"; };
|
||||
84001FC51D0016380026C63F /* LFVideoFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFVideoFrame.h; sourceTree = "<group>"; };
|
||||
84001FC61D0016380026C63F /* LFVideoFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFVideoFrame.m; sourceTree = "<group>"; };
|
||||
84001FF61D0017590026C63F /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
|
||||
84001FF81D00175D0026C63F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
84001FFA1D0017630026C63F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
84001FFC1D0017680026C63F /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
84001FFE1D00176C0026C63F /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
|
||||
840020001D0017850026C63F /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||
849362701D38B542002C8F13 /* LFStreamingBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamingBuffer.h; sourceTree = "<group>"; };
|
||||
849362711D38B542002C8F13 /* LFStreamingBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamingBuffer.m; sourceTree = "<group>"; };
|
||||
849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamRtmpSocket.h; sourceTree = "<group>"; };
|
||||
849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFStreamRtmpSocket.m; sourceTree = "<group>"; };
|
||||
849362741D38B542002C8F13 /* LFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFStreamSocket.h; sourceTree = "<group>"; };
|
||||
849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+LFAdd.h"; sourceTree = "<group>"; };
|
||||
849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+LFAdd.m"; sourceTree = "<group>"; };
|
||||
A17586B27CD6843997425CCF /* Pods-LFLiveKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKit/Pods-LFLiveKit.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B75B965E6B94DE4CBCC82EA7 /* Pods-LFLiveKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKit/Pods-LFLiveKit.release.xcconfig"; sourceTree = "<group>"; };
|
||||
B8CB02D2A92EA1F5A262F154 /* libPods-LFLiveKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKit.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
84001F861D0015D10026C63F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
840020011D0017850026C63F /* libz.tbd in Frameworks */,
|
||||
84001FFF1D00176C0026C63F /* VideoToolbox.framework in Frameworks */,
|
||||
84001FFD1D0017680026C63F /* AudioToolbox.framework in Frameworks */,
|
||||
84001FFB1D0017630026C63F /* UIKit.framework in Frameworks */,
|
||||
84001FF91D00175D0026C63F /* Foundation.framework in Frameworks */,
|
||||
84001FF71D0017590026C63F /* AVFoundation.framework in Frameworks */,
|
||||
AD7F89B4621A7EFEBEA72D49 /* libPods-LFLiveKit.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84001F911D0015D10026C63F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84001F951D0015D10026C63F /* LFLiveKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
0C07D14560B9E91EA1B59306 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840020001D0017850026C63F /* libz.tbd */,
|
||||
84001FFE1D00176C0026C63F /* VideoToolbox.framework */,
|
||||
84001FFC1D0017680026C63F /* AudioToolbox.framework */,
|
||||
84001FFA1D0017630026C63F /* UIKit.framework */,
|
||||
84001FF81D00175D0026C63F /* Foundation.framework */,
|
||||
84001FF61D0017590026C63F /* AVFoundation.framework */,
|
||||
B8CB02D2A92EA1F5A262F154 /* libPods-LFLiveKit.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001F801D0015D10026C63F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001F8C1D0015D10026C63F /* LFLiveKit */,
|
||||
84001F981D0015D10026C63F /* LFLiveKitTests */,
|
||||
84001F8B1D0015D10026C63F /* Products */,
|
||||
EDD4B76A07A6817C79BB4E5C /* Pods */,
|
||||
0C07D14560B9E91EA1B59306 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001F8B1D0015D10026C63F /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001F8A1D0015D10026C63F /* LFLiveKit.framework */,
|
||||
84001F941D0015D10026C63F /* LFLiveKitTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001F8C1D0015D10026C63F /* LFLiveKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001F8D1D0015D10026C63F /* LFLiveKit.h */,
|
||||
84001FBA1D0016380026C63F /* LFLiveSession.h */,
|
||||
84001FBB1D0016380026C63F /* LFLiveSession.m */,
|
||||
84001FBC1D0016380026C63F /* objects */,
|
||||
84001FB01D0016380026C63F /* configuration */,
|
||||
84001FA41D0016380026C63F /* capture */,
|
||||
84001FA91D0016380026C63F /* coder */,
|
||||
84001FB51D0016380026C63F /* filter */,
|
||||
8493626F1D38B542002C8F13 /* publish */,
|
||||
84001F8F1D0015D10026C63F /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001F981D0015D10026C63F /* LFLiveKitTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001F991D0015D10026C63F /* LFLiveKitTests.m */,
|
||||
84001F9B1D0015D10026C63F /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKitTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001FA41D0016380026C63F /* capture */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001FA51D0016380026C63F /* LFAudioCapture.h */,
|
||||
84001FA61D0016380026C63F /* LFAudioCapture.m */,
|
||||
84001FA71D0016380026C63F /* LFVideoCapture.h */,
|
||||
84001FA81D0016380026C63F /* LFVideoCapture.m */,
|
||||
);
|
||||
path = capture;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001FA91D0016380026C63F /* coder */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001FAA1D0016380026C63F /* LFAudioEncoding.h */,
|
||||
84001FAB1D0016380026C63F /* LFHardwareAudioEncoder.h */,
|
||||
84001FAC1D0016380026C63F /* LFHardwareAudioEncoder.m */,
|
||||
84001FAD1D0016380026C63F /* LFHardwareVideoEncoder.h */,
|
||||
84001FAE1D0016380026C63F /* LFHardwareVideoEncoder.m */,
|
||||
84001FAF1D0016380026C63F /* LFVideoEncoding.h */,
|
||||
);
|
||||
path = coder;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001FB01D0016380026C63F /* configuration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001FB11D0016380026C63F /* LFLiveAudioConfiguration.h */,
|
||||
84001FB21D0016380026C63F /* LFLiveAudioConfiguration.m */,
|
||||
84001FB31D0016380026C63F /* LFLiveVideoConfiguration.h */,
|
||||
84001FB41D0016380026C63F /* LFLiveVideoConfiguration.m */,
|
||||
);
|
||||
path = configuration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001FB51D0016380026C63F /* filter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001FB61D0016380026C63F /* LFGPUImageBeautyFilter.h */,
|
||||
84001FB71D0016380026C63F /* LFGPUImageBeautyFilter.m */,
|
||||
84001FB81D0016380026C63F /* LFGPUImageEmptyFilter.h */,
|
||||
84001FB91D0016380026C63F /* LFGPUImageEmptyFilter.m */,
|
||||
);
|
||||
path = filter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84001FBC1D0016380026C63F /* objects */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
84001FBD1D0016380026C63F /* LFAudioFrame.h */,
|
||||
84001FBE1D0016380026C63F /* LFAudioFrame.m */,
|
||||
84001FBF1D0016380026C63F /* LFFrame.h */,
|
||||
84001FC01D0016380026C63F /* LFFrame.m */,
|
||||
84001FC11D0016380026C63F /* LFLiveDebug.h */,
|
||||
84001FC21D0016380026C63F /* LFLiveDebug.m */,
|
||||
84001FC31D0016380026C63F /* LFLiveStreamInfo.h */,
|
||||
84001FC41D0016380026C63F /* LFLiveStreamInfo.m */,
|
||||
84001FC51D0016380026C63F /* LFVideoFrame.h */,
|
||||
84001FC61D0016380026C63F /* LFVideoFrame.m */,
|
||||
);
|
||||
path = objects;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8493626F1D38B542002C8F13 /* publish */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849362701D38B542002C8F13 /* LFStreamingBuffer.h */,
|
||||
849362711D38B542002C8F13 /* LFStreamingBuffer.m */,
|
||||
849362721D38B542002C8F13 /* LFStreamRtmpSocket.h */,
|
||||
849362731D38B542002C8F13 /* LFStreamRtmpSocket.m */,
|
||||
849362741D38B542002C8F13 /* LFStreamSocket.h */,
|
||||
849362781D38B542002C8F13 /* NSMutableArray+LFAdd.h */,
|
||||
849362791D38B542002C8F13 /* NSMutableArray+LFAdd.m */,
|
||||
);
|
||||
path = publish;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EDD4B76A07A6817C79BB4E5C /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A17586B27CD6843997425CCF /* Pods-LFLiveKit.debug.xcconfig */,
|
||||
B75B965E6B94DE4CBCC82EA7 /* Pods-LFLiveKit.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
84001F871D0015D10026C63F /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84001FDB1D0016380026C63F /* LFLiveAudioConfiguration.h in Headers */,
|
||||
8493627C1D38B542002C8F13 /* LFStreamRtmpSocket.h in Headers */,
|
||||
84001FDD1D0016380026C63F /* LFLiveVideoConfiguration.h in Headers */,
|
||||
84001FE31D0016380026C63F /* LFLiveSession.h in Headers */,
|
||||
8493627A1D38B542002C8F13 /* LFStreamingBuffer.h in Headers */,
|
||||
84001FEB1D0016380026C63F /* LFLiveStreamInfo.h in Headers */,
|
||||
84001FE91D0016380026C63F /* LFLiveDebug.h in Headers */,
|
||||
84001FE71D0016380026C63F /* LFFrame.h in Headers */,
|
||||
84001FD61D0016380026C63F /* LFHardwareAudioEncoder.h in Headers */,
|
||||
84001FDF1D0016380026C63F /* LFGPUImageBeautyFilter.h in Headers */,
|
||||
84001FD31D0016380026C63F /* LFVideoCapture.h in Headers */,
|
||||
84001FD11D0016380026C63F /* LFAudioCapture.h in Headers */,
|
||||
84001FE11D0016380026C63F /* LFGPUImageEmptyFilter.h in Headers */,
|
||||
84001FDA1D0016380026C63F /* LFVideoEncoding.h in Headers */,
|
||||
84001FE51D0016380026C63F /* LFAudioFrame.h in Headers */,
|
||||
84001FED1D0016380026C63F /* LFVideoFrame.h in Headers */,
|
||||
84001FD81D0016380026C63F /* LFHardwareVideoEncoder.h in Headers */,
|
||||
849362811D38B542002C8F13 /* NSMutableArray+LFAdd.h in Headers */,
|
||||
8493627E1D38B542002C8F13 /* LFStreamSocket.h in Headers */,
|
||||
84001FD51D0016380026C63F /* LFAudioEncoding.h in Headers */,
|
||||
84001F8E1D0015D10026C63F /* LFLiveKit.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
84001F891D0015D10026C63F /* LFLiveKit */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 84001F9E1D0015D10026C63F /* Build configuration list for PBXNativeTarget "LFLiveKit" */;
|
||||
buildPhases = (
|
||||
8EE9401DCA9508E918B7FB68 /* 📦 Check Pods Manifest.lock */,
|
||||
84001F851D0015D10026C63F /* Sources */,
|
||||
84001F861D0015D10026C63F /* Frameworks */,
|
||||
84001F871D0015D10026C63F /* Headers */,
|
||||
84001F881D0015D10026C63F /* Resources */,
|
||||
817C22141AD3F2EB34365AA3 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = LFLiveKit;
|
||||
productName = LFLiveKit;
|
||||
productReference = 84001F8A1D0015D10026C63F /* LFLiveKit.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
84001F931D0015D10026C63F /* LFLiveKitTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 84001FA11D0015D10026C63F /* Build configuration list for PBXNativeTarget "LFLiveKitTests" */;
|
||||
buildPhases = (
|
||||
84001F901D0015D10026C63F /* Sources */,
|
||||
84001F911D0015D10026C63F /* Frameworks */,
|
||||
84001F921D0015D10026C63F /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
84001F971D0015D10026C63F /* PBXTargetDependency */,
|
||||
);
|
||||
name = LFLiveKitTests;
|
||||
productName = LFLiveKitTests;
|
||||
productReference = 84001F941D0015D10026C63F /* LFLiveKitTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
84001F811D0015D10026C63F /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = admin;
|
||||
TargetAttributes = {
|
||||
84001F891D0015D10026C63F = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
};
|
||||
84001F931D0015D10026C63F = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 84001F841D0015D10026C63F /* Build configuration list for PBXProject "LFLiveKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 84001F801D0015D10026C63F;
|
||||
productRefGroup = 84001F8B1D0015D10026C63F /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
84001F891D0015D10026C63F /* LFLiveKit */,
|
||||
84001F931D0015D10026C63F /* LFLiveKitTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
84001F881D0015D10026C63F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84001F921D0015D10026C63F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
817C22141AD3F2EB34365AA3 /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKit/Pods-LFLiveKit-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
8EE9401DCA9508E918B7FB68 /* 📦 Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
84001F851D0015D10026C63F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84001FE21D0016380026C63F /* LFGPUImageEmptyFilter.m in Sources */,
|
||||
84001FE41D0016380026C63F /* LFLiveSession.m in Sources */,
|
||||
84001FE61D0016380026C63F /* LFAudioFrame.m in Sources */,
|
||||
84001FDC1D0016380026C63F /* LFLiveAudioConfiguration.m in Sources */,
|
||||
84001FD41D0016380026C63F /* LFVideoCapture.m in Sources */,
|
||||
84001FE81D0016380026C63F /* LFFrame.m in Sources */,
|
||||
849362821D38B542002C8F13 /* NSMutableArray+LFAdd.m in Sources */,
|
||||
8493627B1D38B542002C8F13 /* LFStreamingBuffer.m in Sources */,
|
||||
84001FDE1D0016380026C63F /* LFLiveVideoConfiguration.m in Sources */,
|
||||
84001FD21D0016380026C63F /* LFAudioCapture.m in Sources */,
|
||||
8493627D1D38B542002C8F13 /* LFStreamRtmpSocket.m in Sources */,
|
||||
84001FD91D0016380026C63F /* LFHardwareVideoEncoder.m in Sources */,
|
||||
84001FEC1D0016380026C63F /* LFLiveStreamInfo.m in Sources */,
|
||||
84001FEA1D0016380026C63F /* LFLiveDebug.m in Sources */,
|
||||
84001FEE1D0016380026C63F /* LFVideoFrame.m in Sources */,
|
||||
84001FD71D0016380026C63F /* LFHardwareAudioEncoder.m in Sources */,
|
||||
84001FE01D0016380026C63F /* LFGPUImageBeautyFilter.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
84001F901D0015D10026C63F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
84001F9A1D0015D10026C63F /* LFLiveKitTests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
84001F971D0015D10026C63F /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 84001F891D0015D10026C63F /* LFLiveKit */;
|
||||
targetProxy = 84001F961D0015D10026C63F /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
84001F9C1D0015D10026C63F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84001F9D1D0015D10026C63F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84001F9F1D0015D10026C63F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A17586B27CD6843997425CCF /* Pods-LFLiveKit.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = LFLiveKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84001FA01D0015D10026C63F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B75B965E6B94DE4CBCC82EA7 /* Pods-LFLiveKit.release.xcconfig */;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = LFLiveKit/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKit;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
84001FA21D0015D10026C63F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = LFLiveKitTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
84001FA31D0015D10026C63F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
INFOPLIST_FILE = LFLiveKitTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
84001F841D0015D10026C63F /* Build configuration list for PBXProject "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84001F9C1D0015D10026C63F /* Debug */,
|
||||
84001F9D1D0015D10026C63F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84001F9E1D0015D10026C63F /* Build configuration list for PBXNativeTarget "LFLiveKit" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84001F9F1D0015D10026C63F /* Debug */,
|
||||
84001FA01D0015D10026C63F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
84001FA11D0015D10026C63F /* Build configuration list for PBXNativeTarget "LFLiveKitTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
84001FA21D0015D10026C63F /* Debug */,
|
||||
84001FA31D0015D10026C63F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 84001F811D0015D10026C63F /* Project object */;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKit.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,155 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "48F687CDE9990BD471D7883061F7E5D4"
|
||||
BuildableName = "libCocoaAsyncSocket.a"
|
||||
BlueprintName = "CocoaAsyncSocket"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "6610362E50A6DE8BACCA1F2885CD9157"
|
||||
BuildableName = "libGPUImage.a"
|
||||
BlueprintName = "GPUImage"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "7C2BDDF89D4243C7BCA44592D146DEED"
|
||||
BuildableName = "libPods-LFLiveKit.a"
|
||||
BlueprintName = "Pods-LFLiveKit"
|
||||
ReferencedContainer = "container:Pods/Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F931D0015D10026C63F"
|
||||
BuildableName = "LFLiveKitTests.xctest"
|
||||
BlueprintName = "LFLiveKitTests"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F931D0015D10026C63F"
|
||||
BuildableName = "LFLiveKitTests.xctest"
|
||||
BlueprintName = "LFLiveKitTests"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "84001F891D0015D10026C63F"
|
||||
BuildableName = "LFLiveKit.framework"
|
||||
BlueprintName = "LFLiveKit"
|
||||
ReferencedContainer = "container:LFLiveKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>LFLiveKit.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>84001F891D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>84001F931D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>84001F891D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>84001F931D0015D10026C63F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:LFLiveKit.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "LFLiveKitTests/LFLiveKitTests.m"
|
||||
timestampString = "486890388.753673"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "18"
|
||||
endingLineNumber = "18"
|
||||
landmarkName = "-setUp"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "LFLiveKitTests/LFLiveKitTests.m"
|
||||
timestampString = "486890389.93478"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "24"
|
||||
endingLineNumber = "24"
|
||||
landmarkName = "-tearDown"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "LFLiveKitTests/LFLiveKitTests.m"
|
||||
timestampString = "486890391.195074"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "30"
|
||||
endingLineNumber = "30"
|
||||
landmarkName = "-testExample"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "LFLiveKitTests/LFLiveKitTests.m"
|
||||
timestampString = "486890392.195974"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "37"
|
||||
endingLineNumber = "37"
|
||||
landmarkName = "-testPerformanceExample"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
@@ -2,10 +2,13 @@
|
||||
// LFLiveKit.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by admin on 16/5/24.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef LFLiveKit_h
|
||||
#define LFLiveKit_h
|
||||
|
||||
#import "LFLiveSession.h"
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
@@ -13,3 +16,7 @@
|
||||
#import "LFFrame.h"
|
||||
#import "LFLiveStreamInfo.h"
|
||||
#import "LFVideoFrame.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
// LFLiveSession.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
//
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -16,6 +17,28 @@
|
||||
#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>
|
||||
|
||||
@@ -23,9 +46,9 @@
|
||||
/** live status changed will callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state;
|
||||
/** live debug info callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug *)debugInfo;
|
||||
/** callback socket errorcode */
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
- (void)liveSession:(nullable LFLiveSession *)session errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
@end
|
||||
|
||||
@class LFLiveStreamInfo;
|
||||
@@ -37,13 +60,13 @@
|
||||
/// @name Attribute
|
||||
///=============================================================================
|
||||
/** The delegate of the capture. captureData callback */
|
||||
@property (nullable,nonatomic, weak) id<LFLiveSessionDelegate> delegate;
|
||||
@property (nullable, nonatomic, weak) id<LFLiveSessionDelegate> delegate;
|
||||
|
||||
/** The running control start capture or stop capture*/
|
||||
@property (nonatomic, assign) BOOL running;
|
||||
|
||||
/** The preView will show OpenGL ES view*/
|
||||
@property (nonatomic, strong,null_resettable) UIView *preView;
|
||||
@property (nonatomic, strong, null_resettable) UIView *preView;
|
||||
|
||||
/** The captureDevicePosition control camraPosition ,default front*/
|
||||
@property (nonatomic, assign) AVCaptureDevicePosition captureDevicePosition;
|
||||
@@ -51,10 +74,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 */
|
||||
@@ -67,22 +90,42 @@
|
||||
@property (nonatomic, assign) BOOL mirror;
|
||||
|
||||
/** The muted control callbackAudioData,muted will memset 0.*/
|
||||
@property (nonatomic,assign) BOOL muted;
|
||||
@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;
|
||||
@property (nullable, nonatomic, strong, readonly) LFLiveStreamInfo *streamInfo;
|
||||
|
||||
/** The status of the stream .*/
|
||||
@property (nonatomic,assign,readonly) LFLiveState state;
|
||||
@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;
|
||||
@property (nonatomic, assign) BOOL showDebugInfo;
|
||||
|
||||
/** The reconnectInterval control reconnect timeInterval(重连间隔) *.*/
|
||||
@property (nonatomic,assign) NSUInteger reconnectInterval;
|
||||
@property (nonatomic, assign) NSUInteger reconnectInterval;
|
||||
|
||||
/** The reconnectCount control reconnect count (重连次数) *.*/
|
||||
@property (nonatomic,assign) NSUInteger reconnectCount;
|
||||
@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, nullable) UIView *warterMarkView;
|
||||
|
||||
/* The currentImage is videoCapture shot */
|
||||
@property (nonatomic, strong,readonly ,nullable) UIImage *currentImage;
|
||||
|
||||
/* The saveLocalVideo is save the local video */
|
||||
@property (nonatomic, assign) BOOL saveLocalVideo;
|
||||
|
||||
/* The saveLocalVideoPath is save the local video path */
|
||||
@property (nonatomic, strong, nullable) NSURL *saveLocalVideoPath;
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
@@ -91,18 +134,29 @@
|
||||
- (nullable instancetype)init UNAVAILABLE_ATTRIBUTE;
|
||||
+ (nullable instancetype)new UNAVAILABLE_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration*)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration*)videoConfiguration NS_DESIGNATED_INITIALIZER;
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration captureType:(LFLiveCaptureTypeMask)captureType NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/** The start stream .*/
|
||||
- (void)startLive:(nonnull LFLiveStreamInfo*)streamInfo;
|
||||
- (void)startLive:(nonnull LFLiveStreamInfo *)streamInfo;
|
||||
|
||||
/** The stop stream .*/
|
||||
- (void)stopLive;
|
||||
|
||||
/** support outer input yuv or rgb video(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer;
|
||||
|
||||
/** support outer input pcm audio(set LFLiveCaptureTypeMask) .*/
|
||||
- (void)pushAudio:(nullable NSData*)audioData;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFLiveSession.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveSession.h"
|
||||
@@ -11,19 +11,18 @@
|
||||
#import "LFAudioCapture.h"
|
||||
#import "LFHardwareVideoEncoder.h"
|
||||
#import "LFHardwareAudioEncoder.h"
|
||||
#import "LFStreamRtmpSocket.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;
|
||||
}
|
||||
///音频配置
|
||||
@interface LFLiveSession ()<LFAudioCaptureDelegate, LFVideoCaptureDelegate, LFAudioEncodingDelegate, LFVideoEncodingDelegate, LFStreamSocketDelegate>
|
||||
|
||||
/// 音频配置
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *audioConfiguration;
|
||||
///视频配置
|
||||
/// 视频配置
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
|
||||
/// 声音采集
|
||||
@property (nonatomic, strong) LFAudioCapture *audioCaptureSource;
|
||||
@@ -36,134 +35,189 @@
|
||||
/// 上传
|
||||
@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;
|
||||
/// 当前状态
|
||||
@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;
|
||||
@property (nonatomic, assign) BOOL isFirstFrame;
|
||||
@property (nonatomic, assign) uint64_t currentTimestamp;
|
||||
/// 上传相对时间戳
|
||||
@property (nonatomic, assign) uint64_t relativeTimestamps;
|
||||
/// 音视频是否对齐
|
||||
@property (nonatomic, assign) BOOL AVAlignment;
|
||||
/// 当前是否采集到了音频
|
||||
@property (nonatomic, assign) BOOL hasCaptureAudio;
|
||||
/// 当前是否采集到了关键帧
|
||||
@property (nonatomic, assign) BOOL hasKeyFrameVideo;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFLiveSession
|
||||
|
||||
#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];
|
||||
if(self = [super init]){
|
||||
- (instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)audioConfiguration videoConfiguration:(nullable LFLiveVideoConfiguration *)videoConfiguration {
|
||||
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;
|
||||
_captureType = captureType;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
self.audioCaptureSource.running = NO;
|
||||
self.videoCaptureSource.running = NO;
|
||||
- (void)dealloc {
|
||||
_videoCaptureSource.running = NO;
|
||||
_audioCaptureSource.running = NO;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
- (void)startLive:(LFLiveStreamInfo*)streamInfo{
|
||||
if(!streamInfo) return;
|
||||
- (void)startLive:(LFLiveStreamInfo *)streamInfo {
|
||||
if (!streamInfo) return;
|
||||
_streamInfo = streamInfo;
|
||||
_streamInfo.videoConfiguration = _videoConfiguration;
|
||||
_streamInfo.audioConfiguration = _audioConfiguration;
|
||||
[self.socket start];
|
||||
}
|
||||
|
||||
- (void)stopLive{
|
||||
- (void)stopLive {
|
||||
self.uploading = NO;
|
||||
[self.socket stop];
|
||||
self.socket = nil;
|
||||
}
|
||||
|
||||
- (void)pushVideo:(nullable CVPixelBufferRef)pixelBuffer{
|
||||
if(self.captureType & LFLiveInputMaskVideo){
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:NOW];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pushAudio:(nullable NSData*)audioData{
|
||||
if(self.captureType & LFLiveInputMaskAudio){
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioData timeStamp:NOW];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- PrivateMethod
|
||||
- (void)pushSendBuffer:(LFFrame*)frame{
|
||||
if(self.relativeTimestamps == 0){
|
||||
self.relativeTimestamps = frame.timestamp;
|
||||
}
|
||||
frame.timestamp = [self uploadTimestamp:frame.timestamp];
|
||||
[self.socket sendFrame:frame];
|
||||
}
|
||||
|
||||
#pragma mark -- CaptureDelegate
|
||||
- (void)captureOutput:(nullable LFAudioCapture*)capture audioBuffer:(AudioBufferList)inBufferList{
|
||||
[self.audioEncoder encodeAudioData:inBufferList timeStamp:self.currentTimestamp];
|
||||
- (void)captureOutput:(nullable LFAudioCapture *)capture audioData:(nullable NSData*)audioData {
|
||||
if (self.uploading) [self.audioEncoder encodeAudioData:audioData timeStamp:NOW];
|
||||
}
|
||||
|
||||
- (void)captureOutput:(nullable LFVideoCapture*)capture pixelBuffer:(nullable CVImageBufferRef)pixelBuffer{
|
||||
[self.videoEncoder encodeVideoData:pixelBuffer timeStamp:self.currentTimestamp];
|
||||
- (void)captureOutput:(nullable LFVideoCapture *)capture pixelBuffer:(nullable CVPixelBufferRef)pixelBuffer {
|
||||
if (self.uploading) [self.videoEncoder encodeVideoData:pixelBuffer timeStamp:NOW];
|
||||
}
|
||||
|
||||
#pragma mark -- EncoderDelegate
|
||||
- (void)audioEncoder:(nullable id<LFAudioEncoding>)encoder audioFrame:(nullable LFAudioFrame*)frame{
|
||||
if(self.uploading) [self.socket sendFrame:frame];//<上传
|
||||
- (void)audioEncoder:(nullable id<LFAudioEncoding>)encoder audioFrame:(nullable LFAudioFrame *)frame {
|
||||
//<上传 时间戳对齐
|
||||
if (self.uploading){
|
||||
self.hasCaptureAudio = YES;
|
||||
if(self.AVAlignment) [self pushSendBuffer:frame];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoEncoder:(nullable id<LFVideoEncoding>)encoder videoFrame:(nullable LFVideoFrame*)frame{
|
||||
if(self.uploading) [self.socket sendFrame:frame];//<上传
|
||||
- (void)videoEncoder:(nullable id<LFVideoEncoding>)encoder videoFrame:(nullable LFVideoFrame *)frame {
|
||||
//<上传 时间戳对齐
|
||||
if (self.uploading){
|
||||
if(frame.isKeyFrame && self.hasCaptureAudio) self.hasKeyFrameVideo = YES;
|
||||
if(self.AVAlignment) [self pushSendBuffer:frame];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- LFStreamTcpSocketDelegate
|
||||
- (void)socketStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveState)status{
|
||||
if(status == LFLiveStart){
|
||||
if(!self.uploading){
|
||||
self.timestamp = 0;
|
||||
self.isFirstFrame = YES;
|
||||
- (void)socketStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveState)status {
|
||||
if (status == LFLiveStart) {
|
||||
if (!self.uploading) {
|
||||
self.AVAlignment = NO;
|
||||
self.hasCaptureAudio = NO;
|
||||
self.hasKeyFrameVideo = NO;
|
||||
self.relativeTimestamps = 0;
|
||||
self.uploading = YES;
|
||||
}
|
||||
} else if(status == LFLiveStop || status == LFLiveError){
|
||||
self.uploading = NO;
|
||||
}
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.state = status;
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(liveSession:liveStateDidChange:)]){
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(liveSession:liveStateDidChange:)]) {
|
||||
[self.delegate liveSession:self liveStateDidChange:status];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)socketDidError:(nullable id<LFStreamSocket>)socket errorCode:(LFLiveSocketErrorCode)errorCode{
|
||||
- (void)socketDidError:(nullable id<LFStreamSocket>)socket errorCode:(LFLiveSocketErrorCode)errorCode {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(liveSession:errorCode:)]){
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(liveSession:errorCode:)]) {
|
||||
[self.delegate liveSession:self errorCode:errorCode];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)socketDebug:(nullable id<LFStreamSocket>)socket debugInfo:(nullable LFLiveDebug*)debugInfo{
|
||||
- (void)socketDebug:(nullable id<LFStreamSocket>)socket debugInfo:(nullable LFLiveDebug *)debugInfo {
|
||||
self.debugInfo = debugInfo;
|
||||
if(self.showDebugInfo){
|
||||
if (self.showDebugInfo) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(liveSession:debugInfo:)]){
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(liveSession:debugInfo:)]) {
|
||||
[self.delegate liveSession:self debugInfo:debugInfo];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)socketBufferStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveBuffferState)status{
|
||||
NSUInteger videoBitRate = [_videoEncoder videoBitRate];
|
||||
if(status == LFLiveBuffferIncrease){
|
||||
if(videoBitRate < _videoConfiguration.videoMaxBitRate){
|
||||
videoBitRate = videoBitRate + 50 * 1000;
|
||||
[_videoEncoder setVideoBitRate:videoBitRate];
|
||||
}
|
||||
}else{
|
||||
if(videoBitRate > _videoConfiguration.videoMinBitRate){
|
||||
videoBitRate = videoBitRate - 100 * 1000;
|
||||
[_videoEncoder setVideoBitRate:videoBitRate];
|
||||
- (void)socketBufferStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveBuffferState)status {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- Getter Setter
|
||||
- (void)setRunning:(BOOL)running{
|
||||
if(_running == running) return;
|
||||
- (void)setRunning:(BOOL)running {
|
||||
if (_running == running) return;
|
||||
[self willChangeValueForKey:@"running"];
|
||||
_running = running;
|
||||
[self didChangeValueForKey:@"running"];
|
||||
@@ -171,32 +225,57 @@
|
||||
self.audioCaptureSource.running = _running;
|
||||
}
|
||||
|
||||
- (void)setPreView:(UIView *)preView{
|
||||
- (void)setPreView:(UIView *)preView {
|
||||
[self willChangeValueForKey:@"preView"];
|
||||
[self.videoCaptureSource setPreView:preView];
|
||||
[self didChangeValueForKey:@"preView"];
|
||||
}
|
||||
|
||||
- (UIView*)preView{
|
||||
- (UIView *)preView {
|
||||
return self.videoCaptureSource.preView;
|
||||
}
|
||||
|
||||
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition{
|
||||
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition {
|
||||
[self willChangeValueForKey:@"captureDevicePosition"];
|
||||
[self.videoCaptureSource setCaptureDevicePosition:captureDevicePosition];
|
||||
[self didChangeValueForKey:@"captureDevicePosition"];
|
||||
}
|
||||
|
||||
- (AVCaptureDevicePosition)captureDevicePosition{
|
||||
- (AVCaptureDevicePosition)captureDevicePosition {
|
||||
return self.videoCaptureSource.captureDevicePosition;
|
||||
}
|
||||
|
||||
- (void)setBeautyFace:(BOOL)beautyFace{
|
||||
- (void)setBeautyFace:(BOOL)beautyFace {
|
||||
[self willChangeValueForKey:@"beautyFace"];
|
||||
[self.videoCaptureSource setBeautyFace:beautyFace];
|
||||
[self didChangeValueForKey:@"beautyFace"];
|
||||
}
|
||||
|
||||
- (BOOL)beautyFace{
|
||||
- (BOOL)saveLocalVideo{
|
||||
return self.videoCaptureSource.saveLocalVideo;
|
||||
}
|
||||
|
||||
- (void)setSaveLocalVideo:(BOOL)saveLocalVideo{
|
||||
[self.videoCaptureSource setSaveLocalVideo:saveLocalVideo];
|
||||
}
|
||||
|
||||
|
||||
- (NSURL*)saveLocalVideoPath{
|
||||
return self.videoCaptureSource.saveLocalVideoPath;
|
||||
}
|
||||
|
||||
- (void)setSaveLocalVideoPath:(NSURL*)saveLocalVideoPath{
|
||||
[self.videoCaptureSource setSaveLocalVideoPath:saveLocalVideoPath];
|
||||
}
|
||||
|
||||
- (BOOL)beautyFace {
|
||||
return self.videoCaptureSource.beautyFace;
|
||||
}
|
||||
|
||||
- (void)setBeautyLevel:(CGFloat)beautyLevel {
|
||||
[self willChangeValueForKey:@"beautyLevel"];
|
||||
[self.videoCaptureSource setBeautyLevel:beautyLevel];
|
||||
[self didChangeValueForKey:@"beautyLevel"];
|
||||
}
|
||||
|
||||
- (CGFloat)beautyLevel {
|
||||
@@ -204,7 +283,9 @@
|
||||
}
|
||||
|
||||
- (void)setBrightLevel:(CGFloat)brightLevel {
|
||||
[self willChangeValueForKey:@"brightLevel"];
|
||||
[self.videoCaptureSource setBrightLevel:brightLevel];
|
||||
[self didChangeValueForKey:@"brightLevel"];
|
||||
}
|
||||
|
||||
- (CGFloat)brightLevel {
|
||||
@@ -212,7 +293,9 @@
|
||||
}
|
||||
|
||||
- (void)setZoomScale:(CGFloat)zoomScale {
|
||||
[self willChangeValueForKey:@"zoomScale"];
|
||||
[self.videoCaptureSource setZoomScale:zoomScale];
|
||||
[self didChangeValueForKey:@"zoomScale"];
|
||||
}
|
||||
|
||||
- (CGFloat)zoomScale {
|
||||
@@ -220,7 +303,9 @@
|
||||
}
|
||||
|
||||
- (void)setTorch:(BOOL)torch {
|
||||
[self willChangeValueForKey:@"torch"];
|
||||
[self.videoCaptureSource setTorch:torch];
|
||||
[self didChangeValueForKey:@"torch"];
|
||||
}
|
||||
|
||||
- (BOOL)torch {
|
||||
@@ -228,80 +313,116 @@
|
||||
}
|
||||
|
||||
- (void)setMirror:(BOOL)mirror {
|
||||
[self willChangeValueForKey:@"mirror"];
|
||||
[self.videoCaptureSource setMirror:mirror];
|
||||
[self didChangeValueForKey:@"mirror"];
|
||||
}
|
||||
|
||||
- (BOOL)mirror {
|
||||
return self.videoCaptureSource.mirror;
|
||||
}
|
||||
|
||||
- (void)setMuted:(BOOL)muted{
|
||||
- (void)setMuted:(BOOL)muted {
|
||||
[self willChangeValueForKey:@"muted"];
|
||||
[self.audioCaptureSource setMuted:muted];
|
||||
[self didChangeValueForKey:@"muted"];
|
||||
}
|
||||
|
||||
- (BOOL)muted{
|
||||
- (BOOL)muted {
|
||||
return self.audioCaptureSource.muted;
|
||||
}
|
||||
|
||||
- (LFAudioCapture*)audioCaptureSource{
|
||||
if(!_audioCaptureSource){
|
||||
_audioCaptureSource = [[LFAudioCapture alloc] initWithAudioConfiguration:_audioConfiguration];
|
||||
_audioCaptureSource.delegate = self;
|
||||
- (void)setWarterMarkView:(UIView *)warterMarkView{
|
||||
[self.videoCaptureSource setWarterMarkView:warterMarkView];
|
||||
}
|
||||
|
||||
- (nullable UIView*)warterMarkView{
|
||||
return self.videoCaptureSource.warterMarkView;
|
||||
}
|
||||
|
||||
- (nullable UIImage *)currentImage{
|
||||
return self.videoCaptureSource.currentImage;
|
||||
}
|
||||
|
||||
- (LFAudioCapture *)audioCaptureSource {
|
||||
if (!_audioCaptureSource) {
|
||||
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;
|
||||
- (LFVideoCapture *)videoCaptureSource {
|
||||
if (!_videoCaptureSource) {
|
||||
if(self.captureType & LFLiveCaptureMaskVideo){
|
||||
_videoCaptureSource = [[LFVideoCapture alloc] initWithVideoConfiguration:_videoConfiguration];
|
||||
_videoCaptureSource.delegate = self;
|
||||
}
|
||||
}
|
||||
return _videoCaptureSource;
|
||||
}
|
||||
|
||||
- (id<LFAudioEncoding>)audioEncoder{
|
||||
if(!_audioEncoder){
|
||||
- (id<LFAudioEncoding>)audioEncoder {
|
||||
if (!_audioEncoder) {
|
||||
_audioEncoder = [[LFHardwareAudioEncoder alloc] initWithAudioStreamConfiguration:_audioConfiguration];
|
||||
[_audioEncoder setDelegate:self];
|
||||
}
|
||||
return _audioEncoder;
|
||||
}
|
||||
|
||||
- (id<LFVideoEncoding>)videoEncoder{
|
||||
if(!_videoEncoder){
|
||||
_videoEncoder = [[LFHardwareVideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
- (id<LFVideoEncoding>)videoEncoder {
|
||||
if (!_videoEncoder) {
|
||||
if([[UIDevice currentDevice].systemVersion floatValue] < 8.0){
|
||||
_videoEncoder = [[LFH264VideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
}else{
|
||||
_videoEncoder = [[LFHardwareVideoEncoder alloc] initWithVideoStreamConfiguration:_videoConfiguration];
|
||||
}
|
||||
[_videoEncoder setDelegate:self];
|
||||
}
|
||||
return _videoEncoder;
|
||||
}
|
||||
|
||||
- (id<LFStreamSocket>)socket{
|
||||
if(!_socket){
|
||||
_socket = [[LFStreamRtmpSocket alloc] initWithStream:self.streamInfo videoSize:self.videoConfiguration.videoSize reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
|
||||
- (id<LFStreamSocket>)socket {
|
||||
if (!_socket) {
|
||||
_socket = [[LFStreamRTMPSocket alloc] initWithStream:self.streamInfo reconnectInterval:self.reconnectInterval reconnectCount:self.reconnectCount];
|
||||
[_socket setDelegate:self];
|
||||
}
|
||||
return _socket;
|
||||
}
|
||||
|
||||
- (LFLiveStreamInfo*)streamInfo{
|
||||
if(!_streamInfo){
|
||||
- (LFLiveStreamInfo *)streamInfo {
|
||||
if (!_streamInfo) {
|
||||
_streamInfo = [[LFLiveStreamInfo alloc] init];
|
||||
}
|
||||
return _streamInfo;
|
||||
}
|
||||
|
||||
- (uint64_t)currentTimestamp{
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
uint64_t currentts = 0;
|
||||
if(_isFirstFrame == true) {
|
||||
_timestamp = NOW;
|
||||
_isFirstFrame = false;
|
||||
currentts = 0;
|
||||
} else {
|
||||
currentts = NOW - _timestamp;
|
||||
- (dispatch_semaphore_t)lock{
|
||||
if(!_lock){
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
}
|
||||
dispatch_semaphore_signal(_lock);
|
||||
return _lock;
|
||||
}
|
||||
|
||||
- (uint64_t)uploadTimestamp:(uint64_t)captureTimestamp{
|
||||
dispatch_semaphore_wait(self.lock, DISPATCH_TIME_FOREVER);
|
||||
uint64_t currentts = 0;
|
||||
currentts = captureTimestamp - self.relativeTimestamps;
|
||||
dispatch_semaphore_signal(self.lock);
|
||||
return currentts;
|
||||
}
|
||||
|
||||
- (BOOL)AVAlignment{
|
||||
if((self.captureType & LFLiveCaptureMaskAudio || self.captureType & LFLiveInputMaskAudio) &&
|
||||
(self.captureType & LFLiveCaptureMaskVideo || self.captureType & LFLiveInputMaskVideo)
|
||||
){
|
||||
if(self.hasCaptureAudio && self.hasKeyFrameVideo) return YES;
|
||||
else return NO;
|
||||
}else{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFAudioCapture.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -17,7 +17,7 @@ extern NSString *_Nullable const LFAudioComponentFailedToCreateNotification;
|
||||
@class LFAudioCapture;
|
||||
/** LFAudioCapture callback audioData */
|
||||
@protocol LFAudioCaptureDelegate <NSObject>
|
||||
- (void)captureOutput:(nullable LFAudioCapture*)capture audioBuffer:(AudioBufferList)inBufferList;
|
||||
- (void)captureOutput:(nullable LFAudioCapture *)capture audioData:(nullable NSData*)audioData;
|
||||
@end
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@ extern NSString *_Nullable const LFAudioComponentFailedToCreateNotification;
|
||||
///=============================================================================
|
||||
|
||||
/** The delegate of the capture. captureData callback */
|
||||
@property (nullable,nonatomic, weak) id<LFAudioCaptureDelegate> delegate;
|
||||
@property (nullable, nonatomic, weak) id<LFAudioCaptureDelegate> delegate;
|
||||
|
||||
/** The muted control callbackAudioData,muted will memset 0.*/
|
||||
@property (nonatomic,assign) BOOL muted;
|
||||
@property (nonatomic, assign) BOOL muted;
|
||||
|
||||
/** The running control start capture or stop capture*/
|
||||
@property (nonatomic, assign) BOOL running;
|
||||
@@ -45,8 +45,8 @@ extern NSString *_Nullable const LFAudioComponentFailedToCreateNotification;
|
||||
+ (nullable instancetype)new UNAVAILABLE_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithAudioConfiguration:(nullable LFLiveAudioConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFAudioCapture.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFAudioCapture.h"
|
||||
@@ -14,11 +14,11 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
|
||||
@interface LFAudioCapture ()
|
||||
|
||||
@property (nonatomic, assign) AudioComponentInstance componetInstance;
|
||||
@property (nonatomic, assign) AudioComponent component;
|
||||
@property (nonatomic, strong) dispatch_queue_t taskQueue;
|
||||
@property (nonatomic, assign) AudioComponentInstance componetInstance;
|
||||
@property (nonatomic, assign) AudioComponent component;
|
||||
@property (nonatomic, strong) dispatch_queue_t taskQueue;
|
||||
@property (nonatomic, assign) BOOL isRunning;
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *configuration;
|
||||
@property (nonatomic, strong,nullable) LFLiveAudioConfiguration *configuration;
|
||||
|
||||
@end
|
||||
|
||||
@@ -32,7 +32,7 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
self.taskQueue = dispatch_queue_create("com.youku.Laifeng.audioCapture.Queue", NULL);
|
||||
|
||||
AVAudioSession *session = [AVAudioSession sharedInstance];
|
||||
[session setActive:YES error:nil];
|
||||
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||
selector: @selector(handleRouteChange:)
|
||||
@@ -43,18 +43,9 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
name: AVAudioSessionInterruptionNotification
|
||||
object: session];
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
|
||||
|
||||
[session setMode:AVAudioSessionModeVideoRecording error:&error];
|
||||
|
||||
if (![session setActive:YES error:&error]) {
|
||||
[self handleAudioComponentCreationFailure];
|
||||
}
|
||||
|
||||
AudioComponentDescription acd;
|
||||
acd.componentType = kAudioUnitType_Output;
|
||||
//acd.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
|
||||
acd.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
acd.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
acd.componentFlags = 0;
|
||||
@@ -96,18 +87,20 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
}
|
||||
|
||||
[session setPreferredSampleRate:_configuration.audioSampleRate error:nil];
|
||||
|
||||
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:nil];
|
||||
[session setActive:YES withOptions:kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation error:nil];
|
||||
|
||||
[session setActive:YES error:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
dispatch_sync(self.taskQueue, ^{
|
||||
if(self.componetInstance){
|
||||
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
if (self.componetInstance) {
|
||||
self.isRunning = NO;
|
||||
AudioOutputUnitStop(self.componetInstance);
|
||||
AudioComponentInstanceDispose(self.componetInstance);
|
||||
self.componetInstance = nil;
|
||||
@@ -117,17 +110,22 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
}
|
||||
|
||||
#pragma mark -- Setter
|
||||
- (void)setRunning:(BOOL)running{
|
||||
if(_running == running) return;
|
||||
- (void)setRunning:(BOOL)running {
|
||||
if (_running == running) return;
|
||||
_running = running;
|
||||
if(_running){
|
||||
if (_running) {
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
self.isRunning = YES;
|
||||
NSLog(@"MicrophoneSource: startRunning");
|
||||
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:nil];
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
}else{
|
||||
self.isRunning = NO;
|
||||
} else {
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
self.isRunning = NO;
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
AudioOutputUnitStop(self.componetInstance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,76 +139,77 @@ NSString *const LFAudioComponentFailedToCreateNotification = @"LFAudioComponentF
|
||||
#pragma mark -- NSNotification
|
||||
- (void)handleRouteChange:(NSNotification *)notification {
|
||||
AVAudioSession *session = [ AVAudioSession sharedInstance ];
|
||||
NSString* seccReason = @"";
|
||||
NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
|
||||
NSString *seccReason = @"";
|
||||
NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
|
||||
// AVAudioSessionRouteDescription* prevRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey];
|
||||
switch (reason) {
|
||||
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
|
||||
seccReason = @"The route changed because no suitable route is now available for the specified category.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonWakeFromSleep:
|
||||
seccReason = @"The route changed when the device woke up from sleep.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonOverride:
|
||||
seccReason = @"The output route was overridden by the app.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonCategoryChange:
|
||||
seccReason = @"The category of the session object changed.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
|
||||
seccReason = @"The previous audio output path is no longer available.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
|
||||
seccReason = @"A preferred new audio output path is now available.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonUnknown:
|
||||
default:
|
||||
seccReason = @"The reason for the change is unknown.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
|
||||
seccReason = @"The route changed because no suitable route is now available for the specified category.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonWakeFromSleep:
|
||||
seccReason = @"The route changed when the device woke up from sleep.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonOverride:
|
||||
seccReason = @"The output route was overridden by the app.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonCategoryChange:
|
||||
seccReason = @"The category of the session object changed.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
|
||||
seccReason = @"The previous audio output path is no longer available.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
|
||||
seccReason = @"A preferred new audio output path is now available.";
|
||||
break;
|
||||
case AVAudioSessionRouteChangeReasonUnknown:
|
||||
default:
|
||||
seccReason = @"The reason for the change is unknown.";
|
||||
break;
|
||||
}
|
||||
NSLog(@"handleRouteChange reason is %@",seccReason);
|
||||
|
||||
AVAudioSessionPortDescription *input = [[session.currentRoute.inputs count]?session.currentRoute.inputs:nil objectAtIndex:0];
|
||||
NSLog(@"handleRouteChange reason is %@", seccReason);
|
||||
|
||||
AVAudioSessionPortDescription *input = [[session.currentRoute.inputs count] ? session.currentRoute.inputs : nil objectAtIndex:0];
|
||||
if (input.portType == AVAudioSessionPortHeadsetMic) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleInterruption:(NSNotification *)notification {
|
||||
NSInteger reason = 0;
|
||||
NSString* reasonStr = @"";
|
||||
NSString *reasonStr = @"";
|
||||
if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
|
||||
//Posted when an audio interruption occurs.
|
||||
reason = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] integerValue];
|
||||
if (reason == AVAudioSessionInterruptionTypeBegan) {
|
||||
if (self.isRunning) {
|
||||
dispatch_sync(self.taskQueue, ^{
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
AudioOutputUnitStop(self.componetInstance);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (reason == AVAudioSessionInterruptionTypeEnded) {
|
||||
reasonStr = @"AVAudioSessionInterruptionTypeEnded";
|
||||
NSNumber* seccondReason = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey] ;
|
||||
NSNumber *seccondReason = [[notification userInfo] objectForKey:AVAudioSessionInterruptionOptionKey];
|
||||
switch ([seccondReason integerValue]) {
|
||||
case AVAudioSessionInterruptionOptionShouldResume:
|
||||
if (self.isRunning) {
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
}
|
||||
// Indicates that the audio session is active and immediately ready to be used. Your app can resume the audio operation that was interrupted.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case AVAudioSessionInterruptionOptionShouldResume:
|
||||
if (self.isRunning) {
|
||||
dispatch_async(self.taskQueue, ^{
|
||||
NSLog(@"MicrophoneSource: startRunning");
|
||||
AudioOutputUnitStart(self.componetInstance);
|
||||
});
|
||||
}
|
||||
// Indicates that the audio session is active and immediately ready to be used. Your app can resume the audio operation that was interrupted.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
NSLog(@"handleInterruption: %@ reason %@",[notification name], reasonStr);
|
||||
|
||||
}
|
||||
;
|
||||
NSLog(@"handleInterruption: %@ reason %@", [notification name], reasonStr);
|
||||
}
|
||||
|
||||
#pragma mark -- CallBack
|
||||
@@ -222,43 +221,34 @@ static OSStatus handleInputBuffer(void *inRefCon,
|
||||
AudioBufferList *ioData) {
|
||||
@autoreleasepool {
|
||||
LFAudioCapture *source = (__bridge LFAudioCapture *)inRefCon;
|
||||
if(!source) return -1;
|
||||
|
||||
if (!source) return -1;
|
||||
|
||||
AudioBuffer buffer;
|
||||
buffer.mData = NULL;
|
||||
buffer.mDataByteSize = 0;
|
||||
buffer.mNumberChannels = 1;
|
||||
|
||||
|
||||
AudioBufferList buffers;
|
||||
buffers.mNumberBuffers = 1;
|
||||
buffers.mBuffers[0] = buffer;
|
||||
|
||||
|
||||
OSStatus status = AudioUnitRender(source.componetInstance,
|
||||
ioActionFlags,
|
||||
inTimeStamp,
|
||||
inBusNumber,
|
||||
inNumberFrames,
|
||||
&buffers);
|
||||
|
||||
if (!source.isRunning) {
|
||||
dispatch_sync(source.taskQueue, ^{
|
||||
NSLog(@"MicrophoneSource: stopRunning");
|
||||
AudioOutputUnitStop(source.componetInstance);
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
if (source.muted) {
|
||||
for (int i = 0; i < buffers.mNumberBuffers; i++) {
|
||||
AudioBuffer ab = buffers.mBuffers[i];
|
||||
memset(ab.mData, 0, ab.mDataByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
if(!status) {
|
||||
if(source.delegate && [source.delegate respondsToSelector:@selector(captureOutput:audioBuffer:)]){
|
||||
[source.delegate captureOutput:source audioBuffer:buffers];
|
||||
|
||||
if (!status) {
|
||||
if (source.delegate && [source.delegate respondsToSelector:@selector(captureOutput:audioData:)]) {
|
||||
[source.delegate captureOutput:source audioData:[NSData dataWithBytes:buffers.mBuffers[0].mData length:buffers.mBuffers[0].mDataByteSize]];
|
||||
}
|
||||
}
|
||||
return status;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFVideoCapture.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -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
|
||||
@@ -24,13 +24,13 @@
|
||||
///=============================================================================
|
||||
|
||||
/** The delegate of the capture. captureData callback */
|
||||
@property (nullable,nonatomic, weak) id<LFVideoCaptureDelegate> delegate;
|
||||
@property (nullable, nonatomic, weak) id<LFVideoCaptureDelegate> delegate;
|
||||
|
||||
/** The running control start capture or stop capture*/
|
||||
@property (nonatomic, assign) BOOL running;
|
||||
|
||||
/** The preView will show OpenGL ES view*/
|
||||
@property (null_resettable,nonatomic, strong) UIView * preView;
|
||||
@property (null_resettable, nonatomic, strong) UIView *preView;
|
||||
|
||||
/** The captureDevicePosition control camraPosition ,default front*/
|
||||
@property (nonatomic, assign) AVCaptureDevicePosition captureDevicePosition;
|
||||
@@ -56,6 +56,18 @@
|
||||
/** 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, nullable) UIView *warterMarkView;
|
||||
|
||||
/* The currentImage is videoCapture shot */
|
||||
@property (nonatomic, strong, nullable) UIImage *currentImage;
|
||||
|
||||
/* The saveLocalVideo is save the local video */
|
||||
@property (nonatomic, assign) BOOL saveLocalVideo;
|
||||
|
||||
/* The saveLocalVideoPath is save the local video path */
|
||||
@property (nonatomic, strong, nullable) NSURL *saveLocalVideoPath;
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
/// @name Initializer
|
||||
@@ -64,8 +76,8 @@
|
||||
+ (nullable instancetype)new UNAVAILABLE_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
The designated initializer. Multiple instances with the same configuration will make the
|
||||
capture unstable.
|
||||
*/
|
||||
- (nullable instancetype)initWithVideoConfiguration:(nullable LFLiveVideoConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
||||
@@ -2,24 +2,37 @@
|
||||
// LFVideoCapture.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFVideoCapture.h"
|
||||
#import "GPUImage.h"
|
||||
#import "LFGPUImageBeautyFilter.h"
|
||||
#import "LFGPUImageEmptyFilter.h"
|
||||
|
||||
#if __has_include(<GPUImage/GPUImage.h>)
|
||||
#import <GPUImage/GPUImage.h>
|
||||
#elif __has_include("GPUImage/GPUImage.h")
|
||||
#import "GPUImage/GPUImage.h"
|
||||
#else
|
||||
#import "GPUImage.h"
|
||||
#endif
|
||||
|
||||
@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, strong) 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;
|
||||
|
||||
@property (nonatomic, strong) GPUImageMovieWriter *movieWriter;
|
||||
|
||||
@end
|
||||
|
||||
@@ -30,116 +43,104 @@
|
||||
@synthesize zoomScale = _zoomScale;
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
- (instancetype)initWithVideoConfiguration:(LFLiveVideoConfiguration *)configuration{
|
||||
if(self = [super init]){
|
||||
- (instancetype)initWithVideoConfiguration:(LFLiveVideoConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
_configuration = configuration;
|
||||
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:_configuration.avSessionPreset cameraPosition:AVCaptureDevicePositionFront];
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if(configuration.landscape){
|
||||
if(statusBar != UIInterfaceOrientationLandscapeLeft && statusBar != UIInterfaceOrientationLandscapeRight){
|
||||
NSLog(@"当前设置方向出错");
|
||||
NSLog(@"当前设置方向出错");
|
||||
NSLog(@"当前设置方向出错");
|
||||
_videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
}else{
|
||||
_videoCamera.outputImageOrientation = statusBar;
|
||||
}
|
||||
}else{
|
||||
if(statusBar != UIInterfaceOrientationPortrait && statusBar != UIInterfaceOrientationPortraitUpsideDown){
|
||||
NSLog(@"当前设置方向出错");
|
||||
NSLog(@"当前设置方向出错");
|
||||
NSLog(@"当前设置方向出错");
|
||||
_videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
||||
}else{
|
||||
_videoCamera.outputImageOrientation = statusBar;
|
||||
}
|
||||
}
|
||||
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
||||
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
|
||||
_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;
|
||||
self.mirror = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
- (void)dealloc {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[_videoCamera stopCameraCapture];
|
||||
if(_gpuImageView){
|
||||
[_gpuImageView removeFromSuperview];
|
||||
_gpuImageView = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
- (void)setRunning:(BOOL)running{
|
||||
if(_running == running) return;
|
||||
|
||||
- (GPUImageVideoCamera *)videoCamera{
|
||||
if(!_videoCamera){
|
||||
_videoCamera = [[GPUImageVideoCamera alloc] initWithSessionPreset:_configuration.avSessionPreset cameraPosition:AVCaptureDevicePositionFront];
|
||||
_videoCamera.outputImageOrientation = _configuration.outputImageOrientation;
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = NO;
|
||||
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
}
|
||||
return _videoCamera;
|
||||
}
|
||||
|
||||
- (void)setRunning:(BOOL)running {
|
||||
if (_running == running) return;
|
||||
_running = running;
|
||||
|
||||
if(!_running){
|
||||
if (!_running) {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[_videoCamera stopCameraCapture];
|
||||
}else{
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
[_videoCamera startCameraCapture];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPreView:(UIView *)preView{
|
||||
if(_gpuImageView.superview) [_gpuImageView removeFromSuperview];
|
||||
[preView insertSubview:_gpuImageView atIndex:0];
|
||||
}
|
||||
|
||||
- (UIView*)preView{
|
||||
return _gpuImageView.superview;
|
||||
}
|
||||
|
||||
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition{
|
||||
[_videoCamera rotateCamera];
|
||||
_videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
if (captureDevicePosition == AVCaptureDevicePositionFront) {
|
||||
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
|
||||
[self.videoCamera stopCameraCapture];
|
||||
if(self.saveLocalVideo) [self.movieWriter finishRecording];
|
||||
} else {
|
||||
[_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
[self reloadFilter];
|
||||
[self.videoCamera startCameraCapture];
|
||||
if(self.saveLocalVideo) [self.movieWriter startRecording];
|
||||
}
|
||||
}
|
||||
|
||||
- (AVCaptureDevicePosition)captureDevicePosition{
|
||||
return [_videoCamera cameraPosition];
|
||||
- (void)setPreView:(UIView *)preView {
|
||||
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);
|
||||
}
|
||||
|
||||
- (void)setVideoFrameRate:(NSInteger)videoFrameRate{
|
||||
if(videoFrameRate <= 0) return;
|
||||
if(videoFrameRate == _videoCamera.frameRate) return;
|
||||
_videoCamera.frameRate = (uint32_t)videoFrameRate;
|
||||
- (UIView *)preView {
|
||||
return self.gpuImageView.superview;
|
||||
}
|
||||
|
||||
- (NSInteger)videoFrameRate{
|
||||
return _videoCamera.frameRate;
|
||||
- (void)setCaptureDevicePosition:(AVCaptureDevicePosition)captureDevicePosition {
|
||||
[self.videoCamera rotateCamera];
|
||||
self.videoCamera.frameRate = (int32_t)_configuration.videoFrameRate;
|
||||
[self reloadMirror];
|
||||
}
|
||||
|
||||
- (AVCaptureDevicePosition)captureDevicePosition {
|
||||
return [self.videoCamera cameraPosition];
|
||||
}
|
||||
|
||||
- (void)setVideoFrameRate:(NSInteger)videoFrameRate {
|
||||
if (videoFrameRate <= 0) return;
|
||||
if (videoFrameRate == self.videoCamera.frameRate) return;
|
||||
self.videoCamera.frameRate = (uint32_t)videoFrameRate;
|
||||
}
|
||||
|
||||
- (NSInteger)videoFrameRate {
|
||||
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) {
|
||||
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) {
|
||||
if (self.videoCamera.inputCamera.torchAvailable) {
|
||||
NSError *err = nil;
|
||||
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;
|
||||
@@ -151,37 +152,45 @@
|
||||
[session commitConfiguration];
|
||||
_torch = ret;
|
||||
}
|
||||
|
||||
- (BOOL)torch {
|
||||
return _videoCamera.inputCamera.torchMode;
|
||||
return self.videoCamera.inputCamera.torchMode;
|
||||
}
|
||||
|
||||
- (void)setMirror:(BOOL)mirror {
|
||||
_videoCamera.horizontallyMirrorFrontFacingCamera = mirror;
|
||||
_videoCamera.horizontallyMirrorRearFacingCamera = mirror;
|
||||
_mirror = 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];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)beautyLevel {
|
||||
return _beautyLevel;
|
||||
}
|
||||
|
||||
- (void)setBrightLevel:(CGFloat)brightLevel {
|
||||
_brightLevel = brightLevel;
|
||||
if (_beautyFilter) {
|
||||
[_beautyFilter setBrightLevel:brightLevel];
|
||||
if (self.beautyFilter) {
|
||||
[self.beautyFilter setBrightLevel:brightLevel];
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)brightLevel {
|
||||
return _brightLevel;
|
||||
}
|
||||
|
||||
- (void)setZoomScale:(CGFloat)zoomScale {
|
||||
if (self.videoCamera && self.videoCamera.inputCamera) {
|
||||
AVCaptureDevice* device = (AVCaptureDevice*)self.videoCamera.inputCamera;
|
||||
AVCaptureDevice *device = (AVCaptureDevice *)self.videoCamera.inputCamera;
|
||||
if ([device lockForConfiguration:nil]) {
|
||||
device.videoZoomFactor = zoomScale;
|
||||
[device unlockForConfiguration];
|
||||
@@ -194,100 +203,182 @@
|
||||
return _zoomScale;
|
||||
}
|
||||
|
||||
- (void)setBeautyFace:(BOOL)beautyFace{
|
||||
if(_beautyFace == beautyFace) return;
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
if (_configuration.isClipVideo) {
|
||||
if (_configuration.landscape){
|
||||
_cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.125, 0, 0.75, 1)];
|
||||
} else {
|
||||
_cropfilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0, 0.125, 1, 0.75)];
|
||||
}
|
||||
[_videoCamera addTarget:_cropfilter];
|
||||
[_cropfilter addTarget:_filter];
|
||||
} else {
|
||||
[_videoCamera addTarget:_filter];
|
||||
_warterMarkView = warterMarkView;
|
||||
self.blendFilter.mix = warterMarkView.alpha;
|
||||
[self.waterMarkContentView addSubview:_warterMarkView];
|
||||
[self reloadFilter];
|
||||
}
|
||||
|
||||
- (GPUImageUIElement *)uiElementInput{
|
||||
if(!_uiElementInput){
|
||||
_uiElementInput = [[GPUImageUIElement alloc] initWithView:self.waterMarkContentView];
|
||||
}
|
||||
|
||||
if (_beautyFace) {
|
||||
[_filter addTarget:_output];
|
||||
[_output addTarget:_gpuImageView];
|
||||
} else {
|
||||
[_filter addTarget:_gpuImageView];
|
||||
return _uiElementInput;
|
||||
}
|
||||
|
||||
- (GPUImageAlphaBlendFilter *)blendFilter{
|
||||
if(!_blendFilter){
|
||||
_blendFilter = [[GPUImageAlphaBlendFilter alloc] init];
|
||||
_blendFilter.mix = 1.0;
|
||||
[_blendFilter disableSecondFrameCheck];
|
||||
}
|
||||
|
||||
if (_videoCamera.cameraPosition == AVCaptureDevicePositionFront) {
|
||||
[_gpuImageView setInputRotation:kGPUImageFlipHorizonal atIndex:0];
|
||||
} else {
|
||||
[_gpuImageView setInputRotation:kGPUImageNoRotation atIndex:0];
|
||||
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;
|
||||
}
|
||||
|
||||
-(UIImage *)currentImage{
|
||||
if(_filter){
|
||||
[_filter useNextFrameForImageCapture];
|
||||
return _filter.imageFromCurrentFramebuffer;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (GPUImageMovieWriter*)movieWriter{
|
||||
if(!_movieWriter){
|
||||
_movieWriter = [[GPUImageMovieWriter alloc] initWithMovieURL:self.saveLocalVideoPath size:self.configuration.videoSize];
|
||||
_movieWriter.encodingLiveVideo = YES;
|
||||
_movieWriter.shouldPassthroughAudio = YES;
|
||||
self.videoCamera.audioEncodingTarget = self.movieWriter;
|
||||
}
|
||||
return _movieWriter;
|
||||
}
|
||||
|
||||
#pragma mark -- Custom Method
|
||||
- (void)processVideo:(GPUImageOutput *)output{
|
||||
- (void)processVideo:(GPUImageOutput *)output {
|
||||
__weak typeof(self) _self = self;
|
||||
@autoreleasepool {
|
||||
GPUImageFramebuffer *imageFramebuffer = output.framebufferForOutput;
|
||||
CVPixelBufferRef pixelBuffer = [imageFramebuffer pixelBuffer];
|
||||
|
||||
if(pixelBuffer && _self.delegate && [_self.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:)]){
|
||||
CVPixelBufferRef pixelBuffer = NULL;
|
||||
CVPixelBufferCreateWithBytes(kCFAllocatorDefault, _self.configuration.videoSize.width, _self.configuration.videoSize.height, kCVPixelFormatType_32BGRA, [imageFramebuffer byteBuffer], _self.configuration.videoSize.width * 4, NULL, NULL, NULL, &pixelBuffer);
|
||||
if (pixelBuffer && _self.delegate && [_self.delegate respondsToSelector:@selector(captureOutput:pixelBuffer:)]) {
|
||||
[_self.delegate captureOutput:_self pixelBuffer:pixelBuffer];
|
||||
}
|
||||
|
||||
CFRelease(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 = (LFGPUImageBeautyFilter*)self.filter;
|
||||
} else {
|
||||
self.output = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.filter = [[LFGPUImageEmptyFilter alloc] init];
|
||||
self.beautyFilter = nil;
|
||||
}
|
||||
|
||||
///< 调节镜像
|
||||
[self reloadMirror];
|
||||
|
||||
///< 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];
|
||||
if(self.saveLocalVideo) [self.blendFilter addTarget:self.movieWriter];
|
||||
[self.filter addTarget:self.output];
|
||||
[self.uiElementInput update];
|
||||
}else{
|
||||
[self.filter addTarget:self.output];
|
||||
[self.output addTarget:self.gpuImageView];
|
||||
if(self.saveLocalVideo) [self.output addTarget:self.movieWriter];
|
||||
}
|
||||
|
||||
[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];
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
- (void)reloadMirror{
|
||||
if(self.mirror && self.captureDevicePosition == AVCaptureDevicePositionFront){
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = YES;
|
||||
}else{
|
||||
self.videoCamera.horizontallyMirrorFrontFacingCamera = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Notification
|
||||
|
||||
- (void)willEnterBackground:(NSNotification*)notification{
|
||||
- (void)willEnterBackground:(NSNotification *)notification {
|
||||
[UIApplication sharedApplication].idleTimerDisabled = NO;
|
||||
[_videoCamera pauseCameraCapture];
|
||||
[self.videoCamera pauseCameraCapture];
|
||||
runSynchronouslyOnVideoProcessingQueue(^{
|
||||
glFinish();
|
||||
});
|
||||
}
|
||||
|
||||
- (void)willEnterForeground:(NSNotification*)notification{
|
||||
[_videoCamera resumeCameraCapture];
|
||||
- (void)willEnterForeground:(NSNotification *)notification {
|
||||
[self.videoCamera resumeCameraCapture];
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
}
|
||||
|
||||
- (void)statusBarChanged:(NSNotification*)notification{
|
||||
NSLog(@"UIApplicationWillChangeStatusBarOrientationNotification. UserInfo: %@", notification.userInfo);
|
||||
- (void)statusBarChanged:(NSNotification *)notification {
|
||||
NSLog(@"UIApplicationWillChangeStatusBarOrientationNotification. UserInfo: %@", notification.userInfo);
|
||||
UIInterfaceOrientation statusBar = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if(_configuration.landscape){
|
||||
if(statusBar == UIInterfaceOrientationLandscapeLeft){
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeRight;
|
||||
}else if(statusBar == UIInterfaceOrientationLandscapeRight){
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
}
|
||||
}else{
|
||||
if(statusBar == UIInterfaceOrientationPortrait){
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortraitUpsideDown;
|
||||
}else if(statusBar == UIInterfaceOrientationPortraitUpsideDown){
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
||||
|
||||
if(self.configuration.autorotate){
|
||||
if (self.configuration.landscape) {
|
||||
if (statusBar == UIInterfaceOrientationLandscapeLeft) {
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeRight;
|
||||
} else if (statusBar == UIInterfaceOrientationLandscapeRight) {
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
}
|
||||
} else {
|
||||
if (statusBar == UIInterfaceOrientationPortrait) {
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortraitUpsideDown;
|
||||
} else if (statusBar == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
self.videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// AVEncoder.h
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 14/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVAssetWriter.h>
|
||||
#import <AVFoundation/AVAssetWriterInput.h>
|
||||
#import <AVFoundation/AVMediaFormat.h>
|
||||
#import <AVFoundation/AVVideoSettings.h>
|
||||
#import <sys/stat.h>
|
||||
|
||||
#import "LFVideoEncoder.h"
|
||||
#import "LFMP4Atom.h"
|
||||
|
||||
|
||||
|
||||
typedef int (^encoder_handler_t)(NSArray *data, CMTimeValue ptsValue);
|
||||
typedef int (^param_handler_t)(NSData *params);
|
||||
|
||||
@interface LFAVEncoder : NSObject
|
||||
|
||||
@property (atomic) NSUInteger 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;
|
||||
- (NSData *)getConfigData;
|
||||
- (void)shutdown;
|
||||
|
||||
|
||||
@property (readonly, atomic) int bitspersecond;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,439 @@
|
||||
//
|
||||
// AVEncoder.m
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 14/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "LFAVEncoder.h"
|
||||
#import "LFNALUnit.h"
|
||||
|
||||
static void *AVEncoderContext = &AVEncoderContext;
|
||||
|
||||
static unsigned int to_host(unsigned char *p){
|
||||
return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||||
}
|
||||
|
||||
#define OUTPUT_FILE_SWITCH_POINT (50 * 1024 * 1024) // 50 MB switch point
|
||||
#define MAX_FILENAME_INDEX 5 // filenames "capture1.mp4" wraps at capture5.mp4
|
||||
|
||||
|
||||
@interface LFAVEncoder ()
|
||||
|
||||
{
|
||||
// initial writer, used to obtain SPS/PPS from header
|
||||
LFVideoEncoder *_headerWriter;
|
||||
|
||||
// main encoder/writer
|
||||
LFVideoEncoder *_writer;
|
||||
|
||||
// writer output file (input to our extractor) and monitoring
|
||||
NSFileHandle *_inputFile;
|
||||
dispatch_queue_t _readQueue;
|
||||
dispatch_source_t _readSource;
|
||||
|
||||
// index of current file name
|
||||
BOOL _swapping;
|
||||
int _currentFile;
|
||||
int _height;
|
||||
int _width;
|
||||
|
||||
// param set data
|
||||
NSData *_avcC;
|
||||
int _lengthSize;
|
||||
|
||||
// location of mdat
|
||||
BOOL _foundMDAT;
|
||||
uint64_t _posMDAT;
|
||||
int _bytesToNextAtom;
|
||||
BOOL _needParams;
|
||||
|
||||
// tracking if NALU is next frame
|
||||
int _prev_nal_idc;
|
||||
int _prev_nal_type;
|
||||
// array of NSData comprising a single frame. each data is one nalu with no start code
|
||||
NSMutableArray *_pendingNALU;
|
||||
|
||||
// FIFO for frame times
|
||||
NSMutableArray *_times;
|
||||
|
||||
encoder_handler_t _outputBlock;
|
||||
param_handler_t _paramsBlock;
|
||||
|
||||
// estimate bitrate over first second
|
||||
int _bitspersecond;
|
||||
CMTimeValue _firstpts;
|
||||
}
|
||||
|
||||
@property (atomic) BOOL bitrateChanged;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFAVEncoder
|
||||
|
||||
@synthesize bitspersecond = _bitspersecond;
|
||||
|
||||
+ (LFAVEncoder *)encoderForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
LFAVEncoder *enc = [LFAVEncoder alloc];
|
||||
[enc initForHeight:height andWidth:width bitrate:bitrate];
|
||||
return enc;
|
||||
}
|
||||
|
||||
- (NSString *)makeFilename {
|
||||
NSString *filename = [NSString stringWithFormat:@"capture%d.mp4", _currentFile];
|
||||
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)initForHeight:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
_height = height;
|
||||
_width = width;
|
||||
_bitrate = bitrate;
|
||||
NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:@"params.mp4"];
|
||||
_headerWriter = [LFVideoEncoder encoderForPath:path Height:height andWidth:width bitrate:(int)self.bitrate];
|
||||
_times = [NSMutableArray arrayWithCapacity:10];
|
||||
|
||||
// swap between 3 filenames
|
||||
_currentFile = 1;
|
||||
_writer = [LFVideoEncoder encoderForPath:[self makeFilename] Height:height andWidth:width bitrate:(int)self.bitrate];
|
||||
|
||||
[self addObserver:self forKeyPath:NSStringFromSelector(@selector(bitrate)) options:0 context:AVEncoderContext];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary *)change
|
||||
context:(void *)context {
|
||||
if (context == AVEncoderContext && [keyPath isEqualToString:NSStringFromSelector(@selector(bitrate))]) {
|
||||
self.bitrateChanged = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)encodeWithBlock:(encoder_handler_t)block onParams:(param_handler_t)paramsHandler {
|
||||
_outputBlock = block;
|
||||
_paramsBlock = paramsHandler;
|
||||
_needParams = YES;
|
||||
_pendingNALU = nil;
|
||||
_firstpts = -1;
|
||||
_bitspersecond = 0;
|
||||
}
|
||||
|
||||
- (BOOL)parseParams:(NSString *)path {
|
||||
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
struct stat s;
|
||||
fstat([file fileDescriptor], &s);
|
||||
LFMP4Atom *movie = [LFMP4Atom atomAt:0 size:(int)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];
|
||||
if (trak == nil) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (trak.type == (OSType)('trak')) {
|
||||
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) {
|
||||
break;
|
||||
} else {
|
||||
tkhd = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LFMP4Atom *stsd = nil;
|
||||
if (trak != nil) {
|
||||
LFMP4Atom *media = [trak childOfType:(OSType)('mdia') startAt:0];
|
||||
if (media != nil) {
|
||||
LFMP4Atom *minf = [media childOfType:(OSType)('minf') startAt:0];
|
||||
if (minf != nil) {
|
||||
LFMP4Atom *stbl = [minf childOfType:(OSType)('stbl') startAt:0];
|
||||
if (stbl != nil) {
|
||||
stsd = [stbl childOfType:(OSType)('stsd') startAt:0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stsd != nil) {
|
||||
LFMP4Atom *avc1 = [stsd childOfType:(OSType)('avc1') startAt:8];
|
||||
if (avc1 != nil) {
|
||||
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:(int)esd.length];
|
||||
if (_avcC != nil) {
|
||||
// extract size of length field
|
||||
unsigned char *p = (unsigned char *)[_avcC bytes];
|
||||
_lengthSize = (p[4] & 3) + 1;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)onParamsCompletion {
|
||||
// the initial one-frame-only file has been completed
|
||||
// Extract the avcC structure and then start monitoring the
|
||||
// main file to extract video from the mdat chunk.
|
||||
if ([self parseParams:_headerWriter.path]) {
|
||||
if (_paramsBlock) {
|
||||
_paramsBlock(_avcC);
|
||||
}
|
||||
_headerWriter = nil;
|
||||
_swapping = NO;
|
||||
_inputFile = [NSFileHandle fileHandleForReadingAtPath:_writer.path];
|
||||
_readQueue = dispatch_queue_create("uk.co.gdcl.avencoder.read", DISPATCH_QUEUE_SERIAL);
|
||||
|
||||
_readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [_inputFile fileDescriptor], 0, _readQueue);
|
||||
dispatch_source_set_event_handler(_readSource, ^{
|
||||
[self onFileUpdate];
|
||||
});
|
||||
dispatch_resume(_readSource);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)encodeFrame:(CMSampleBufferRef)sampleBuffer {
|
||||
CMTime prestime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
||||
NSNumber *pts = [NSNumber numberWithLongLong:prestime.value];
|
||||
|
||||
@synchronized(self){
|
||||
if (_needParams) {
|
||||
// the avcC record is needed for decoding and it's not written to the file until
|
||||
// completion. We get round that by writing the first frame to two files; the first
|
||||
// file (containing only one frame) is then finished, so we can extract the avcC record.
|
||||
// Only when we've got that do we start reading from the main file.
|
||||
_needParams = NO;
|
||||
if ([_headerWriter encodeFrame:sampleBuffer]) {
|
||||
[_headerWriter finishWithCompletionHandler:^{
|
||||
[self onParamsCompletion];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@synchronized(_times){
|
||||
[_times addObject:pts];
|
||||
}
|
||||
@synchronized(self){
|
||||
// switch output files when we reach a size limit
|
||||
// to avoid runaway storage use.
|
||||
if (!_swapping) {
|
||||
struct stat st;
|
||||
fstat([_inputFile fileDescriptor], &st);
|
||||
if (st.st_size > OUTPUT_FILE_SWITCH_POINT || self.bitrateChanged) {
|
||||
self.bitrateChanged = NO;
|
||||
_swapping = YES;
|
||||
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 = [LFVideoEncoder encoderForPath:[self makeFilename] Height:_height andWidth:_width bitrate:(int)self.bitrate];
|
||||
|
||||
// to do this seamlessly requires a few steps in the right order
|
||||
// first, suspend the read source
|
||||
if (_readSource) {
|
||||
dispatch_source_cancel(_readSource);
|
||||
// execute the next step as a block on the same queue, to be sure the suspend is done
|
||||
dispatch_async(_readQueue, ^{
|
||||
// finish the file, writing moov, before reading any more from the file
|
||||
// since we don't yet know where the mdat ends
|
||||
_readSource = nil;
|
||||
[oldVideo finishWithCompletionHandler:^{
|
||||
[self swapFiles:oldVideo.path];
|
||||
}];
|
||||
});
|
||||
} else {
|
||||
[self swapFiles:oldVideo.path];
|
||||
}
|
||||
}
|
||||
}
|
||||
[_writer encodeFrame:sampleBuffer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)swapFiles:(NSString *)oldPath {
|
||||
// save current position
|
||||
uint64_t pos = [_inputFile offsetInFile];
|
||||
|
||||
// re-read mdat length
|
||||
[_inputFile seekToFileOffset:_posMDAT];
|
||||
NSData *hdr = [_inputFile readDataOfLength:4];
|
||||
unsigned char *p = (unsigned char *)[hdr bytes];
|
||||
if (p) {
|
||||
int lenMDAT = to_host(p);
|
||||
|
||||
// extract nalus from saved position to mdat end
|
||||
uint64_t posEnd = _posMDAT + lenMDAT;
|
||||
uint32_t cRead = (uint32_t)(posEnd - pos);
|
||||
[_inputFile seekToFileOffset:pos];
|
||||
[self readAndDeliver:cRead];
|
||||
}
|
||||
|
||||
// close and remove file
|
||||
[_inputFile closeFile];
|
||||
_foundMDAT = false;
|
||||
_bytesToNextAtom = 0;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:oldPath error:nil];
|
||||
|
||||
|
||||
// open new file and set up dispatch source
|
||||
_inputFile = [NSFileHandle fileHandleForReadingAtPath:_writer.path];
|
||||
_readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [_inputFile fileDescriptor], 0, _readQueue);
|
||||
dispatch_source_set_event_handler(_readSource, ^{
|
||||
[self onFileUpdate];
|
||||
});
|
||||
dispatch_resume(_readSource);
|
||||
_swapping = NO;
|
||||
}
|
||||
|
||||
- (void)readAndDeliver:(uint32_t)cReady {
|
||||
// Identify the individual NALUs and extract them
|
||||
while (cReady > _lengthSize) {
|
||||
NSData *lenField = [_inputFile readDataOfLength:_lengthSize];
|
||||
cReady -= _lengthSize;
|
||||
unsigned char *p = (unsigned char *)[lenField bytes];
|
||||
unsigned int lenNALU = to_host(p);
|
||||
|
||||
if (lenNALU > cReady) {
|
||||
// whole NALU not present -- seek back to start of NALU and wait for more
|
||||
[_inputFile seekToFileOffset:[_inputFile offsetInFile] - 4];
|
||||
break;
|
||||
}
|
||||
NSData *nalu = [_inputFile readDataOfLength:lenNALU];
|
||||
cReady -= lenNALU;
|
||||
|
||||
[self onNALU:nalu];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onFileUpdate {
|
||||
// called whenever there is more data to read in the main encoder output file.
|
||||
struct stat s;
|
||||
fstat([_inputFile fileDescriptor], &s);
|
||||
int cReady = (int)(s.st_size - [_inputFile offsetInFile]);
|
||||
|
||||
// locate the mdat atom if needed
|
||||
while (!_foundMDAT && (cReady > 8)) {
|
||||
if (_bytesToNextAtom == 0) {
|
||||
NSData *hdr = [_inputFile readDataOfLength:8];
|
||||
cReady -= 8;
|
||||
unsigned char *p = (unsigned char *)[hdr bytes];
|
||||
int lenAtom = to_host(p);
|
||||
unsigned int nameAtom = to_host(p+4);
|
||||
if (nameAtom == (unsigned int)('mdat')) {
|
||||
_foundMDAT = true;
|
||||
_posMDAT = [_inputFile offsetInFile] - 8;
|
||||
} else {
|
||||
_bytesToNextAtom = lenAtom - 8;
|
||||
}
|
||||
}
|
||||
if (_bytesToNextAtom > 0) {
|
||||
int cThis = cReady < _bytesToNextAtom ? cReady : _bytesToNextAtom;
|
||||
_bytesToNextAtom -= cThis;
|
||||
[_inputFile seekToFileOffset:[_inputFile offsetInFile]+cThis];
|
||||
cReady -= cThis;
|
||||
}
|
||||
}
|
||||
if (!_foundMDAT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the mdat must be just encoded video.
|
||||
[self readAndDeliver:cReady];
|
||||
}
|
||||
|
||||
- (void)onEncodedFrame {
|
||||
CMTimeValue pts = 0;
|
||||
@synchronized(_times){
|
||||
if ([_times count] > 0) {
|
||||
NSNumber *time = _times[0];
|
||||
pts = [time longLongValue];
|
||||
[_times removeObjectAtIndex:0];
|
||||
if (_firstpts < 0) {
|
||||
_firstpts = pts;
|
||||
}
|
||||
if ((pts - _firstpts) < 1) {
|
||||
int bytes = 0;
|
||||
for (NSData *data in _pendingNALU) {
|
||||
bytes += [data length];
|
||||
}
|
||||
_bitspersecond += (bytes * 8);
|
||||
}
|
||||
} else {
|
||||
//NSLog(@"no pts for buffer");
|
||||
}
|
||||
}
|
||||
if (_outputBlock != nil) {
|
||||
_outputBlock(_pendingNALU, pts);
|
||||
}
|
||||
}
|
||||
|
||||
// combine multiple NALUs into a single frame, and in the process, convert to BSF
|
||||
// by adding 00 00 01 startcodes before each NALU.
|
||||
- (void)onNALU:(NSData *)nalu {
|
||||
unsigned char *pNal = (unsigned char *)[nalu bytes];
|
||||
int idc = pNal[0] & 0x60;
|
||||
int naltype = pNal[0] & 0x1f;
|
||||
|
||||
if (_pendingNALU) {
|
||||
LFNALUnit nal(pNal, (int)[nalu length]);
|
||||
|
||||
// we have existing data —is this the same frame?
|
||||
// typically there are a couple of NALUs per frame in iOS encoding.
|
||||
// This is not general-purpose: it assumes that arbitrary slice ordering is not allowed.
|
||||
BOOL bNew = NO;
|
||||
if ((idc != _prev_nal_idc) && ((idc * _prev_nal_idc) == 0)) {
|
||||
bNew = YES;
|
||||
} else if ((naltype != _prev_nal_type) && ((naltype == 5) || (_prev_nal_type == 5))) {
|
||||
bNew = YES;
|
||||
} else if ((naltype >= 1) && (naltype <= 5)) {
|
||||
nal.Skip(8);
|
||||
int first_mb = (int)nal.GetUE();
|
||||
if (first_mb == 0) {
|
||||
bNew = YES;
|
||||
}
|
||||
}
|
||||
if (bNew) {
|
||||
[self onEncodedFrame];
|
||||
_pendingNALU = nil;
|
||||
}
|
||||
}
|
||||
_prev_nal_type = naltype;
|
||||
_prev_nal_idc = idc;
|
||||
if (_pendingNALU == nil) {
|
||||
_pendingNALU = [NSMutableArray arrayWithCapacity:2];
|
||||
}
|
||||
[_pendingNALU addObject:nalu];
|
||||
}
|
||||
|
||||
- (NSData *)getConfigData {
|
||||
return [_avcC copy];
|
||||
}
|
||||
|
||||
- (void)shutdown {
|
||||
@synchronized(self){
|
||||
_readSource = nil;
|
||||
if (_headerWriter) {
|
||||
[_headerWriter finishWithCompletionHandler:^{
|
||||
_headerWriter = nil;
|
||||
}];
|
||||
}
|
||||
if (_writer) {
|
||||
[_writer finishWithCompletionHandler:^{
|
||||
_writer = nil;
|
||||
}];
|
||||
}
|
||||
// !! wait for these to finish before returning and delete temp files
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// LFMP4Atom.h
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 15/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LFMP4Atom : NSObject
|
||||
|
||||
{
|
||||
NSFileHandle *_file;
|
||||
int64_t _offset;
|
||||
int64_t _length;
|
||||
OSType _type;
|
||||
int64_t _nextChild;
|
||||
}
|
||||
@property OSType type;
|
||||
@property int64_t length;
|
||||
|
||||
+ (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;
|
||||
- (LFMP4Atom *)nextChild;
|
||||
- (LFMP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// LFMP4Atom.m
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 15/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "LFMP4Atom.h"
|
||||
|
||||
static unsigned int to_host(unsigned char *p){
|
||||
return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||||
}
|
||||
|
||||
@implementation LFMP4Atom
|
||||
|
||||
@synthesize type = _type;
|
||||
@synthesize length = _length;
|
||||
|
||||
+ (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;
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
|
||||
- (BOOL)init:(int64_t)offset size:(int)length type:(OSType)fourcc inFile:(NSFileHandle *)handle {
|
||||
_file = handle;
|
||||
_offset = offset;
|
||||
_length = length;
|
||||
_type = fourcc;
|
||||
_nextChild = 0;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSData *)readAt:(int64_t)offset size:(int)length {
|
||||
[_file seekToFileOffset:_offset + offset];
|
||||
return [_file readDataOfLength:length];
|
||||
}
|
||||
|
||||
- (BOOL)setChildOffset:(int64_t)offset {
|
||||
_nextChild = offset;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (LFMP4Atom *)nextChild {
|
||||
if (_nextChild <= (_length - 8)) {
|
||||
[_file seekToFileOffset:_offset + _nextChild];
|
||||
NSData *data = [_file readDataOfLength:8];
|
||||
int cHeader = 8;
|
||||
unsigned char *p = (unsigned char *)[data bytes];
|
||||
int64_t len = to_host(p);
|
||||
OSType fourcc = to_host(p + 4);
|
||||
if (len == 1) {
|
||||
// 64-bit extended length
|
||||
cHeader += 8;
|
||||
data = [_file readDataOfLength:8];
|
||||
p = (unsigned char *)[data bytes];
|
||||
len = to_host(p);
|
||||
len = (len << 32) + to_host(p + 4);
|
||||
} else if (len == 0) {
|
||||
// whole remaining parent space
|
||||
len = _length - _nextChild;
|
||||
}
|
||||
if (fourcc == (OSType)('uuid')) {
|
||||
cHeader += 16;
|
||||
}
|
||||
if ((len < 0) || ((len + _nextChild) > _length)) {
|
||||
return nil;
|
||||
}
|
||||
int64_t offset = _nextChild + cHeader;
|
||||
_nextChild += len;
|
||||
len -= cHeader;
|
||||
return [LFMP4Atom atomAt:offset+_offset size:(int)len type:fourcc inFile:_file];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (LFMP4Atom *)childOfType:(OSType)fourcc startAt:(int64_t)offset {
|
||||
[self setChildOffset:offset];
|
||||
LFMP4Atom *child = nil;
|
||||
do {
|
||||
child = [self nextChild];
|
||||
} while ((child != nil) && (child.type != fourcc));
|
||||
return child;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,424 @@
|
||||
|
||||
//
|
||||
// NALUnit.cpp
|
||||
//
|
||||
// Implementation of Basic parsing of H.264 NAL Units
|
||||
//
|
||||
// Geraint Davies, March 2004
|
||||
//
|
||||
// Copyright (c) GDCL 2004-2008 http://www.gdcl.co.uk/license.htm
|
||||
|
||||
|
||||
|
||||
#include "LFNALUnit.h"
|
||||
|
||||
|
||||
// --- core NAL Unit implementation ------------------------------
|
||||
|
||||
LFNALUnit::LFNALUnit()
|
||||
: m_pStart(NULL),
|
||||
m_cBytes(0){
|
||||
}
|
||||
|
||||
bool
|
||||
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.
|
||||
// if no start code is found, pStart and cRemain should be unchanged.
|
||||
|
||||
const BYTE *pThis = pStart;
|
||||
int cBytes = cRemain;
|
||||
|
||||
pBegin = NULL;
|
||||
while (cBytes >= 4) {
|
||||
if (pThis[0] == 0) {
|
||||
// remember first 00
|
||||
if (pBegin == NULL) {
|
||||
pBegin = pThis;
|
||||
}
|
||||
if ((pThis[1] == 0) &&
|
||||
(pThis[2] == 1)) {
|
||||
// point to type byte of NAL unit
|
||||
pStart = pThis + 3;
|
||||
cRemain = cBytes - 3;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
pBegin = NULL;
|
||||
}
|
||||
cBytes--;
|
||||
pThis++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
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;
|
||||
|
||||
ResetBitstream();
|
||||
|
||||
if (LengthSize > 0) {
|
||||
m_pStartCodeStart = pBuffer;
|
||||
|
||||
if (LengthSize > cSpace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cBytes = 0;
|
||||
for (int i = 0; i < LengthSize; i++) {
|
||||
m_cBytes <<= 8;
|
||||
m_cBytes += *pBuffer++;
|
||||
}
|
||||
|
||||
if ((m_cBytes+LengthSize) <= cSpace) {
|
||||
m_pStart = pBuffer;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// this is not length-delimited: we must look for start codes
|
||||
const BYTE *pBegin;
|
||||
if (GetStartCode(pBegin, pBuffer, cSpace)) {
|
||||
m_pStart = pBuffer;
|
||||
m_pStartCodeStart = pBegin;
|
||||
|
||||
// either we find another startcode, or we continue to the
|
||||
// buffer end (if this is the last block of data)
|
||||
if (GetStartCode(pBegin, pBuffer, cSpace)) {
|
||||
m_cBytes = int(pBegin - m_pStart);
|
||||
return true;
|
||||
} else if (bEnd) {
|
||||
// current element extends to end of buffer
|
||||
m_cBytes = cSpace;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// bitwise access to data
|
||||
void
|
||||
LFNALUnit::ResetBitstream(){
|
||||
m_idx = 0;
|
||||
m_nBits = 0;
|
||||
m_cZeros = 0;
|
||||
}
|
||||
|
||||
void
|
||||
LFNALUnit::Skip(int nBits){
|
||||
if (nBits < m_nBits) {
|
||||
m_nBits -= nBits;
|
||||
} else {
|
||||
nBits -= m_nBits;
|
||||
while (nBits >= 8) {
|
||||
GetBYTE();
|
||||
nBits -= 8;
|
||||
}
|
||||
if (nBits) {
|
||||
m_byte = GetBYTE();
|
||||
m_nBits = 8;
|
||||
|
||||
m_nBits -= nBits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get the next byte, removing emulation prevention bytes
|
||||
BYTE
|
||||
LFNALUnit::GetBYTE(){
|
||||
if (m_idx >= m_cBytes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE b = m_pStart[m_idx++];
|
||||
|
||||
// to avoid start-code emulation, a byte 0x03 is inserted
|
||||
// after any 00 00 pair. Discard that here.
|
||||
if (b == 0) {
|
||||
m_cZeros++;
|
||||
if ((m_idx < m_cBytes) && (m_cZeros == 2) && (m_pStart[m_idx] == 0x03)) {
|
||||
m_idx++;
|
||||
m_cZeros = 0;
|
||||
}
|
||||
} else {
|
||||
m_cZeros = 0;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
LFNALUnit::GetBit(){
|
||||
if (m_nBits == 0) {
|
||||
m_byte = GetBYTE();
|
||||
m_nBits = 8;
|
||||
}
|
||||
m_nBits--;
|
||||
return (m_byte >> m_nBits) & 0x1;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
LFNALUnit::GetWord(int nBits){
|
||||
unsigned long u = 0;
|
||||
while (nBits > 0) {
|
||||
u <<= 1;
|
||||
u |= GetBit();
|
||||
nBits--;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
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.
|
||||
// That is, if you see
|
||||
// 0001010
|
||||
// You have three leading zeros, so there are three data bits (010)
|
||||
// counting up from a base of 111: thus 111 + 010 = 1001 = 9
|
||||
int cZeros = 0;
|
||||
while (GetBit() == 0) {
|
||||
cZeros++;
|
||||
}
|
||||
return GetWord(cZeros) + ((1 << cZeros)-1);
|
||||
}
|
||||
|
||||
long
|
||||
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
|
||||
// 0, 1, 2, 3, 4
|
||||
// mean
|
||||
// 0, 1, -1, 2, -2 etc
|
||||
|
||||
unsigned long UE = GetUE();
|
||||
bool bPositive = UE & 1;
|
||||
long SE = (UE + 1) >> 1;
|
||||
if (!bPositive) {
|
||||
SE = -SE;
|
||||
}
|
||||
return SE;
|
||||
}
|
||||
|
||||
// --- sequence params parsing ---------------
|
||||
LFSeqParamSet::LFSeqParamSet()
|
||||
: m_cx(0),
|
||||
m_cy(0),
|
||||
m_FrameBits(0){
|
||||
// SetRect(&m_rcFrame, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
ScalingList(int size, LFNALUnit *pnalu){
|
||||
long lastScale = 8;
|
||||
long nextScale = 8;
|
||||
for (int j = 0; j < size; j++) {
|
||||
if (nextScale != 0) {
|
||||
long delta = pnalu->GetSE();
|
||||
nextScale = (lastScale + delta + 256) %256;
|
||||
}
|
||||
int scaling_list_j = (nextScale == 0) ? (int)lastScale : (int)nextScale;
|
||||
lastScale = scaling_list_j;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LFSeqParamSet::Parse(LFNALUnit *pnalu){
|
||||
if (pnalu->Type() != LFNALUnit::NAL_Sequence_Params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// with the UE/SE type encoding, we must decode all the values
|
||||
// to get through to the ones we want
|
||||
pnalu->ResetBitstream();
|
||||
pnalu->Skip(8); // type
|
||||
m_Profile =(int) pnalu->GetWord(8);
|
||||
m_Compatibility = (BYTE)pnalu->GetWord(8);
|
||||
m_Level = (int)pnalu->GetWord(8);
|
||||
|
||||
/*int seq_param_id =*/ pnalu->GetUE();
|
||||
|
||||
if ((m_Profile == 100) || (m_Profile == 110) || (m_Profile == 122) || (m_Profile == 144)) {
|
||||
int chroma_fmt = (int)pnalu->GetUE();
|
||||
if (chroma_fmt == 3) {
|
||||
pnalu->Skip(1);
|
||||
}
|
||||
/* int bit_depth_luma_minus8 = */ pnalu->GetUE();
|
||||
/* int bit_depth_chroma_minus8 = */ pnalu->GetUE();
|
||||
pnalu->Skip(1);
|
||||
int seq_scaling_matrix_present = (int)pnalu->GetBit();
|
||||
if (seq_scaling_matrix_present) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (pnalu->GetBit()) {
|
||||
if (i < 6) {
|
||||
ScalingList(16, pnalu);
|
||||
} else {
|
||||
ScalingList(64, pnalu);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int log2_frame_minus4 = (int)pnalu->GetUE();
|
||||
m_FrameBits = log2_frame_minus4 + 4;
|
||||
int POCtype = (int)pnalu->GetUE();
|
||||
if (POCtype == 0) {
|
||||
/*int log2_poc_minus4 =*/ pnalu->GetUE();
|
||||
} else if (POCtype == 1) {
|
||||
pnalu->Skip(1); // delta always zero
|
||||
/*int nsp_offset =*/ pnalu->GetSE();
|
||||
/*int nsp_top_to_bottom = */ pnalu->GetSE();
|
||||
int num_ref_in_cycle = (int)pnalu->GetUE();
|
||||
for (int i = 0; i < num_ref_in_cycle; i++) {
|
||||
/*int sf_offset =*/ pnalu->GetSE();
|
||||
}
|
||||
} else if (POCtype != 2) {
|
||||
return false;
|
||||
}
|
||||
// else for POCtype == 2, no additional data in stream
|
||||
|
||||
/*int num_ref_frames =*/ pnalu->GetUE();
|
||||
/*int gaps_allowed =*/ pnalu->GetBit();
|
||||
|
||||
int mbs_width = (int)pnalu->GetUE();
|
||||
int mbs_height = (int)pnalu->GetUE();
|
||||
m_cx = (mbs_width+1) * 16;
|
||||
m_cy = (mbs_height+1) * 16;
|
||||
|
||||
// smoke test validation of sps
|
||||
if ((m_cx > 2000) || (m_cy > 2000)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if this is false, then sizes are field sizes and need adjusting
|
||||
m_bFrameOnly = pnalu->GetBit() ? true : false;
|
||||
|
||||
if (!m_bFrameOnly) {
|
||||
pnalu->Skip(1); // adaptive frame/field
|
||||
}
|
||||
pnalu->Skip(1); // direct 8x8
|
||||
|
||||
#if 0
|
||||
SetRect(&m_rcFrame, 0, 0, 0, 0);
|
||||
bool bCrop = pnalu->GetBit() ? true : false;
|
||||
if (bCrop) {
|
||||
// get cropping rect
|
||||
// store as exclusive, pixel parameters relative to frame
|
||||
m_rcFrame.left = pnalu->GetUE() * 2;
|
||||
m_rcFrame.right = pnalu->GetUE() * 2;
|
||||
m_rcFrame.top = pnalu->GetUE() * 2;
|
||||
m_rcFrame.bottom = pnalu->GetUE() * 2;
|
||||
}
|
||||
|
||||
if (!IsRectEmpty(&m_rcFrame)) {
|
||||
m_rcFrame.right = m_cx - m_rcFrame.right;
|
||||
m_rcFrame.bottom = m_cy - m_rcFrame.bottom;
|
||||
}
|
||||
#endif
|
||||
// adjust rect from 2x2 units to pixels
|
||||
|
||||
if (!m_bFrameOnly) {
|
||||
// adjust heights from field to frame
|
||||
m_cy *= 2;
|
||||
#if 0
|
||||
m_rcFrame.top *= 2;
|
||||
m_rcFrame.bottom *= 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
// .. rest are not interesting yet
|
||||
m_nalu = *pnalu;
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- slice header --------------------
|
||||
bool
|
||||
LFSliceHeader::Parse(LFNALUnit *pnalu){
|
||||
switch (pnalu->Type()) {
|
||||
case LFNALUnit::NAL_IDR_Slice:
|
||||
case LFNALUnit::NAL_Slice:
|
||||
case LFNALUnit::NAL_PartitionA:
|
||||
// all these begin with a slice header
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// slice header has the 1-byte type, then one UE value,
|
||||
// then the frame number.
|
||||
pnalu->ResetBitstream();
|
||||
pnalu->Skip(8); // NALU type
|
||||
pnalu->GetUE(); // first mb in slice
|
||||
pnalu->GetUE(); // slice type
|
||||
pnalu->GetUE(); // pic param set id
|
||||
|
||||
m_framenum = (int)pnalu->GetWord(m_nBitsFrame);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --- SEI ----------------------
|
||||
|
||||
|
||||
LFSEIMessage::LFSEIMessage(LFNALUnit *pnalu){
|
||||
m_pnalu = pnalu;
|
||||
const BYTE *p = pnalu->Start();
|
||||
p++; // nalu type byte
|
||||
m_type = 0;
|
||||
while (*p == 0xff) {
|
||||
m_type += 255;
|
||||
p++;
|
||||
}
|
||||
m_type += *p;
|
||||
p++;
|
||||
m_length = 0;
|
||||
while (*p == 0xff) {
|
||||
m_type += 255;
|
||||
p++;
|
||||
}
|
||||
m_length += *p;
|
||||
p++;
|
||||
m_idxPayload = int(p - m_pnalu->Start());
|
||||
}
|
||||
|
||||
LFavcCHeader::LFavcCHeader(const BYTE *header, int cBytes){
|
||||
if (cBytes < 8) {
|
||||
return;
|
||||
}
|
||||
const BYTE *pEnd = header + cBytes;
|
||||
|
||||
int cSeq = header[5] & 0x1f;
|
||||
header += 6;
|
||||
for (int i = 0; i < cSeq; i++) {
|
||||
if ((header+2) > pEnd) {
|
||||
return;
|
||||
}
|
||||
int cThis = (header[0] << 8) + header[1];
|
||||
header += 2;
|
||||
if ((header+cThis) > pEnd) {
|
||||
return;
|
||||
}
|
||||
if (i == 0) {
|
||||
LFNALUnit n(header, cThis);
|
||||
m_sps = n;
|
||||
}
|
||||
header += cThis;
|
||||
}
|
||||
if ((header + 3) >= pEnd) {
|
||||
return;
|
||||
}
|
||||
int cPPS = header[0];
|
||||
if (cPPS > 0) {
|
||||
int cThis = (header[1] << 8) + header[2];
|
||||
header += 3;
|
||||
LFNALUnit n(header, cThis);
|
||||
m_pps = n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
|
||||
//
|
||||
// NALUnit.h
|
||||
//
|
||||
// Basic parsing of H.264 NAL Units
|
||||
//
|
||||
// Geraint Davies, March 2004
|
||||
//
|
||||
// Copyright (c) GDCL 2004-2008 http://www.gdcl.co.uk/license.htm
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned long ULONG;
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
class LFNALUnit
|
||||
{
|
||||
public:
|
||||
LFNALUnit();
|
||||
LFNALUnit(const BYTE* pStart, int len){
|
||||
m_pStart = m_pStartCodeStart = pStart;
|
||||
m_cBytes = len;
|
||||
ResetBitstream();
|
||||
}
|
||||
virtual ~LFNALUnit() {
|
||||
}
|
||||
|
||||
// assignment copies a pointer into a fixed buffer managed elsewhere. We do not copy the data
|
||||
LFNALUnit(const LFNALUnit &r){
|
||||
m_pStart = r.m_pStart;
|
||||
m_cBytes = r.m_cBytes;
|
||||
ResetBitstream();
|
||||
}
|
||||
const LFNALUnit& operator = (const LFNALUnit &r)
|
||||
{
|
||||
m_pStart = r.m_pStart;
|
||||
m_cBytes = r.m_cBytes;
|
||||
ResetBitstream();
|
||||
return *this;
|
||||
}
|
||||
|
||||
enum eNALType {
|
||||
NAL_Slice = 1,
|
||||
NAL_PartitionA = 2,
|
||||
NAL_PartitionB = 3,
|
||||
NAL_PartitionC = 4,
|
||||
NAL_IDR_Slice = 5,
|
||||
NAL_SEI = 6,
|
||||
NAL_Sequence_Params = 7,
|
||||
NAL_Picture_Params = 8,
|
||||
NAL_AUD = 9,
|
||||
};
|
||||
|
||||
// identify a NAL unit within a buffer.
|
||||
// If LengthSize is non-zero, it is the number of bytes
|
||||
// of length field we expect. Otherwise, we expect start-code
|
||||
// delimiters.
|
||||
bool Parse(const BYTE *pBuffer, int cSpace, int LengthSize, bool bEnd);
|
||||
|
||||
eNALType Type(){
|
||||
if (m_pStart == NULL) {
|
||||
return eNALType(0);
|
||||
}
|
||||
return eNALType(m_pStart[0] & 0x1F);
|
||||
}
|
||||
|
||||
int Length(){
|
||||
return m_cBytes;
|
||||
}
|
||||
|
||||
const BYTE *Start(){
|
||||
return m_pStart;
|
||||
}
|
||||
|
||||
// bitwise access to data
|
||||
void ResetBitstream();
|
||||
void Skip(int nBits);
|
||||
|
||||
unsigned long GetWord(int nBits);
|
||||
unsigned long GetUE();
|
||||
long GetSE();
|
||||
BYTE GetBYTE();
|
||||
unsigned long GetBit();
|
||||
|
||||
const BYTE *StartCodeStart() {
|
||||
return m_pStartCodeStart;
|
||||
}
|
||||
|
||||
private:
|
||||
bool GetStartCode(const BYTE *& pBegin, const BYTE *& pStart, int& cRemain);
|
||||
|
||||
private:
|
||||
const BYTE *m_pStartCodeStart;
|
||||
const BYTE *m_pStart;
|
||||
int m_cBytes;
|
||||
|
||||
// bitstream access
|
||||
int m_idx;
|
||||
int m_nBits;
|
||||
BYTE m_byte;
|
||||
int m_cZeros;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// simple parser for the Sequence parameter set things that we need
|
||||
class LFSeqParamSet
|
||||
{
|
||||
public:
|
||||
LFSeqParamSet();
|
||||
bool Parse(LFNALUnit *pnalu);
|
||||
int FrameBits(){
|
||||
return m_FrameBits;
|
||||
}
|
||||
|
||||
long EncodedWidth(){
|
||||
return m_cx;
|
||||
}
|
||||
|
||||
long EncodedHeight(){
|
||||
return m_cy;
|
||||
}
|
||||
|
||||
#if 0
|
||||
long CroppedWidth(){
|
||||
if (IsRectEmpty(&m_rcFrame)) {
|
||||
return EncodedWidth();
|
||||
}
|
||||
return m_rcFrame.right - m_rcFrame.left;
|
||||
}
|
||||
|
||||
long CroppedHeight(){
|
||||
if (IsRectEmpty(&m_rcFrame)) {
|
||||
return EncodedHeight();
|
||||
}
|
||||
return m_rcFrame.bottom - m_rcFrame.top;
|
||||
}
|
||||
|
||||
RECT *CropRect(){
|
||||
return &m_rcFrame;
|
||||
}
|
||||
|
||||
#endif
|
||||
bool Interlaced(){
|
||||
return !m_bFrameOnly;
|
||||
}
|
||||
|
||||
unsigned int Profile() {
|
||||
return m_Profile;
|
||||
}
|
||||
|
||||
unsigned int Level() {
|
||||
return m_Level;
|
||||
}
|
||||
|
||||
BYTE Compat() {
|
||||
return m_Compatibility;
|
||||
}
|
||||
|
||||
LFNALUnit *NALU() {
|
||||
return &m_nalu;
|
||||
}
|
||||
|
||||
private:
|
||||
LFNALUnit m_nalu;
|
||||
int m_FrameBits;
|
||||
long m_cx;
|
||||
long m_cy;
|
||||
// RECT m_rcFrame;
|
||||
bool m_bFrameOnly;
|
||||
|
||||
int m_Profile;
|
||||
int m_Level;
|
||||
BYTE m_Compatibility;
|
||||
};
|
||||
|
||||
// extract frame num from slice headers
|
||||
class LFSliceHeader
|
||||
{
|
||||
public:
|
||||
LFSliceHeader(int nBitsFrame)
|
||||
: m_framenum(0),
|
||||
m_nBitsFrame(nBitsFrame){
|
||||
}
|
||||
|
||||
bool Parse(LFNALUnit *pnalu);
|
||||
int FrameNum(){
|
||||
return m_framenum;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_framenum;
|
||||
int m_nBitsFrame;
|
||||
};
|
||||
|
||||
// SEI message structure
|
||||
class LFSEIMessage
|
||||
{
|
||||
public:
|
||||
LFSEIMessage(LFNALUnit* pnalu);
|
||||
int Type() {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
int Length() {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
const BYTE *Payload() {
|
||||
return m_pnalu->Start() + m_idxPayload;
|
||||
}
|
||||
|
||||
private:
|
||||
LFNALUnit *m_pnalu;
|
||||
int m_type;
|
||||
int m_length;
|
||||
int m_idxPayload;
|
||||
};
|
||||
|
||||
// avcC structure from MP4
|
||||
class LFavcCHeader
|
||||
{
|
||||
public:
|
||||
LFavcCHeader(const BYTE* header, int cBytes);
|
||||
LFNALUnit *sps() {
|
||||
return &m_sps;
|
||||
}
|
||||
|
||||
LFNALUnit *pps() {
|
||||
return &m_pps;
|
||||
}
|
||||
|
||||
private:
|
||||
LFNALUnit m_sps;
|
||||
LFNALUnit m_pps;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// VideoEncoder.h
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 14/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVAssetWriter.h>
|
||||
#import <AVFoundation/AVAssetWriterInput.h>
|
||||
#import <AVFoundation/AVMediaFormat.h>
|
||||
#import <AVFoundation/AVVideoSettings.h>
|
||||
|
||||
@interface LFVideoEncoder : NSObject
|
||||
|
||||
|
||||
@property NSString *path;
|
||||
@property (nonatomic, readonly) NSUInteger 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;
|
||||
- (BOOL)encodeFrame:(CMSampleBufferRef)sampleBuffer;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// LFVideoEncoder.m
|
||||
// Encoder Demo
|
||||
//
|
||||
// Created by Geraint Davies on 14/01/2013.
|
||||
// Copyright (c) 2013 GDCL http://www.gdcl.co.uk/license.htm
|
||||
//
|
||||
|
||||
#import "LFVideoEncoder.h"
|
||||
|
||||
@implementation LFVideoEncoder
|
||||
{
|
||||
AVAssetWriter *_writer;
|
||||
AVAssetWriterInput *_writerInput;
|
||||
NSString *_path;
|
||||
}
|
||||
|
||||
@synthesize path = _path;
|
||||
|
||||
+ (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;
|
||||
}
|
||||
|
||||
- (void)initPath:(NSString *)path Height:(int)height andWidth:(int)width bitrate:(int)bitrate {
|
||||
self.path = path;
|
||||
_bitrate = bitrate;
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:self.path error:nil];
|
||||
NSURL *url = [NSURL fileURLWithPath:self.path];
|
||||
|
||||
NSDictionary *settings = @{
|
||||
AVVideoCodecKey: AVVideoCodecH264,
|
||||
AVVideoWidthKey: @(width),
|
||||
AVVideoHeightKey: @(height),
|
||||
AVVideoCompressionPropertiesKey: @{
|
||||
AVVideoAverageBitRateKey: @(self.bitrate),
|
||||
AVVideoMaxKeyFrameIntervalKey: @(30 * 2),
|
||||
AVVideoProfileLevelKey: AVVideoProfileLevelH264Baseline41,
|
||||
AVVideoAllowFrameReorderingKey: @NO,
|
||||
}
|
||||
};
|
||||
_writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
|
||||
_writerInput.expectsMediaDataInRealTime = YES;
|
||||
|
||||
_writer = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeQuickTimeMovie error:nil];
|
||||
[_writer addInput:_writerInput];
|
||||
}
|
||||
|
||||
- (void)finishWithCompletionHandler:(void (^)(void))handler {
|
||||
if (_writer.status == AVAssetWriterStatusWriting) {
|
||||
[_writer finishWritingWithCompletionHandler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)encodeFrame:(CMSampleBufferRef)sampleBuffer {
|
||||
if (CMSampleBufferDataIsReady(sampleBuffer)) {
|
||||
if (_writer.status == AVAssetWriterStatusUnknown) {
|
||||
CMTime startTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
|
||||
[_writer startWriting];
|
||||
[_writer startSessionAtSourceTime:startTime];
|
||||
}
|
||||
if (_writer.status == AVAssetWriterStatusFailed) {
|
||||
//NSLog(@"AVAssetWriterStatusFailed");
|
||||
return NO;
|
||||
}
|
||||
if (_writerInput.readyForMoreMediaData == YES) {
|
||||
[_writerInput appendSampleBuffer:sampleBuffer];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFAudioEncoding.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -11,21 +11,23 @@
|
||||
#import "LFAudioFrame.h"
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
|
||||
|
||||
|
||||
@protocol LFAudioEncoding;
|
||||
/// 编码器编码后回调
|
||||
@protocol LFAudioEncodingDelegate <NSObject>
|
||||
@required
|
||||
- (void)audioEncoder:(nullable id<LFAudioEncoding>)encoder audioFrame:(nullable LFAudioFrame*)frame;
|
||||
- (void)audioEncoder:(nullable id<LFAudioEncoding>)encoder audioFrame:(nullable LFAudioFrame *)frame;
|
||||
@end
|
||||
|
||||
/// 编码器抽象的接口
|
||||
@protocol LFAudioEncoding <NSObject>
|
||||
@required
|
||||
- (void)encodeAudioData:(AudioBufferList)inBufferList timeStamp:(uint64_t)timeStamp;
|
||||
- (void)encodeAudioData:(nullable NSData*)audioData timeStamp:(uint64_t)timeStamp;
|
||||
- (void)stopEncoder;
|
||||
@optional
|
||||
- (nullable instancetype)initWithAudioStreamConfiguration:(nullable LFLiveAudioConfiguration*)configuration;
|
||||
- (nullable instancetype)initWithAudioStreamConfiguration:(nullable LFLiveAudioConfiguration *)configuration;
|
||||
- (void)setDelegate:(nullable id<LFAudioEncodingDelegate>)delegate;
|
||||
- (nullable NSData*)adtsData:(NSInteger)channel rawDataLength:(NSInteger)rawDataLength;
|
||||
- (nullable NSData *)adtsData:(NSInteger)channel rawDataLength:(NSInteger)rawDataLength;
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// LFH264VideoEncoder
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFVideoEncoding.h"
|
||||
|
||||
@interface LFH264VideoEncoder : NSObject <LFVideoEncoding> {
|
||||
|
||||
}
|
||||
|
||||
- (void)shutdown;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,263 @@
|
||||
//
|
||||
// LFH264VideoEncoder
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
#import <mach/mach_time.h>
|
||||
#import "LFNALUnit.h"
|
||||
#import "LFAVEncoder.h"
|
||||
#import "LFH264VideoEncoder.h"
|
||||
#import "LFVideoFrame.h"
|
||||
|
||||
@interface LFH264VideoEncoder() {
|
||||
FILE *fp;
|
||||
NSInteger frameCount;
|
||||
BOOL enabledWriteVideoFile;
|
||||
}
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *configuration;
|
||||
@property (nonatomic, weak) id<LFVideoEncodingDelegate> h264Delegate;
|
||||
@property (nonatomic) BOOL isBackGround;
|
||||
@property (nonatomic) NSInteger currentVideoBitRate;
|
||||
@property (nonatomic, strong) dispatch_queue_t sendQueue;
|
||||
|
||||
@property (nonatomic, strong) LFAVEncoder *encoder;
|
||||
|
||||
@property (nonatomic, strong) NSData *naluStartCode;
|
||||
@property (nonatomic, strong) NSMutableData *videoSPSandPPS;
|
||||
@property (nonatomic, strong) NSMutableData *spsData;
|
||||
@property (nonatomic, strong) NSMutableData *ppsData;
|
||||
@property (nonatomic, strong) NSMutableData *sei;
|
||||
@property (nonatomic) CMTimeScale timescale;
|
||||
@property (nonatomic, strong) NSMutableArray *orphanedFrames;
|
||||
@property (nonatomic, strong) NSMutableArray *orphanedSEIFrames;
|
||||
@property (nonatomic) CMTime lastPTS;
|
||||
@end
|
||||
|
||||
@implementation LFH264VideoEncoder
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
- (instancetype)initWithVideoStreamConfiguration:(LFLiveVideoConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
NSLog(@"USE LF264VideoEncoder");
|
||||
_configuration = configuration;
|
||||
[self initCompressionSession];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initCompressionSession{
|
||||
_sendQueue = dispatch_queue_create("com.youku.laifeng.h264.sendframe", DISPATCH_QUEUE_SERIAL);
|
||||
[self initializeNALUnitStartCode];
|
||||
_lastPTS = kCMTimeInvalid;
|
||||
_timescale = 1000;
|
||||
frameCount = 0;
|
||||
#ifdef DEBUG
|
||||
enabledWriteVideoFile = NO;
|
||||
[self initForFilePath];
|
||||
#endif
|
||||
|
||||
_encoder = [LFAVEncoder encoderForHeight:(int)_configuration.videoSize.height andWidth:(int)_configuration.videoSize.width bitrate:(int)_configuration.videoBitRate];
|
||||
[_encoder encodeWithBlock:^int(NSArray* dataArray, CMTimeValue ptsValue) {
|
||||
[self incomingVideoFrames:dataArray ptsValue:ptsValue];
|
||||
return 0;
|
||||
} onParams:^int(NSData *data) {
|
||||
[self generateSPSandPPS];
|
||||
return 0;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) initializeNALUnitStartCode {
|
||||
NSUInteger naluLength = 4;
|
||||
uint8_t *nalu = (uint8_t*)malloc(naluLength * sizeof(uint8_t));
|
||||
nalu[0] = 0x00;
|
||||
nalu[1] = 0x00;
|
||||
nalu[2] = 0x00;
|
||||
nalu[3] = 0x01;
|
||||
_naluStartCode = [NSData dataWithBytesNoCopy:nalu length:naluLength freeWhenDone:YES];
|
||||
}
|
||||
|
||||
- (void) generateSPSandPPS {
|
||||
NSData* config = _encoder.getConfigData;
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
LFavcCHeader avcC((const BYTE*)[config bytes], (int)[config length]);
|
||||
LFSeqParamSet seqParams;
|
||||
seqParams.Parse(avcC.sps());
|
||||
|
||||
NSData* spsData = [NSData dataWithBytes:avcC.sps()->Start() length:avcC.sps()->Length()];
|
||||
NSData *ppsData = [NSData dataWithBytes:avcC.pps()->Start() length:avcC.pps()->Length()];
|
||||
|
||||
_spsData = [NSMutableData dataWithCapacity:avcC.sps()->Length()+_naluStartCode.length];
|
||||
_ppsData = [NSMutableData dataWithCapacity:avcC.pps()->Length()+_naluStartCode.length];
|
||||
|
||||
[_spsData appendData:_naluStartCode];
|
||||
[_spsData appendData:spsData];
|
||||
[_ppsData appendData:_naluStartCode];
|
||||
[_ppsData appendData:ppsData];
|
||||
|
||||
_videoSPSandPPS = [NSMutableData dataWithCapacity:avcC.sps()->Length() + avcC.pps()->Length() + _naluStartCode.length * 2];
|
||||
[_videoSPSandPPS appendData:_naluStartCode];
|
||||
[_videoSPSandPPS appendData:spsData];
|
||||
[_videoSPSandPPS appendData:_naluStartCode];
|
||||
[_videoSPSandPPS appendData:ppsData];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)setVideoBitRate:(NSInteger)videoBitRate{
|
||||
_currentVideoBitRate = videoBitRate;
|
||||
_encoder.bitrate = _currentVideoBitRate;
|
||||
}
|
||||
|
||||
- (NSInteger)videoBitRate{
|
||||
return _currentVideoBitRate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<LFVideoEncodingDelegate>)delegate{
|
||||
_h264Delegate = delegate;
|
||||
}
|
||||
|
||||
- (void)encodeVideoData:(CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp {
|
||||
|
||||
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
|
||||
CMVideoFormatDescriptionRef videoInfo = NULL;
|
||||
CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBuffer, &videoInfo);
|
||||
|
||||
CMTime frameTime = CMTimeMake(timeStamp, 1000);
|
||||
CMTime duration = CMTimeMake(1, (int32_t)_configuration.videoFrameRate);
|
||||
CMSampleTimingInfo timing = {duration, frameTime, kCMTimeInvalid};
|
||||
|
||||
CMSampleBufferRef sampleBuffer = NULL;
|
||||
CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, YES, NULL, NULL, videoInfo, &timing, &sampleBuffer);
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
|
||||
[_encoder encodeFrame:sampleBuffer];
|
||||
CFRelease(videoInfo);
|
||||
CFRelease(sampleBuffer);
|
||||
|
||||
frameCount++;
|
||||
}
|
||||
|
||||
- (void)addOrphanedFramesFromArray:(NSArray*)frames {
|
||||
for (NSData *data in frames) {
|
||||
unsigned char* pNal = (unsigned char*)[data bytes];
|
||||
int idc = pNal[0] & 0x60;
|
||||
int naltype = pNal[0] & 0x1f;
|
||||
if (idc == 0 && naltype == 6) { // SEI
|
||||
[self.orphanedSEIFrames addObject:data];
|
||||
} else {
|
||||
[self.orphanedFrames addObject:data];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)writeVideoFrames:(NSArray*)frames pts:(CMTime)pts {
|
||||
NSMutableArray *totalFrames = [NSMutableArray array];
|
||||
if (self.orphanedSEIFrames.count > 0) {
|
||||
[totalFrames addObjectsFromArray:self.orphanedSEIFrames];
|
||||
[self.orphanedSEIFrames removeAllObjects];
|
||||
}
|
||||
[totalFrames addObjectsFromArray:frames];
|
||||
|
||||
NSMutableData *aggregateFrameData = [NSMutableData data];
|
||||
//BOOL hasKeyframe = NO;
|
||||
|
||||
for (NSData *data in totalFrames) {
|
||||
unsigned char* pNal = (unsigned char*)[data bytes];
|
||||
int idc = pNal[0] & 0x60;
|
||||
int naltype = pNal[0] & 0x1f;
|
||||
NSData *videoData = nil;
|
||||
|
||||
if (idc == 0 && naltype == 6) { // SEI
|
||||
_sei = [NSMutableData dataWithData:data];
|
||||
continue;
|
||||
} else if (naltype == 5) { // IDR
|
||||
//hasKeyframe = YES;
|
||||
NSMutableData *IDRData = [NSMutableData dataWithData:_videoSPSandPPS];
|
||||
if (_sei) {
|
||||
[IDRData appendData:_naluStartCode];
|
||||
[IDRData appendData:_sei];
|
||||
_sei = nil;
|
||||
}
|
||||
[IDRData appendData:_naluStartCode];
|
||||
[IDRData appendData:data];
|
||||
videoData = IDRData;
|
||||
} else {
|
||||
NSMutableData *regularData = [NSMutableData dataWithData:_naluStartCode];
|
||||
[regularData appendData:data];
|
||||
videoData = regularData;
|
||||
}
|
||||
[aggregateFrameData appendData:videoData];
|
||||
|
||||
LFVideoFrame *videoFrame = [LFVideoFrame new];
|
||||
const char *dataBuffer = (const char *)aggregateFrameData.bytes;
|
||||
videoFrame.data = [NSMutableData dataWithBytes:dataBuffer + _naluStartCode.length length:aggregateFrameData.length - _naluStartCode.length];
|
||||
videoFrame.timestamp = pts.value;
|
||||
videoFrame.isKeyFrame = (naltype == 5);
|
||||
videoFrame.sps = _spsData;
|
||||
videoFrame.pps = _ppsData;
|
||||
|
||||
if(self.h264Delegate && [self.h264Delegate respondsToSelector:@selector(videoEncoder:videoFrame:)]){
|
||||
[self.h264Delegate videoEncoder:self videoFrame:videoFrame];
|
||||
}
|
||||
}
|
||||
|
||||
if (self->enabledWriteVideoFile) {
|
||||
fwrite(aggregateFrameData.bytes, 1, aggregateFrameData.length, self->fp);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) incomingVideoFrames:(NSArray*)frames ptsValue:(CMTimeValue)ptsValue {
|
||||
if (ptsValue == 0) {
|
||||
[self addOrphanedFramesFromArray:frames];
|
||||
return;
|
||||
}
|
||||
if (!_videoSPSandPPS) {
|
||||
[self generateSPSandPPS];
|
||||
}
|
||||
CMTime pts = CMTimeMake(ptsValue, _timescale);
|
||||
if (self.orphanedFrames.count > 0) {
|
||||
CMTime ptsDiff = CMTimeSubtract(pts, _lastPTS);
|
||||
NSUInteger orphanedFramesCount = self.orphanedFrames.count;
|
||||
// NSLog(@"lastPTS before first orphaned frame: %lld", _lastPTS.value);
|
||||
for (NSData *frame in self.orphanedFrames) {
|
||||
CMTime fakePTSDiff = CMTimeMultiplyByFloat64(ptsDiff, 1.0/(orphanedFramesCount + 1));
|
||||
CMTime fakePTS = CMTimeAdd(_lastPTS, fakePTSDiff);
|
||||
// NSLog(@"orphan frame fakePTS: %lld", fakePTS.value);
|
||||
[self writeVideoFrames:@[frame] pts:fakePTS];
|
||||
}
|
||||
// NSLog(@"pts after orphaned frame: %lld", pts.value);
|
||||
[self.orphanedFrames removeAllObjects];
|
||||
}
|
||||
|
||||
[self writeVideoFrames:frames pts:pts];
|
||||
_lastPTS = pts;
|
||||
}
|
||||
|
||||
|
||||
- (void) dealloc {
|
||||
[_encoder shutdown];
|
||||
}
|
||||
|
||||
- (void)shutdown {
|
||||
[_encoder encodeWithBlock:nil onParams:nil];
|
||||
}
|
||||
|
||||
- (void)initForFilePath {
|
||||
NSString *path = [self GetFilePathByfileName:@"IOSCamDemo.h264"];
|
||||
NSLog(@"%@", path);
|
||||
self->fp = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "wb");
|
||||
}
|
||||
|
||||
- (NSString *)GetFilePathByfileName:(NSString*)filename {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:filename];
|
||||
return writablePath;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFHardwareAudioEncoder.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFAudioEncoding.h"
|
||||
|
||||
@@ -2,15 +2,19 @@
|
||||
// LFHardwareAudioEncoder.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFHardwareAudioEncoder.h"
|
||||
|
||||
@interface LFHardwareAudioEncoder (){
|
||||
AudioConverterRef m_converter;
|
||||
char *leftBuf;
|
||||
char *aacBuf;
|
||||
NSInteger leftLength;
|
||||
FILE *fp;
|
||||
BOOL enabledWriteVideoFile;
|
||||
}
|
||||
@property (nonatomic, strong) LFLiveAudioConfiguration *configuration;
|
||||
@property (nonatomic, weak) id<LFAudioEncodingDelegate> aacDeleage;
|
||||
@@ -19,61 +23,122 @@
|
||||
|
||||
@implementation LFHardwareAudioEncoder
|
||||
|
||||
- (instancetype)initWithAudioStreamConfiguration:(LFLiveAudioConfiguration *)configuration{
|
||||
if(self = [super init]){
|
||||
- (instancetype)initWithAudioStreamConfiguration:(nullable LFLiveAudioConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
NSLog(@"USE LFHardwareAudioEncoder");
|
||||
_configuration = configuration;
|
||||
|
||||
if (!leftBuf) {
|
||||
leftBuf = malloc(_configuration.bufferLength);
|
||||
}
|
||||
|
||||
if (!aacBuf) {
|
||||
aacBuf = malloc(_configuration.bufferLength);
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
enabledWriteVideoFile = NO;
|
||||
[self initForFilePath];
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
if(aacBuf) free(aacBuf);
|
||||
- (void)dealloc {
|
||||
if (aacBuf) free(aacBuf);
|
||||
if (leftBuf) free(leftBuf);
|
||||
}
|
||||
|
||||
#pragma mark -- LFAudioEncoder
|
||||
- (void)setDelegate:(id<LFAudioEncodingDelegate>)delegate{
|
||||
- (void)setDelegate:(id<LFAudioEncodingDelegate>)delegate {
|
||||
_aacDeleage = delegate;
|
||||
}
|
||||
|
||||
- (void)encodeAudioData:(AudioBufferList)inBufferList timeStamp:(uint64_t)timeStamp{
|
||||
if (![self createAudioConvert]){
|
||||
- (void)encodeAudioData:(nullable NSData*)audioData timeStamp:(uint64_t)timeStamp {
|
||||
if (![self createAudioConvert]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!aacBuf){
|
||||
aacBuf = malloc(inBufferList.mBuffers[0].mDataByteSize);
|
||||
}
|
||||
|
||||
// 初始化一个输出缓冲列表
|
||||
AudioBufferList outBufferList;
|
||||
outBufferList.mNumberBuffers = 1;
|
||||
outBufferList.mBuffers[0].mNumberChannels = inBufferList.mBuffers[0].mNumberChannels;
|
||||
outBufferList.mBuffers[0].mDataByteSize = inBufferList.mBuffers[0].mDataByteSize; // 设置缓冲区大小
|
||||
outBufferList.mBuffers[0].mData = aacBuf; // 设置AAC缓冲区
|
||||
UInt32 outputDataPacketSize = 1;
|
||||
if (AudioConverterFillComplexBuffer(m_converter, inputDataProc, &inBufferList, &outputDataPacketSize, &outBufferList, NULL) != noErr){
|
||||
return;
|
||||
}
|
||||
LFAudioFrame *audioFrame = [LFAudioFrame new];
|
||||
audioFrame.timestamp = timeStamp;
|
||||
audioFrame.data = [NSData dataWithBytes:aacBuf length:outBufferList.mBuffers[0].mDataByteSize];
|
||||
|
||||
char exeData[2];
|
||||
exeData[0] = _configuration.asc[0];
|
||||
exeData[1] = _configuration.asc[1];
|
||||
audioFrame.audioInfo =[NSData dataWithBytes:exeData length:2];
|
||||
if(self.aacDeleage && [self.aacDeleage respondsToSelector:@selector(audioEncoder:audioFrame:)]){
|
||||
[self.aacDeleage audioEncoder:self audioFrame:audioFrame];
|
||||
if(leftLength + audioData.length >= self.configuration.bufferLength){
|
||||
///< 发送
|
||||
NSInteger totalSize = leftLength + audioData.length;
|
||||
NSInteger encodeCount = totalSize/self.configuration.bufferLength;
|
||||
char *totalBuf = malloc(totalSize);
|
||||
char *p = totalBuf;
|
||||
|
||||
memset(totalBuf, (int)totalSize, 0);
|
||||
memcpy(totalBuf, leftBuf, leftLength);
|
||||
memcpy(totalBuf + leftLength, audioData.bytes, audioData.length);
|
||||
|
||||
for(NSInteger index = 0;index < encodeCount;index++){
|
||||
[self encodeBuffer:p timeStamp:timeStamp];
|
||||
p += self.configuration.bufferLength;
|
||||
}
|
||||
|
||||
leftLength = totalSize%self.configuration.bufferLength;
|
||||
memset(leftBuf, 0, self.configuration.bufferLength);
|
||||
memcpy(leftBuf, totalBuf + (totalSize -leftLength), leftLength);
|
||||
|
||||
free(totalBuf);
|
||||
|
||||
}else{
|
||||
///< 积累
|
||||
memcpy(leftBuf+leftLength, audioData.bytes, audioData.length);
|
||||
leftLength = leftLength + audioData.length;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopEncoder{
|
||||
- (void)encodeBuffer:(char*)buf timeStamp:(uint64_t)timeStamp{
|
||||
|
||||
AudioBuffer inBuffer;
|
||||
inBuffer.mNumberChannels = 1;
|
||||
inBuffer.mData = buf;
|
||||
inBuffer.mDataByteSize = (UInt32)self.configuration.bufferLength;
|
||||
|
||||
AudioBufferList buffers;
|
||||
buffers.mNumberBuffers = 1;
|
||||
buffers.mBuffers[0] = inBuffer;
|
||||
|
||||
|
||||
// 初始化一个输出缓冲列表
|
||||
AudioBufferList outBufferList;
|
||||
outBufferList.mNumberBuffers = 1;
|
||||
outBufferList.mBuffers[0].mNumberChannels = inBuffer.mNumberChannels;
|
||||
outBufferList.mBuffers[0].mDataByteSize = inBuffer.mDataByteSize; // 设置缓冲区大小
|
||||
outBufferList.mBuffers[0].mData = aacBuf; // 设置AAC缓冲区
|
||||
UInt32 outputDataPacketSize = 1;
|
||||
if (AudioConverterFillComplexBuffer(m_converter, inputDataProc, &buffers, &outputDataPacketSize, &outBufferList, NULL) != noErr) {
|
||||
return;
|
||||
}
|
||||
|
||||
LFAudioFrame *audioFrame = [LFAudioFrame new];
|
||||
audioFrame.timestamp = timeStamp;
|
||||
audioFrame.data = [NSData dataWithBytes:aacBuf length:outBufferList.mBuffers[0].mDataByteSize];
|
||||
|
||||
char exeData[2];
|
||||
exeData[0] = _configuration.asc[0];
|
||||
exeData[1] = _configuration.asc[1];
|
||||
audioFrame.audioInfo = [NSData dataWithBytes:exeData length:2];
|
||||
if (self.aacDeleage && [self.aacDeleage respondsToSelector:@selector(audioEncoder:audioFrame:)]) {
|
||||
[self.aacDeleage audioEncoder:self audioFrame:audioFrame];
|
||||
}
|
||||
|
||||
if (self->enabledWriteVideoFile) {
|
||||
NSData *adts = [self adtsData:_configuration.numberOfChannels rawDataLength:audioFrame.data.length];
|
||||
fwrite(adts.bytes, 1, adts.length, self->fp);
|
||||
fwrite(audioFrame.data.bytes, 1, audioFrame.data.length, self->fp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)stopEncoder {
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
-(BOOL)createAudioConvert{ //根据输入样本初始化一个编码转换器
|
||||
if (m_converter != nil){
|
||||
- (BOOL)createAudioConvert { //根据输入样本初始化一个编码转换器
|
||||
if (m_converter != nil) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -89,10 +154,10 @@
|
||||
|
||||
AudioStreamBasicDescription outputFormat; // 这里开始是输出音频格式
|
||||
memset(&outputFormat, 0, sizeof(outputFormat));
|
||||
outputFormat.mSampleRate = inputFormat.mSampleRate; // 采样率保持一致
|
||||
outputFormat.mFormatID = kAudioFormatMPEG4AAC; // AAC编码 kAudioFormatMPEG4AAC kAudioFormatMPEG4AAC_HE_V2
|
||||
outputFormat.mSampleRate = inputFormat.mSampleRate; // 采样率保持一致
|
||||
outputFormat.mFormatID = kAudioFormatMPEG4AAC; // AAC编码 kAudioFormatMPEG4AAC kAudioFormatMPEG4AAC_HE_V2
|
||||
outputFormat.mChannelsPerFrame = (UInt32)_configuration.numberOfChannels;;
|
||||
outputFormat.mFramesPerPacket = 1024; // AAC一帧是1024个字节
|
||||
outputFormat.mFramesPerPacket = 1024; // AAC一帧是1024个字节
|
||||
|
||||
const OSType subtype = kAudioFormatMPEG4AAC;
|
||||
AudioClassDescription requestedCodecs[2] = {
|
||||
@@ -107,47 +172,31 @@
|
||||
kAppleHardwareAudioCodecManufacturer
|
||||
}
|
||||
};
|
||||
OSStatus result = AudioConverterNewSpecific(&inputFormat, &outputFormat, 2, requestedCodecs, &m_converter);
|
||||
|
||||
OSStatus result = AudioConverterNewSpecific(&inputFormat, &outputFormat, 2, requestedCodecs, &m_converter);;
|
||||
UInt32 outputBitrate = _configuration.audioBitrate;
|
||||
UInt32 propSize = sizeof(outputBitrate);
|
||||
|
||||
|
||||
if(result != noErr) return NO;
|
||||
if(result == noErr) {
|
||||
result = AudioConverterSetProperty(m_converter, kAudioConverterEncodeBitRate, propSize, &outputBitrate);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(AudioClassDescription*)getAudioClassDescriptionWithType:(UInt32)type fromManufacturer:(UInt32)manufacturer { // 获得相应的编码器
|
||||
static AudioClassDescription audioDesc;
|
||||
|
||||
UInt32 encoderSpecifier = type, size = 0;
|
||||
OSStatus status;
|
||||
|
||||
memset(&audioDesc, 0, sizeof(audioDesc));
|
||||
status = AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size);
|
||||
if (status) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
uint32_t count = size / sizeof(AudioClassDescription);
|
||||
AudioClassDescription descs[count];
|
||||
AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(encoderSpecifier), &encoderSpecifier, &size, descs);
|
||||
for (uint32_t i = 0; i < count; i++){
|
||||
if ((type == descs[i].mSubType) && (manufacturer == descs[i].mManufacturer)){
|
||||
memcpy(&audioDesc, &descs[i], sizeof(audioDesc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return &audioDesc;
|
||||
}
|
||||
|
||||
#pragma mark -- AudioCallBack
|
||||
OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData,AudioStreamPacketDescription **outDataPacketDescription, void *inUserData) { //<span style="font-family: Arial, Helvetica, sans-serif;">AudioConverterFillComplexBuffer 编码过程中,会要求这个函数来填充输入数据,也就是原始PCM数据</span>
|
||||
AudioBufferList bufferList = *(AudioBufferList*)inUserData;
|
||||
OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription * *outDataPacketDescription, void *inUserData) { //<span style="font-family: Arial, Helvetica, sans-serif;">AudioConverterFillComplexBuffer 编码过程中,会要求这个函数来填充输入数据,也就是原始PCM数据</span>
|
||||
AudioBufferList bufferList = *(AudioBufferList *)inUserData;
|
||||
ioData->mBuffers[0].mNumberChannels = 1;
|
||||
ioData->mBuffers[0].mData = bufferList.mBuffers[0].mData;
|
||||
ioData->mBuffers[0].mDataByteSize = bufferList.mBuffers[0].mDataByteSize;
|
||||
ioData->mBuffers[0].mData = bufferList.mBuffers[0].mData;
|
||||
ioData->mBuffers[0].mDataByteSize = bufferList.mBuffers[0].mDataByteSize;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -- Custom Method
|
||||
/**
|
||||
* Add ADTS header at the beginning of each and every AAC packet.
|
||||
* This is needed as MediaCodec encoder generates a packet of raw
|
||||
@@ -157,18 +206,18 @@ OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPacket
|
||||
* See: http://wiki.multimedia.cx/index.php?title=ADTS
|
||||
* Also: http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Channel_Configurations
|
||||
**/
|
||||
- (NSData*)adtsData:(NSInteger)channel rawDataLength:(NSInteger)rawDataLength {
|
||||
- (NSData *)adtsData:(NSInteger)channel rawDataLength:(NSInteger)rawDataLength {
|
||||
int adtsLength = 7;
|
||||
char *packet = malloc(sizeof(char) * adtsLength);
|
||||
// Variables Recycled by addADTStoPacket
|
||||
int profile = 2; //AAC LC
|
||||
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
|
||||
int freqIdx = 4; //44.1KHz
|
||||
NSInteger freqIdx = [self sampleRateIndex:self.configuration.audioSampleRate]; //44.1KHz
|
||||
int chanCfg = (int)channel; //MPEG-4 Audio Channel Configuration. 1 Channel front-center
|
||||
NSUInteger fullLength = adtsLength + rawDataLength;
|
||||
// fill in ADTS data
|
||||
packet[0] = (char)0xFF; // 11111111 = syncword
|
||||
packet[1] = (char)0xF9; // 1111 1 00 1 = syncword MPEG-2 Layer CRC
|
||||
packet[0] = (char)0xFF; // 11111111 = syncword
|
||||
packet[1] = (char)0xF9; // 1111 1 00 1 = syncword MPEG-2 Layer CRC
|
||||
packet[2] = (char)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));
|
||||
packet[3] = (char)(((chanCfg&3)<<6) + (fullLength>>11));
|
||||
packet[4] = (char)((fullLength&0x7FF) >> 3);
|
||||
@@ -178,4 +227,65 @@ OSStatus inputDataProc(AudioConverterRef inConverter, UInt32 *ioNumberDataPacket
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSInteger)sampleRateIndex:(NSInteger)frequencyInHz {
|
||||
NSInteger sampleRateIndex = 0;
|
||||
switch (frequencyInHz) {
|
||||
case 96000:
|
||||
sampleRateIndex = 0;
|
||||
break;
|
||||
case 88200:
|
||||
sampleRateIndex = 1;
|
||||
break;
|
||||
case 64000:
|
||||
sampleRateIndex = 2;
|
||||
break;
|
||||
case 48000:
|
||||
sampleRateIndex = 3;
|
||||
break;
|
||||
case 44100:
|
||||
sampleRateIndex = 4;
|
||||
break;
|
||||
case 32000:
|
||||
sampleRateIndex = 5;
|
||||
break;
|
||||
case 24000:
|
||||
sampleRateIndex = 6;
|
||||
break;
|
||||
case 22050:
|
||||
sampleRateIndex = 7;
|
||||
break;
|
||||
case 16000:
|
||||
sampleRateIndex = 8;
|
||||
break;
|
||||
case 12000:
|
||||
sampleRateIndex = 9;
|
||||
break;
|
||||
case 11025:
|
||||
sampleRateIndex = 10;
|
||||
break;
|
||||
case 8000:
|
||||
sampleRateIndex = 11;
|
||||
break;
|
||||
case 7350:
|
||||
sampleRateIndex = 12;
|
||||
break;
|
||||
default:
|
||||
sampleRateIndex = 15;
|
||||
}
|
||||
return sampleRateIndex;
|
||||
}
|
||||
|
||||
- (void)initForFilePath {
|
||||
NSString *path = [self GetFilePathByfileName:@"IOSCamDemo_HW.aac"];
|
||||
NSLog(@"%@", path);
|
||||
self->fp = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "wb");
|
||||
}
|
||||
|
||||
- (NSString *)GetFilePathByfileName:(NSString*)filename {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:filename];
|
||||
return writablePath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFHardwareVideoEncoder.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFVideoEncoding.h"
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// LFHardwareVideoEncoder.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFHardwareVideoEncoder.h"
|
||||
#import <VideoToolbox/VideoToolbox.h>
|
||||
|
||||
@@ -19,77 +18,76 @@
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *configuration;
|
||||
@property (nonatomic,weak) id<LFVideoEncodingDelegate> h264Delegate;
|
||||
@property (nonatomic) BOOL isBackGround;
|
||||
@property (nonatomic, weak) id<LFVideoEncodingDelegate> h264Delegate;
|
||||
@property (nonatomic) NSInteger currentVideoBitRate;
|
||||
@property (nonatomic) BOOL isBackGround;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFHardwareVideoEncoder
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
- (instancetype)initWithVideoStreamConfiguration:(LFLiveVideoConfiguration *)configuration{
|
||||
if(self = [super init]){
|
||||
- (instancetype)initWithVideoStreamConfiguration:(LFLiveVideoConfiguration *)configuration {
|
||||
if (self = [super init]) {
|
||||
NSLog(@"USE LFHardwareVideoEncoder");
|
||||
_configuration = configuration;
|
||||
[self initCompressionSession];
|
||||
|
||||
[self resetCompressionSession];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterBackground:) name:UIApplicationWillResignActiveNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
#ifdef DEBUG
|
||||
enabledWriteVideoFile = NO;
|
||||
[self initForFilePath];
|
||||
#endif
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterBackground:) name:UIApplicationWillResignActiveNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initCompressionSession{
|
||||
if(compressionSession){
|
||||
- (void)resetCompressionSession {
|
||||
if (compressionSession) {
|
||||
VTCompressionSessionCompleteFrames(compressionSession, kCMTimeInvalid);
|
||||
|
||||
|
||||
VTCompressionSessionInvalidate(compressionSession);
|
||||
CFRelease(compressionSession);
|
||||
compressionSession = NULL;
|
||||
}
|
||||
|
||||
|
||||
OSStatus status = VTCompressionSessionCreate(NULL, _configuration.videoSize.width, _configuration.videoSize.height, kCMVideoCodecType_H264, NULL, NULL, NULL, VideoCompressonOutputCallback, (__bridge void *)self, &compressionSession);
|
||||
if(status != noErr){
|
||||
if (status != noErr) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_currentVideoBitRate = _configuration.videoBitRate;
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration,(__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, (__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, (__bridge CFTypeRef)@(_configuration.videoMaxKeyframeInterval/_configuration.videoFrameRate));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_ExpectedFrameRate, (__bridge CFTypeRef)@(_configuration.videoFrameRate));
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(_configuration.videoBitRate));
|
||||
NSArray *limit = @[@(_configuration.videoBitRate * 1.5/8),@(1)];
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)setVideoBitRate:(NSInteger)videoBitRate{
|
||||
- (void)setVideoBitRate:(NSInteger)videoBitRate {
|
||||
if(_isBackGround) return;
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_AverageBitRate, (__bridge CFTypeRef)@(videoBitRate));
|
||||
NSArray *limit = @[@(videoBitRate * 1.5/8),@(1)];
|
||||
NSArray *limit = @[@(videoBitRate * 1.5/8), @(1)];
|
||||
VTSessionSetProperty(compressionSession, kVTCompressionPropertyKey_DataRateLimits, (__bridge CFArrayRef)limit);
|
||||
_currentVideoBitRate = videoBitRate;
|
||||
}
|
||||
|
||||
-(NSInteger)videoBitRate{
|
||||
- (NSInteger)videoBitRate {
|
||||
return _currentVideoBitRate;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
if(compressionSession != NULL)
|
||||
{
|
||||
- (void)dealloc {
|
||||
if (compressionSession != NULL) {
|
||||
VTCompressionSessionCompleteFrames(compressionSession, kCMTimeInvalid);
|
||||
|
||||
|
||||
VTCompressionSessionInvalidate(compressionSession);
|
||||
CFRelease(compressionSession);
|
||||
compressionSession = NULL;
|
||||
@@ -98,90 +96,88 @@
|
||||
}
|
||||
|
||||
#pragma mark -- LFVideoEncoder
|
||||
- (void)encodeVideoData:(CVImageBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp{
|
||||
- (void)encodeVideoData:(CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp {
|
||||
if(_isBackGround) return;
|
||||
|
||||
frameCount ++;
|
||||
CMTime presentationTimeStamp = CMTimeMake(frameCount, 1000);
|
||||
frameCount++;
|
||||
CMTime presentationTimeStamp = CMTimeMake(frameCount, (int32_t)_configuration.videoFrameRate);
|
||||
VTEncodeInfoFlags flags;
|
||||
CMTime duration = CMTimeMake(1, (int32_t)_configuration.videoFrameRate);
|
||||
|
||||
|
||||
NSDictionary *properties = nil;
|
||||
if(frameCount % (int32_t)_configuration.videoMaxKeyframeInterval == 0){
|
||||
if (frameCount % (int32_t)_configuration.videoMaxKeyframeInterval == 0) {
|
||||
properties = @{(__bridge NSString *)kVTEncodeFrameOptionKey_ForceKeyFrame: @YES};
|
||||
}
|
||||
NSNumber *timeNumber = @(timeStamp);
|
||||
|
||||
VTCompressionSessionEncodeFrame(compressionSession, pixelBuffer, presentationTimeStamp, duration, (__bridge CFDictionaryRef)properties, (__bridge_retained void *)timeNumber, &flags);
|
||||
|
||||
OSStatus status = VTCompressionSessionEncodeFrame(compressionSession, pixelBuffer, presentationTimeStamp, duration, (__bridge CFDictionaryRef)properties, (__bridge_retained void *)timeNumber, &flags);
|
||||
if(status != noErr){
|
||||
[self resetCompressionSession];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopEncoder{
|
||||
- (void)stopEncoder {
|
||||
VTCompressionSessionCompleteFrames(compressionSession, kCMTimeIndefinite);
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id<LFVideoEncodingDelegate>)delegate{
|
||||
- (void)setDelegate:(id<LFVideoEncodingDelegate>)delegate {
|
||||
_h264Delegate = delegate;
|
||||
}
|
||||
|
||||
#pragma mark -- NSNotification
|
||||
#pragma mark -- Notification
|
||||
- (void)willEnterBackground:(NSNotification*)notification{
|
||||
_isBackGround = YES;
|
||||
}
|
||||
|
||||
- (void)willEnterForeground:(NSNotification*)notification{
|
||||
[self initCompressionSession];
|
||||
[self resetCompressionSession];
|
||||
_isBackGround = NO;
|
||||
}
|
||||
|
||||
#pragma mark -- VideoCallBack
|
||||
static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer)
|
||||
{
|
||||
if(!sampleBuffer) return;
|
||||
static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer){
|
||||
if (!sampleBuffer) return;
|
||||
CFArrayRef array = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, true);
|
||||
if(!array) return;
|
||||
if (!array) return;
|
||||
CFDictionaryRef dic = (CFDictionaryRef)CFArrayGetValueAtIndex(array, 0);
|
||||
if(!dic) return;
|
||||
|
||||
if (!dic) return;
|
||||
|
||||
BOOL keyframe = !CFDictionaryContainsKey(dic, kCMSampleAttachmentKey_NotSync);
|
||||
uint64_t timeStamp = [((__bridge_transfer NSNumber*)VTFrameRef) longLongValue];
|
||||
|
||||
uint64_t timeStamp = [((__bridge_transfer NSNumber *)VTFrameRef) longLongValue];
|
||||
|
||||
LFHardwareVideoEncoder *videoEncoder = (__bridge LFHardwareVideoEncoder *)VTref;
|
||||
if(status != noErr){
|
||||
if (status != noErr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyframe && !videoEncoder->sps)
|
||||
{
|
||||
|
||||
if (keyframe && !videoEncoder->sps) {
|
||||
CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);
|
||||
|
||||
|
||||
size_t sparameterSetSize, sparameterSetCount;
|
||||
const uint8_t *sparameterSet;
|
||||
OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 0, &sparameterSet, &sparameterSetSize, &sparameterSetCount, 0 );
|
||||
if (statusCode == noErr)
|
||||
{
|
||||
OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 0, &sparameterSet, &sparameterSetSize, &sparameterSetCount, 0);
|
||||
if (statusCode == noErr) {
|
||||
size_t pparameterSetSize, pparameterSetCount;
|
||||
const uint8_t *pparameterSet;
|
||||
OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 1, &pparameterSet, &pparameterSetSize, &pparameterSetCount, 0 );
|
||||
if (statusCode == noErr)
|
||||
{
|
||||
OSStatus statusCode = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 1, &pparameterSet, &pparameterSetSize, &pparameterSetCount, 0);
|
||||
if (statusCode == noErr) {
|
||||
videoEncoder->sps = [NSData dataWithBytes:sparameterSet length:sparameterSetSize];
|
||||
videoEncoder->pps = [NSData dataWithBytes:pparameterSet length:pparameterSetSize];
|
||||
|
||||
if(videoEncoder->enabledWriteVideoFile){
|
||||
|
||||
if (videoEncoder->enabledWriteVideoFile) {
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
uint8_t header[] = {0x00,0x00,0x00,0x01};
|
||||
uint8_t header[] = {0x00, 0x00, 0x00, 0x01};
|
||||
[data appendBytes:header length:4];
|
||||
[data appendData:videoEncoder->sps];
|
||||
[data appendBytes:header length:4];
|
||||
[data appendData:videoEncoder->pps];
|
||||
fwrite(data.bytes, 1,data.length,videoEncoder->fp);
|
||||
fwrite(data.bytes, 1, data.length, videoEncoder->fp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
CMBlockBufferRef dataBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
|
||||
size_t length, totalLength;
|
||||
char *dataPointer;
|
||||
@@ -193,7 +189,7 @@ static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatu
|
||||
// Read the NAL unit length
|
||||
uint32_t NALUnitLength = 0;
|
||||
memcpy(&NALUnitLength, dataPointer + bufferOffset, AVCCHeaderLength);
|
||||
|
||||
|
||||
NALUnitLength = CFSwapInt32BigToHost(NALUnitLength);
|
||||
|
||||
LFVideoFrame *videoFrame = [LFVideoFrame new];
|
||||
@@ -202,56 +198,44 @@ static void VideoCompressonOutputCallback(void *VTref, void *VTFrameRef, OSStatu
|
||||
videoFrame.isKeyFrame = keyframe;
|
||||
videoFrame.sps = videoEncoder->sps;
|
||||
videoFrame.pps = videoEncoder->pps;
|
||||
|
||||
if(videoEncoder.h264Delegate && [videoEncoder.h264Delegate respondsToSelector:@selector(videoEncoder:videoFrame:)]){
|
||||
|
||||
if (videoEncoder.h264Delegate && [videoEncoder.h264Delegate respondsToSelector:@selector(videoEncoder:videoFrame:)]) {
|
||||
[videoEncoder.h264Delegate videoEncoder:videoEncoder videoFrame:videoFrame];
|
||||
}
|
||||
|
||||
if(videoEncoder->enabledWriteVideoFile){
|
||||
|
||||
if (videoEncoder->enabledWriteVideoFile) {
|
||||
NSMutableData *data = [[NSMutableData alloc] init];
|
||||
if(keyframe){
|
||||
uint8_t header[] = {0x00,0x00,0x00,0x01};
|
||||
if (keyframe) {
|
||||
uint8_t header[] = {0x00, 0x00, 0x00, 0x01};
|
||||
[data appendBytes:header length:4];
|
||||
}else{
|
||||
uint8_t header[] = {0x00,0x00,0x01};
|
||||
} else {
|
||||
uint8_t header[] = {0x00, 0x00, 0x01};
|
||||
[data appendBytes:header length:3];
|
||||
}
|
||||
[data appendData:videoFrame.data];
|
||||
|
||||
fwrite(data.bytes, 1,data.length,videoEncoder->fp);
|
||||
|
||||
fwrite(data.bytes, 1, data.length, videoEncoder->fp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bufferOffset += AVCCHeaderLength + NALUnitLength;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)initForFilePath
|
||||
{
|
||||
char *path = [self GetFilePathByfileName:"IOSCamDemo.h264"];
|
||||
NSLog(@"%s",path);
|
||||
self->fp = fopen(path,"wb");
|
||||
- (void)initForFilePath {
|
||||
NSString *path = [self GetFilePathByfileName:@"IOSCamDemo.h264"];
|
||||
NSLog(@"%@", path);
|
||||
self->fp = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "wb");
|
||||
}
|
||||
|
||||
|
||||
- (char*)GetFilePathByfileName:(char*)filename
|
||||
{
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
|
||||
- (NSString *)GetFilePathByfileName:(NSString*)filename {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *documentsDirectory = [paths objectAtIndex:0];
|
||||
NSString *strName = [NSString stringWithFormat:@"%s",filename];
|
||||
|
||||
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:strName];
|
||||
|
||||
NSUInteger len = [writablePath length];
|
||||
|
||||
char *filepath = (char*)malloc(sizeof(char) * (len + 1));
|
||||
|
||||
[writablePath getCString:filepath maxLength:len + 1 encoding:[NSString defaultCStringEncoding]];
|
||||
|
||||
return filepath;
|
||||
NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:filename];
|
||||
return writablePath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFVideoEncoding.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -14,18 +14,17 @@
|
||||
/// 编码器编码后回调
|
||||
@protocol LFVideoEncodingDelegate <NSObject>
|
||||
@required
|
||||
- (void)videoEncoder:(nullable id<LFVideoEncoding>)encoder videoFrame:(nullable LFVideoFrame*)frame;
|
||||
- (void)videoEncoder:(nullable id<LFVideoEncoding>)encoder videoFrame:(nullable LFVideoFrame *)frame;
|
||||
@end
|
||||
|
||||
/// 编码器抽象的接口
|
||||
@protocol LFVideoEncoding <NSObject>
|
||||
@required
|
||||
- (void)encodeVideoData:(nullable CVImageBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp;
|
||||
- (void)stopEncoder;
|
||||
- (void)encodeVideoData:(nullable CVPixelBufferRef)pixelBuffer timeStamp:(uint64_t)timeStamp;
|
||||
@optional
|
||||
@property (nonatomic, assign) NSInteger videoBitRate;
|
||||
- (nullable instancetype)initWithVideoStreamConfiguration:(nullable LFLiveVideoConfiguration*)configuration;
|
||||
- (nullable instancetype)initWithVideoStreamConfiguration:(nullable LFLiveVideoConfiguration *)configuration;
|
||||
- (void)setDelegate:(nullable id<LFVideoEncodingDelegate>)delegate;
|
||||
|
||||
- (void)stopEncoder;
|
||||
@end
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// LFLiveAudioConfiguration.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/// 音频码率
|
||||
typedef NS_ENUM(NSUInteger, LFLiveAudioBitRate) {
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioBitRate) {
|
||||
/// 32Kbps 音频码率
|
||||
LFLiveAudioBitRate_32Kbps = 32000,
|
||||
/// 64Kbps 音频码率
|
||||
@@ -19,34 +19,36 @@ typedef NS_ENUM(NSUInteger, LFLiveAudioBitRate) {
|
||||
/// 128Kbps 音频码率
|
||||
LFLiveAudioBitRate_128Kbps = 128000,
|
||||
/// 默认音频码率,默认为 64Kbps
|
||||
LFLiveAudioBitRate_Default = LFLiveAudioBitRate_64Kbps
|
||||
LFLiveAudioBitRate_Default = LFLiveAudioBitRate_96Kbps
|
||||
};
|
||||
|
||||
/// 采样率 (默认44.1Hz iphoneg6以上48Hz)
|
||||
typedef NS_ENUM(NSUInteger, LFLiveAudioSampleRate){
|
||||
/// 44.1Hz 采样率
|
||||
/// 采样率 (默认44.1Hz)
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioSampleRate){
|
||||
/// 16KHz 采样率
|
||||
LFLiveAudioSampleRate_16000Hz = 16000,
|
||||
/// 44.1KHz 采样率
|
||||
LFLiveAudioSampleRate_44100Hz = 44100,
|
||||
/// 48Hz 采样率
|
||||
/// 48KHz 采样率
|
||||
LFLiveAudioSampleRate_48000Hz = 48000,
|
||||
/// 默认音频码率,默认为 64Kbps
|
||||
LFLiveAudioSampleRate_Default = LFLiveAudioSampleRate_44100Hz
|
||||
};
|
||||
|
||||
/// Audio Live quality(音频质量)
|
||||
typedef NS_ENUM(NSUInteger, LFLiveAudioQuality){
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 32Kbps
|
||||
typedef NS_ENUM (NSUInteger, LFLiveAudioQuality){
|
||||
/// 高音频质量 audio sample rate: 16KHz audio bitrate: numberOfChannels 1 : 32Kbps 2 : 64Kbps
|
||||
LFLiveAudioQuality_Low = 0,
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 64Kbps
|
||||
/// 高音频质量 audio sample rate: 44KHz audio bitrate: 96Kbps
|
||||
LFLiveAudioQuality_Medium = 1,
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 96Kbps
|
||||
/// 高音频质量 audio sample rate: 44MHz audio bitrate: 128Kbps
|
||||
LFLiveAudioQuality_High = 2,
|
||||
/// 高音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 128Kbps
|
||||
/// 高音频质量 audio sample rate: 48MHz, audio bitrate: 128Kbps
|
||||
LFLiveAudioQuality_VeryHigh = 3,
|
||||
/// 默认音频质量 audio sample rate: 44MHz(默认44.1Hz iphoneg6以上48Hz), audio bitrate: 64Kbps
|
||||
LFLiveAudioQuality_Default = LFLiveAudioQuality_Medium
|
||||
/// 默认音频质量 audio sample rate: 44MHz, audio bitrate: 96Kbps
|
||||
LFLiveAudioQuality_Default = LFLiveAudioQuality_High
|
||||
};
|
||||
|
||||
@interface LFLiveAudioConfiguration : NSObject<NSCoding,NSCopying>
|
||||
@interface LFLiveAudioConfiguration : NSObject<NSCoding, NSCopying>
|
||||
|
||||
/// 默认音频配置
|
||||
+ (instancetype)defaultConfiguration;
|
||||
@@ -64,6 +66,8 @@ typedef NS_ENUM(NSUInteger, LFLiveAudioQuality){
|
||||
// 码率
|
||||
@property (nonatomic, assign) LFLiveAudioBitRate audioBitrate;
|
||||
/// flv编码音频头 44100 为0x12 0x10
|
||||
@property (nonatomic ,assign,readonly) char *asc;
|
||||
@property (nonatomic, assign, readonly) char *asc;
|
||||
/// 缓存区长度
|
||||
@property (nonatomic, assign,readonly) NSUInteger bufferLength;
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFLiveAudioConfiguration.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
@@ -12,165 +12,124 @@
|
||||
@implementation LFLiveAudioConfiguration
|
||||
|
||||
#pragma mark -- LifyCycle
|
||||
+ (instancetype)defaultConfiguration{
|
||||
+ (instancetype)defaultConfiguration {
|
||||
LFLiveAudioConfiguration *audioConfig = [LFLiveAudioConfiguration defaultConfigurationForQuality:LFLiveAudioQuality_Default];
|
||||
return audioConfig;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveAudioQuality)audioQuality{
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveAudioQuality)audioQuality {
|
||||
LFLiveAudioConfiguration *audioConfig = [LFLiveAudioConfiguration new];
|
||||
audioConfig.numberOfChannels = 2;
|
||||
switch (audioQuality) {
|
||||
case LFLiveAudioQuality_Default:{
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_64Kbps;
|
||||
}
|
||||
break;
|
||||
case LFLiveAudioQuality_Low:{
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_32Kbps;
|
||||
}
|
||||
case LFLiveAudioQuality_High:{
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
}
|
||||
case LFLiveAudioQuality_VeryHigh:{
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case LFLiveAudioQuality_Low: {
|
||||
audioConfig.audioBitrate = audioConfig.numberOfChannels == 1 ? LFLiveAudioBitRate_32Kbps : LFLiveAudioBitRate_64Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_16000Hz;
|
||||
}
|
||||
audioConfig.audioSampleRate = [self.class isNewThaniPhone6] ? LFLiveAudioSampleRate_48000Hz : LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
break;
|
||||
case LFLiveAudioQuality_Medium: {
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
}
|
||||
break;
|
||||
case LFLiveAudioQuality_High: {
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
}
|
||||
break;
|
||||
case LFLiveAudioQuality_VeryHigh: {
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_48000Hz;
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
audioConfig.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfig.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return audioConfig;
|
||||
}
|
||||
|
||||
- (instancetype)init{
|
||||
if(self = [super init]){
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_asc = malloc(2);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
if(_asc) free(_asc);
|
||||
- (void)dealloc {
|
||||
if (_asc) free(_asc);
|
||||
}
|
||||
|
||||
#pragma mark Setter
|
||||
- (void)setAudioSampleRate:(LFLiveAudioSampleRate)audioSampleRate{
|
||||
- (void)setAudioSampleRate:(LFLiveAudioSampleRate)audioSampleRate {
|
||||
_audioSampleRate = audioSampleRate;
|
||||
NSInteger sampleRateIndex = [self sampleRateIndex:audioSampleRate];
|
||||
self.asc[0] = 0x10 | ((sampleRateIndex>>1) & 0x3);
|
||||
self.asc[0] = 0x10 | ((sampleRateIndex>>1) & 0x7);
|
||||
self.asc[1] = ((sampleRateIndex & 0x1)<<7) | ((self.numberOfChannels & 0xF) << 3);
|
||||
}
|
||||
|
||||
- (void)setNumberOfChannels:(NSUInteger)numberOfChannels{
|
||||
- (void)setNumberOfChannels:(NSUInteger)numberOfChannels {
|
||||
_numberOfChannels = numberOfChannels;
|
||||
NSInteger sampleRateIndex = [self sampleRateIndex:self.audioSampleRate];
|
||||
self.asc[0] = 0x10 | ((sampleRateIndex>>1) & 0x3);
|
||||
self.asc[0] = 0x10 | ((sampleRateIndex>>1) & 0x7);
|
||||
self.asc[1] = ((sampleRateIndex & 0x1)<<7) | ((numberOfChannels & 0xF) << 3);
|
||||
}
|
||||
|
||||
- (NSUInteger)bufferLength{
|
||||
return 1024*2*self.numberOfChannels;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
- (NSInteger)sampleRateIndex:(NSInteger)frequencyInHz{
|
||||
- (NSInteger)sampleRateIndex:(NSInteger)frequencyInHz {
|
||||
NSInteger sampleRateIndex = 0;
|
||||
switch(frequencyInHz) {
|
||||
case 96000:
|
||||
sampleRateIndex = 0;
|
||||
break;
|
||||
case 88200:
|
||||
sampleRateIndex = 1;
|
||||
break;
|
||||
case 64000:
|
||||
sampleRateIndex = 2;
|
||||
break;
|
||||
case 48000:
|
||||
sampleRateIndex = 3;
|
||||
break;
|
||||
case 44100:
|
||||
sampleRateIndex = 4;
|
||||
break;
|
||||
case 32000:
|
||||
sampleRateIndex = 5;
|
||||
break;
|
||||
case 24000:
|
||||
sampleRateIndex = 6;
|
||||
break;
|
||||
case 22050:
|
||||
sampleRateIndex = 7;
|
||||
break;
|
||||
case 16000:
|
||||
sampleRateIndex = 8;
|
||||
break;
|
||||
case 12000:
|
||||
sampleRateIndex = 9;
|
||||
break;
|
||||
case 11025:
|
||||
sampleRateIndex = 10;
|
||||
break;
|
||||
case 8000:
|
||||
sampleRateIndex = 11;
|
||||
break;
|
||||
case 7350:
|
||||
sampleRateIndex = 12;
|
||||
break;
|
||||
default:
|
||||
sampleRateIndex = 15;
|
||||
switch (frequencyInHz) {
|
||||
case 96000:
|
||||
sampleRateIndex = 0;
|
||||
break;
|
||||
case 88200:
|
||||
sampleRateIndex = 1;
|
||||
break;
|
||||
case 64000:
|
||||
sampleRateIndex = 2;
|
||||
break;
|
||||
case 48000:
|
||||
sampleRateIndex = 3;
|
||||
break;
|
||||
case 44100:
|
||||
sampleRateIndex = 4;
|
||||
break;
|
||||
case 32000:
|
||||
sampleRateIndex = 5;
|
||||
break;
|
||||
case 24000:
|
||||
sampleRateIndex = 6;
|
||||
break;
|
||||
case 22050:
|
||||
sampleRateIndex = 7;
|
||||
break;
|
||||
case 16000:
|
||||
sampleRateIndex = 8;
|
||||
break;
|
||||
case 12000:
|
||||
sampleRateIndex = 9;
|
||||
break;
|
||||
case 11025:
|
||||
sampleRateIndex = 10;
|
||||
break;
|
||||
case 8000:
|
||||
sampleRateIndex = 11;
|
||||
break;
|
||||
case 7350:
|
||||
sampleRateIndex = 12;
|
||||
break;
|
||||
default:
|
||||
sampleRateIndex = 15;
|
||||
}
|
||||
return sampleRateIndex;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -- DeviceCategory
|
||||
+(NSString*)deviceName{
|
||||
struct utsname systemInfo;
|
||||
uname(&systemInfo);
|
||||
|
||||
return [NSString stringWithCString:systemInfo.machine
|
||||
encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
//@"iPad4,1" on 5th Generation iPad (iPad Air) - Wifi
|
||||
//@"iPad4,2" on 5th Generation iPad (iPad Air) - Cellular
|
||||
//@"iPad4,4" on 2nd Generation iPad Mini - Wifi
|
||||
//@"iPad4,5" on 2nd Generation iPad Mini - Cellular
|
||||
//@"iPad4,7" on 3rd Generation iPad Mini - Wifi (model A1599)
|
||||
//@"iPhone7,1" on iPhone 6 Plus
|
||||
//@"iPhone7,2" on iPhone 6
|
||||
//@"iPhone8,1" on iPhone 6S
|
||||
//@"iPhone8,2" on iPhone 6S Plus
|
||||
|
||||
+(BOOL) isNewThaniPhone6{
|
||||
NSString *device = [self deviceName];
|
||||
NSLog(@"device %@", device);
|
||||
if (device == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSArray *array = [device componentsSeparatedByString:@","];
|
||||
if (array.count <2) {
|
||||
return NO;
|
||||
}
|
||||
NSString *model = [array objectAtIndex:0];
|
||||
NSLog(@"model %@", model);
|
||||
if ([model hasPrefix:@"iPhone"]) {
|
||||
NSString *str1 = [model substringFromIndex:[@"iPhone" length]];
|
||||
NSUInteger num = [str1 integerValue];
|
||||
NSLog(@"num %lu", (unsigned long)num);
|
||||
if (num > 7) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
if ([model hasPrefix:@"iPad"]) {
|
||||
NSString *str1 = [model substringFromIndex:[@"iPad" length]];
|
||||
NSUInteger num = [str1 integerValue];
|
||||
if (num > 4) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -- Encoder
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:@(self.numberOfChannels) forKey:@"numberOfChannels"];
|
||||
@@ -188,7 +147,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)other{
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (other == self) {
|
||||
return YES;
|
||||
} else if (![super isEqual:other]) {
|
||||
@@ -196,9 +155,9 @@
|
||||
} else {
|
||||
LFLiveAudioConfiguration *object = other;
|
||||
return object.numberOfChannels == self.numberOfChannels &&
|
||||
object.audioBitrate == self.audioBitrate &&
|
||||
strcmp(object.asc, self.asc) == 0 &&
|
||||
object.audioSampleRate == self.audioSampleRate;
|
||||
object.audioBitrate == self.audioBitrate &&
|
||||
strcmp(object.asc, self.asc) == 0 &&
|
||||
object.audioSampleRate == self.audioSampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,25 +167,25 @@
|
||||
@(_audioSampleRate),
|
||||
[NSString stringWithUTF8String:self.asc],
|
||||
@(_audioBitrate)];
|
||||
|
||||
|
||||
for (NSObject *value in values) {
|
||||
hash ^= value.hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(nullable NSZone *)zone{
|
||||
- (id)copyWithZone:(nullable NSZone *)zone {
|
||||
LFLiveAudioConfiguration *other = [self.class defaultConfiguration];
|
||||
return other;
|
||||
}
|
||||
|
||||
- (NSString *)description{
|
||||
- (NSString *)description {
|
||||
NSMutableString *desc = @"".mutableCopy;
|
||||
[desc appendFormat:@"<LFLiveAudioConfiguration: %p>",self];
|
||||
[desc appendFormat:@" numberOfChannels:%zi",self.numberOfChannels];
|
||||
[desc appendFormat:@" audioSampleRate:%zi",self.audioSampleRate];
|
||||
[desc appendFormat:@" audioBitrate:%zi",self.audioBitrate];
|
||||
[desc appendFormat:@" audioHeader:%@",[NSString stringWithUTF8String:self.asc]];
|
||||
[desc appendFormat:@"<LFLiveAudioConfiguration: %p>", self];
|
||||
[desc appendFormat:@" numberOfChannels:%zi", self.numberOfChannels];
|
||||
[desc appendFormat:@" audioSampleRate:%zi", self.audioSampleRate];
|
||||
[desc appendFormat:@" audioBitrate:%zi", self.audioBitrate];
|
||||
[desc appendFormat:@" audioHeader:%@", [NSString stringWithUTF8String:self.asc]];
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
// LFLiveVideoConfiguration.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/// 视频分辨率(都是16:9 当此设备不支持当前分辨率,自动降低一级)
|
||||
typedef NS_ENUM(NSUInteger, LFLiveVideoSessionPreset){
|
||||
typedef NS_ENUM (NSUInteger, LFLiveVideoSessionPreset){
|
||||
/// 低分辨率
|
||||
LFCaptureSessionPreset360x640 = 0,
|
||||
/// 中分辨率
|
||||
@@ -20,7 +20,7 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoSessionPreset){
|
||||
};
|
||||
|
||||
/// 视频质量
|
||||
typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
|
||||
typedef NS_ENUM (NSUInteger, LFLiveVideoQuality){
|
||||
/// 分辨率: 360 *640 帧数:15 码率:500Kps
|
||||
LFLiveVideoQuality_Low1 = 0,
|
||||
/// 分辨率: 360 *640 帧数:24 码率:800Kps
|
||||
@@ -43,7 +43,7 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
|
||||
LFLiveVideoQuality_Default = LFLiveVideoQuality_Low2
|
||||
};
|
||||
|
||||
@interface LFLiveVideoConfiguration : NSObject<NSCoding,NSCopying>
|
||||
@interface LFLiveVideoConfiguration : NSObject<NSCoding, NSCopying>
|
||||
|
||||
/// 默认视频配置
|
||||
+ (instancetype)defaultConfiguration;
|
||||
@@ -51,17 +51,23 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality;
|
||||
|
||||
/// 视频配置(质量 & 是否是横屏)
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality landscape:(BOOL)landscape;
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality outputImageOrientation:(UIInterfaceOrientation)outputImageOrientation;
|
||||
|
||||
#pragma mark - Attribute
|
||||
///=============================================================================
|
||||
/// @name Attribute
|
||||
///=============================================================================
|
||||
/// 视频的分辨率,宽高务必设定为 2 的倍数,否则解码播放时可能出现绿边
|
||||
/// 视频的分辨率,宽高务必设定为 2 的倍数,否则解码播放时可能出现绿边(这个videoSizeRespectingAspectRatio设置为YES则可能会改变)
|
||||
@property (nonatomic, assign) CGSize videoSize;
|
||||
|
||||
/// 输出图像是否等比例,默认为NO
|
||||
@property (nonatomic, assign) BOOL videoSizeRespectingAspectRatio;
|
||||
|
||||
/// 视频输出方向
|
||||
@property (nonatomic, assign) BOOL landscape;
|
||||
@property (nonatomic, assign) UIInterfaceOrientation outputImageOrientation;
|
||||
|
||||
/// 自动旋转(这里只支持 left 变 right portrait 变 portraitUpsideDown)
|
||||
@property (nonatomic, assign) BOOL autorotate;
|
||||
|
||||
/// 视频的帧率,即 fps
|
||||
@property (nonatomic, assign) NSUInteger videoFrameRate;
|
||||
@@ -88,9 +94,9 @@ typedef NS_ENUM(NSUInteger, LFLiveVideoQuality){
|
||||
@property (nonatomic, assign) LFLiveVideoSessionPreset sessionPreset;
|
||||
|
||||
///< ≈sde3分辨率
|
||||
@property (nonatomic, assign,readonly) NSString *avSessionPreset;
|
||||
@property (nonatomic, assign, readonly) NSString *avSessionPreset;
|
||||
|
||||
///< 是否裁剪
|
||||
@property (nonatomic, assign,readonly) BOOL isClipVideo;
|
||||
///< 是否是横屏
|
||||
@property (nonatomic, assign, readonly) BOOL landscape;
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,249 +2,302 @@
|
||||
// LFLiveVideoConfiguration.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/1.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
|
||||
@implementation LFLiveVideoConfiguration
|
||||
|
||||
#pragma mark -- LifeCycle
|
||||
+ (instancetype)defaultConfiguration{
|
||||
|
||||
+ (instancetype)defaultConfiguration {
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Default];
|
||||
return configuration;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality{
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality landscape:NO];
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality {
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration defaultConfigurationForQuality:videoQuality outputImageOrientation:UIInterfaceOrientationPortrait];
|
||||
return configuration;
|
||||
}
|
||||
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality landscape:(BOOL)landscape{
|
||||
+ (instancetype)defaultConfigurationForQuality:(LFLiveVideoQuality)videoQuality outputImageOrientation:(UIInterfaceOrientation)outputImageOrientation {
|
||||
LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration new];
|
||||
switch (videoQuality) {
|
||||
case LFLiveVideoQuality_Low1:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 500 * 1000;
|
||||
configuration.videoMaxBitRate = 600 * 1000;
|
||||
configuration.videoMinBitRate = 400 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low2:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 600 * 1000;
|
||||
configuration.videoMaxBitRate = 720 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low3:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 600 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium1:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium2:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium3:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 1000 * 1000;
|
||||
configuration.videoMaxBitRate = 1200 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High1:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 1000 * 1000;
|
||||
configuration.videoMaxBitRate = 1200 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High2:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 1200 * 1000;
|
||||
configuration.videoMaxBitRate = 1440 * 1000;
|
||||
configuration.videoMinBitRate = 800 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High3:
|
||||
{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 1200 * 1000;
|
||||
configuration.videoMaxBitRate = 1440 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case LFLiveVideoQuality_Low1:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 500 * 1000;
|
||||
configuration.videoMaxBitRate = 600 * 1000;
|
||||
configuration.videoMinBitRate = 400 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 600 * 1000;
|
||||
configuration.videoMaxBitRate = 720 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Low3: {
|
||||
configuration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 600 * 1000;
|
||||
configuration.videoSize = CGSizeMake(360, 640);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium1:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 800 * 1000;
|
||||
configuration.videoMaxBitRate = 960 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_Medium3:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 1000 * 1000;
|
||||
configuration.videoMaxBitRate = 1200 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(540, 960);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High1:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 15;
|
||||
configuration.videoMaxFrameRate = 15;
|
||||
configuration.videoMinFrameRate = 10;
|
||||
configuration.videoBitRate = 1000 * 1000;
|
||||
configuration.videoMaxBitRate = 1200 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High2:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 24;
|
||||
configuration.videoMaxFrameRate = 24;
|
||||
configuration.videoMinFrameRate = 12;
|
||||
configuration.videoBitRate = 1200 * 1000;
|
||||
configuration.videoMaxBitRate = 1440 * 1000;
|
||||
configuration.videoMinBitRate = 800 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
case LFLiveVideoQuality_High3:{
|
||||
configuration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
configuration.videoFrameRate = 30;
|
||||
configuration.videoMaxFrameRate = 30;
|
||||
configuration.videoMinFrameRate = 15;
|
||||
configuration.videoBitRate = 1200 * 1000;
|
||||
configuration.videoMaxBitRate = 1440 * 1000;
|
||||
configuration.videoMinBitRate = 500 * 1000;
|
||||
configuration.videoSize = CGSizeMake(720, 1280);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
configuration.sessionPreset = [configuration supportSessionPreset:configuration.sessionPreset];
|
||||
configuration.videoMaxKeyframeInterval = configuration.videoFrameRate*2;
|
||||
configuration.landscape = landscape;
|
||||
configuration.outputImageOrientation = outputImageOrientation;
|
||||
CGSize size = configuration.videoSize;
|
||||
if(landscape){
|
||||
if(configuration.landscape) {
|
||||
configuration.videoSize = CGSizeMake(size.height, size.width);
|
||||
}else{
|
||||
} else {
|
||||
configuration.videoSize = CGSizeMake(size.width, size.height);
|
||||
}
|
||||
return configuration;
|
||||
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
- (NSString*)avSessionPreset{
|
||||
- (NSString *)avSessionPreset {
|
||||
NSString *avSessionPreset = nil;
|
||||
switch (self.sessionPreset) {
|
||||
case LFCaptureSessionPreset360x640:
|
||||
{
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:
|
||||
{
|
||||
avSessionPreset = AVCaptureSessionPresetiFrame960x540;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:
|
||||
{
|
||||
avSessionPreset = AVCaptureSessionPreset1280x720;
|
||||
}
|
||||
break;
|
||||
default:{
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset360x640:{
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset540x960:{
|
||||
avSessionPreset = AVCaptureSessionPresetiFrame960x540;
|
||||
}
|
||||
break;
|
||||
case LFCaptureSessionPreset720x1280:{
|
||||
avSessionPreset = AVCaptureSessionPreset1280x720;
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
avSessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return avSessionPreset;
|
||||
}
|
||||
|
||||
- (void)setVideoMaxBitRate:(NSUInteger)videoMaxBitRate{
|
||||
if(videoMaxBitRate <= _videoBitRate) return;
|
||||
- (BOOL)landscape{
|
||||
return (self.outputImageOrientation == UIInterfaceOrientationLandscapeLeft || self.outputImageOrientation == UIInterfaceOrientationLandscapeRight) ? YES : NO;
|
||||
}
|
||||
|
||||
- (CGSize)videoSize{
|
||||
if(_videoSizeRespectingAspectRatio){
|
||||
return self.aspectRatioVideoSize;
|
||||
}
|
||||
return _videoSize;
|
||||
}
|
||||
|
||||
- (void)setVideoMaxBitRate:(NSUInteger)videoMaxBitRate {
|
||||
if (videoMaxBitRate <= _videoBitRate) return;
|
||||
_videoMaxBitRate = videoMaxBitRate;
|
||||
}
|
||||
|
||||
- (void)setVideoMinBitRate:(NSUInteger)videoMinBitRate{
|
||||
if(videoMinBitRate >= _videoBitRate) return;
|
||||
- (void)setVideoMinBitRate:(NSUInteger)videoMinBitRate {
|
||||
if (videoMinBitRate >= _videoBitRate) return;
|
||||
_videoMinBitRate = videoMinBitRate;
|
||||
}
|
||||
|
||||
- (void)setVideoMaxFrameRate:(NSUInteger)videoMaxFrameRate{
|
||||
if(videoMaxFrameRate <= _videoFrameRate) return;
|
||||
- (void)setVideoMaxFrameRate:(NSUInteger)videoMaxFrameRate {
|
||||
if (videoMaxFrameRate <= _videoFrameRate) return;
|
||||
_videoMaxFrameRate = videoMaxFrameRate;
|
||||
}
|
||||
|
||||
- (void)setVideoMinFrameRate:(NSUInteger)videoMinFrameRate{
|
||||
if(videoMinFrameRate >= _videoFrameRate) return;
|
||||
- (void)setVideoMinFrameRate:(NSUInteger)videoMinFrameRate {
|
||||
if (videoMinFrameRate >= _videoFrameRate) return;
|
||||
_videoMinFrameRate = videoMinFrameRate;
|
||||
}
|
||||
|
||||
- (void)setLandscape:(BOOL)landscape{
|
||||
_landscape = landscape;
|
||||
CGSize size = self.videoSize;
|
||||
if(landscape){
|
||||
self.videoSize = CGSizeMake(size.height, size.width);
|
||||
}else{
|
||||
self.videoSize = CGSizeMake(size.width, size.height);
|
||||
}
|
||||
- (void)setSessionPreset:(LFLiveVideoSessionPreset)sessionPreset{
|
||||
_sessionPreset = sessionPreset;
|
||||
_sessionPreset = [self supportSessionPreset:sessionPreset];
|
||||
}
|
||||
|
||||
#pragma mark -- Custom Method
|
||||
- (LFLiveVideoSessionPreset)supportSessionPreset:(LFLiveVideoSessionPreset)sessionPreset{
|
||||
NSString *avSessionPreset = [self avSessionPreset];
|
||||
- (LFLiveVideoSessionPreset)supportSessionPreset:(LFLiveVideoSessionPreset)sessionPreset {
|
||||
AVCaptureSession *session = [[AVCaptureSession alloc] init];
|
||||
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 canSetSessionPreset:avSessionPreset]){
|
||||
if(sessionPreset == LFCaptureSessionPreset720x1280){
|
||||
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){
|
||||
} else if (sessionPreset == LFCaptureSessionPreset540x960) {
|
||||
sessionPreset = LFCaptureSessionPreset360x640;
|
||||
}
|
||||
}
|
||||
return sessionPreset;
|
||||
}
|
||||
|
||||
- (BOOL)isClipVideo{
|
||||
return self.sessionPreset == LFCaptureSessionPreset360x640 ? YES : NO;
|
||||
- (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.outputImageOrientation) forKey:@"outputImageOrientation"];
|
||||
[aCoder encodeObject:@(self.autorotate) forKey:@"autorotate"];
|
||||
[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];
|
||||
_outputImageOrientation = [[aDecoder decodeObjectForKey:@"outputImageOrientation"] unsignedIntegerValue];
|
||||
_autorotate = [[aDecoder decodeObjectForKey:@"autorotate"] boolValue];
|
||||
_videoSizeRespectingAspectRatio = [[aDecoder decodeObjectForKey:@"videoSizeRespectingAspectRatio"] unsignedIntegerValue];
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -258,60 +311,62 @@
|
||||
@(self.videoBitRate),
|
||||
@(self.videoMaxBitRate),
|
||||
@(self.videoMinBitRate),
|
||||
@(self.isClipVideo),
|
||||
self.avSessionPreset,
|
||||
@(self.sessionPreset),
|
||||
@(self.landscape),];
|
||||
|
||||
@(self.outputImageOrientation),
|
||||
@(self.autorotate),
|
||||
@(self.videoSizeRespectingAspectRatio)];
|
||||
|
||||
for (NSObject *value in values) {
|
||||
hash ^= value.hash;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)other
|
||||
{
|
||||
- (BOOL)isEqual:(id)other {
|
||||
if (other == self) {
|
||||
return YES;
|
||||
} else if (![super isEqual:other]) {
|
||||
return NO;
|
||||
} else {
|
||||
LFLiveVideoConfiguration *object = other;
|
||||
return CGSizeEqualToSize(object.videoSize, self.videoSize) &&
|
||||
object.videoFrameRate == self.videoFrameRate &&
|
||||
object.videoMaxFrameRate == self.videoMaxFrameRate &&
|
||||
object.videoMinFrameRate == self.videoMinFrameRate &&
|
||||
object.videoMaxKeyframeInterval == self.videoMaxKeyframeInterval &&
|
||||
object.videoBitRate == self.videoBitRate &&
|
||||
object.videoMaxBitRate == self.videoMaxBitRate &&
|
||||
object.videoMinBitRate == self.videoMinBitRate &&
|
||||
object.isClipVideo == self.isClipVideo &&
|
||||
[object.avSessionPreset isEqualToString:self.avSessionPreset] &&
|
||||
object.sessionPreset == self.sessionPreset &&
|
||||
object.landscape == self.landscape;
|
||||
return CGSizeEqualToSize(object.videoSize, self.videoSize) &&
|
||||
object.videoFrameRate == self.videoFrameRate &&
|
||||
object.videoMaxFrameRate == self.videoMaxFrameRate &&
|
||||
object.videoMinFrameRate == self.videoMinFrameRate &&
|
||||
object.videoMaxKeyframeInterval == self.videoMaxKeyframeInterval &&
|
||||
object.videoBitRate == self.videoBitRate &&
|
||||
object.videoMaxBitRate == self.videoMaxBitRate &&
|
||||
object.videoMinBitRate == self.videoMinBitRate &&
|
||||
[object.avSessionPreset isEqualToString:self.avSessionPreset] &&
|
||||
object.sessionPreset == self.sessionPreset &&
|
||||
object.outputImageOrientation == self.outputImageOrientation &&
|
||||
object.autorotate == self.autorotate &&
|
||||
object.videoSizeRespectingAspectRatio == self.videoSizeRespectingAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(nullable NSZone *)zone{
|
||||
- (id)copyWithZone:(nullable NSZone *)zone {
|
||||
LFLiveVideoConfiguration *other = [self.class defaultConfiguration];
|
||||
return other;
|
||||
}
|
||||
|
||||
- (NSString *)description{
|
||||
- (NSString *)description {
|
||||
NSMutableString *desc = @"".mutableCopy;
|
||||
[desc appendFormat:@"<LFLiveVideoConfiguration: %p>",self];
|
||||
[desc appendFormat:@" videoSize:%@",NSStringFromCGSize(self.videoSize)];
|
||||
[desc appendFormat:@" videoFrameRate:%zi",self.videoFrameRate];
|
||||
[desc appendFormat:@" videoMaxFrameRate:%zi",self.videoMaxFrameRate];
|
||||
[desc appendFormat:@" videoMinFrameRate:%zi",self.videoMinFrameRate];
|
||||
[desc appendFormat:@" videoMaxKeyframeInterval:%zi",self.videoMaxKeyframeInterval];
|
||||
[desc appendFormat:@" videoBitRate:%zi",self.videoBitRate];
|
||||
[desc appendFormat:@" videoMaxBitRate:%zi",self.videoMaxBitRate];
|
||||
[desc appendFormat:@" videoMinBitRate:%zi",self.videoMinBitRate];
|
||||
[desc appendFormat:@" isClipVideo:%zi",self.isClipVideo];
|
||||
[desc appendFormat:@" avSessionPreset:%@",self.avSessionPreset];
|
||||
[desc appendFormat:@" sessionPreset:%zi",self.sessionPreset];
|
||||
[desc appendFormat:@" landscape:%zi",self.landscape];
|
||||
[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];
|
||||
[desc appendFormat:@" videoMaxKeyframeInterval:%zi", self.videoMaxKeyframeInterval];
|
||||
[desc appendFormat:@" videoBitRate:%zi", self.videoBitRate];
|
||||
[desc appendFormat:@" videoMaxBitRate:%zi", self.videoMaxBitRate];
|
||||
[desc appendFormat:@" videoMinBitRate:%zi", self.videoMinBitRate];
|
||||
[desc appendFormat:@" avSessionPreset:%@", self.avSessionPreset];
|
||||
[desc appendFormat:@" sessionPreset:%zi", self.sessionPreset];
|
||||
[desc appendFormat:@" outputImageOrientation:%zi", self.outputImageOrientation];
|
||||
[desc appendFormat:@" autorotate:%zi", self.autorotate];
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#import "GPUImageFilter.h"
|
||||
#if __has_include(<GPUImage/GPUImageFramework.h>)
|
||||
#import <GPUImage/GPUImageFramework.h>
|
||||
#else
|
||||
#import "GPUImage.h"
|
||||
#endif
|
||||
|
||||
@interface LFGPUImageBeautyFilter : GPUImageFilter {
|
||||
}
|
||||
|
||||
@@ -2,237 +2,233 @@
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp vec2 singleStepOffset;
|
||||
uniform highp vec4 params;
|
||||
uniform highp float brightness;
|
||||
|
||||
const highp vec3 W = vec3(0.299,0.587,0.114);
|
||||
const highp mat3 saturateMatrix = mat3(
|
||||
1.1102,-0.0598,-0.061,
|
||||
-0.0774,1.0826,-0.1186,
|
||||
-0.0228,-0.0228,1.1772);
|
||||
highp vec2 blurCoordinates[24];
|
||||
|
||||
highp float hardLight(highp float color) {
|
||||
if(color <= 0.5)
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform highp vec2 singleStepOffset;
|
||||
uniform highp vec4 params;
|
||||
uniform highp float brightness;
|
||||
|
||||
const highp vec3 W = vec3(0.299, 0.587, 0.114);
|
||||
const highp mat3 saturateMatrix = mat3(
|
||||
1.1102, -0.0598, -0.061,
|
||||
-0.0774, 1.0826, -0.1186,
|
||||
-0.0228, -0.0228, 1.1772);
|
||||
highp vec2 blurCoordinates[24];
|
||||
|
||||
highp float hardLight(highp float color) {
|
||||
if (color <= 0.5)
|
||||
color = color * color * 2.0;
|
||||
else
|
||||
color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
|
||||
return color;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
highp vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
|
||||
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
|
||||
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
|
||||
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
|
||||
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
|
||||
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
|
||||
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
|
||||
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
|
||||
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
|
||||
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
|
||||
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
|
||||
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
|
||||
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
|
||||
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
|
||||
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
|
||||
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
|
||||
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
|
||||
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
|
||||
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
|
||||
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
|
||||
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
|
||||
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
|
||||
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
|
||||
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
|
||||
|
||||
highp float sampleColor = centralColor.g * 22.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
|
||||
|
||||
sampleColor = sampleColor / 62.0;
|
||||
|
||||
highp float highPass = centralColor.g - sampleColor + 0.5;
|
||||
|
||||
for(int i = 0; i < 5;i++)
|
||||
{
|
||||
highPass = hardLight(highPass);
|
||||
}
|
||||
highp float lumance = dot(centralColor, W);
|
||||
|
||||
highp float alpha = pow(lumance, params.r);
|
||||
|
||||
highp vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
|
||||
|
||||
smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0);
|
||||
smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0);
|
||||
smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0);
|
||||
|
||||
highp vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
|
||||
highp vec3 bianliang = max(smoothColor, centralColor);
|
||||
highp vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
|
||||
|
||||
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
|
||||
|
||||
highp vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
|
||||
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
|
||||
}
|
||||
);
|
||||
|
||||
void main(){
|
||||
highp vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
|
||||
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
|
||||
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
|
||||
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
|
||||
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
|
||||
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
|
||||
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
|
||||
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
|
||||
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
|
||||
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
|
||||
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
|
||||
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
|
||||
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
|
||||
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
|
||||
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
|
||||
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
|
||||
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
|
||||
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
|
||||
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
|
||||
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
|
||||
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
|
||||
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
|
||||
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
|
||||
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
|
||||
|
||||
highp float sampleColor = centralColor.g * 22.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
|
||||
|
||||
sampleColor = sampleColor / 62.0;
|
||||
|
||||
highp float highPass = centralColor.g - sampleColor + 0.5;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
highPass = hardLight(highPass);
|
||||
}
|
||||
highp float lumance = dot(centralColor, W);
|
||||
|
||||
highp float alpha = pow(lumance, params.r);
|
||||
|
||||
highp vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
|
||||
|
||||
smoothColor.r = clamp(pow(smoothColor.r, params.g), 0.0, 1.0);
|
||||
smoothColor.g = clamp(pow(smoothColor.g, params.g), 0.0, 1.0);
|
||||
smoothColor.b = clamp(pow(smoothColor.b, params.g), 0.0, 1.0);
|
||||
|
||||
highp vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
|
||||
highp vec3 bianliang = max(smoothColor, centralColor);
|
||||
highp vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
|
||||
|
||||
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
|
||||
|
||||
highp vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
|
||||
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
|
||||
}
|
||||
|
||||
);
|
||||
#else
|
||||
NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mediump vec2 singleStepOffset;
|
||||
uniform mediump vec4 params;
|
||||
uniform mediump float brightness;
|
||||
const mediump mat3 saturateMatrix = mat3(
|
||||
1.1102,-0.0598,-0.061,
|
||||
-0.0774,1.0826,-0.1186,
|
||||
-0.0228,-0.0228,1.1772);
|
||||
const mediump vec3 W = vec3(0.299,0.587,0.114);
|
||||
mediump vec2 blurCoordinates[24];
|
||||
|
||||
mediump float hardLight(mediump float color)
|
||||
{
|
||||
if(color <= 0.5)
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
uniform mediump vec2 singleStepOffset;
|
||||
uniform mediump vec4 params;
|
||||
uniform mediump float brightness;
|
||||
const mediump mat3 saturateMatrix = mat3(
|
||||
1.1102, -0.0598, -0.061,
|
||||
-0.0774, 1.0826, -0.1186,
|
||||
-0.0228, -0.0228, 1.1772);
|
||||
const mediump vec3 W = vec3(0.299, 0.587, 0.114);
|
||||
mediump vec2 blurCoordinates[24];
|
||||
|
||||
mediump float hardLight(mediump float color){
|
||||
if (color <= 0.5)
|
||||
color = color * color * 2.0;
|
||||
else
|
||||
color = 1.0 - ((1.0 - color)*(1.0 - color) * 2.0);
|
||||
return color;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
mediump vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
|
||||
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
|
||||
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
|
||||
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
|
||||
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
|
||||
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
|
||||
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
|
||||
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
|
||||
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
|
||||
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
|
||||
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
|
||||
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
|
||||
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
|
||||
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
|
||||
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
|
||||
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
|
||||
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
|
||||
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
|
||||
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
|
||||
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
|
||||
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
|
||||
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
|
||||
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
|
||||
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
|
||||
|
||||
mediump float sampleColor = centralColor.g * 22.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
|
||||
|
||||
sampleColor = sampleColor / 62.0;
|
||||
|
||||
mediump float highPass = centralColor.g - sampleColor + 0.5;
|
||||
|
||||
for(int i = 0; i < 5;i++)
|
||||
{
|
||||
highPass = hardLight(highPass);
|
||||
}
|
||||
mediump float luminance = dot(centralColor, W);
|
||||
|
||||
mediump float alpha = pow(luminance, params);
|
||||
|
||||
mediump vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
|
||||
|
||||
smoothColor.r = clamp(pow(smoothColor.r, params.g),0.0,1.0);
|
||||
smoothColor.g = clamp(pow(smoothColor.g, params.g),0.0,1.0);
|
||||
smoothColor.b = clamp(pow(smoothColor.b, params.g),0.0,1.0);
|
||||
|
||||
mediump vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
|
||||
mediump vec3 bianliang = max(smoothColor, centralColor);
|
||||
mediump vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
|
||||
|
||||
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
|
||||
|
||||
mediump vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
|
||||
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
|
||||
}
|
||||
);
|
||||
|
||||
void main(){
|
||||
mediump vec3 centralColor = texture2D(inputImageTexture, textureCoordinate).rgb;
|
||||
blurCoordinates[0] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -10.0);
|
||||
blurCoordinates[1] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 10.0);
|
||||
blurCoordinates[2] = textureCoordinate.xy + singleStepOffset * vec2(-10.0, 0.0);
|
||||
blurCoordinates[3] = textureCoordinate.xy + singleStepOffset * vec2(10.0, 0.0);
|
||||
blurCoordinates[4] = textureCoordinate.xy + singleStepOffset * vec2(5.0, -8.0);
|
||||
blurCoordinates[5] = textureCoordinate.xy + singleStepOffset * vec2(5.0, 8.0);
|
||||
blurCoordinates[6] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, 8.0);
|
||||
blurCoordinates[7] = textureCoordinate.xy + singleStepOffset * vec2(-5.0, -8.0);
|
||||
blurCoordinates[8] = textureCoordinate.xy + singleStepOffset * vec2(8.0, -5.0);
|
||||
blurCoordinates[9] = textureCoordinate.xy + singleStepOffset * vec2(8.0, 5.0);
|
||||
blurCoordinates[10] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, 5.0);
|
||||
blurCoordinates[11] = textureCoordinate.xy + singleStepOffset * vec2(-8.0, -5.0);
|
||||
blurCoordinates[12] = textureCoordinate.xy + singleStepOffset * vec2(0.0, -6.0);
|
||||
blurCoordinates[13] = textureCoordinate.xy + singleStepOffset * vec2(0.0, 6.0);
|
||||
blurCoordinates[14] = textureCoordinate.xy + singleStepOffset * vec2(6.0, 0.0);
|
||||
blurCoordinates[15] = textureCoordinate.xy + singleStepOffset * vec2(-6.0, 0.0);
|
||||
blurCoordinates[16] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, -4.0);
|
||||
blurCoordinates[17] = textureCoordinate.xy + singleStepOffset * vec2(-4.0, 4.0);
|
||||
blurCoordinates[18] = textureCoordinate.xy + singleStepOffset * vec2(4.0, -4.0);
|
||||
blurCoordinates[19] = textureCoordinate.xy + singleStepOffset * vec2(4.0, 4.0);
|
||||
blurCoordinates[20] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, -2.0);
|
||||
blurCoordinates[21] = textureCoordinate.xy + singleStepOffset * vec2(-2.0, 2.0);
|
||||
blurCoordinates[22] = textureCoordinate.xy + singleStepOffset * vec2(2.0, -2.0);
|
||||
blurCoordinates[23] = textureCoordinate.xy + singleStepOffset * vec2(2.0, 2.0);
|
||||
|
||||
mediump float sampleColor = centralColor.g * 22.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[0]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[1]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[2]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[3]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[4]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[5]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[6]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[7]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[8]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[9]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[10]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[11]).g;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[12]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[13]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[14]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[15]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[16]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[17]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[18]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[19]).g * 2.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[20]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[21]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[22]).g * 3.0;
|
||||
sampleColor += texture2D(inputImageTexture, blurCoordinates[23]).g * 3.0;
|
||||
|
||||
sampleColor = sampleColor / 62.0;
|
||||
|
||||
mediump float highPass = centralColor.g - sampleColor + 0.5;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
highPass = hardLight(highPass);
|
||||
}
|
||||
mediump float luminance = dot(centralColor, W);
|
||||
|
||||
mediump float alpha = pow(luminance, params);
|
||||
|
||||
mediump vec3 smoothColor = centralColor + (centralColor-vec3(highPass))*alpha*0.1;
|
||||
|
||||
smoothColor.r = clamp(pow(smoothColor.r, params.g), 0.0, 1.0);
|
||||
smoothColor.g = clamp(pow(smoothColor.g, params.g), 0.0, 1.0);
|
||||
smoothColor.b = clamp(pow(smoothColor.b, params.g), 0.0, 1.0);
|
||||
|
||||
mediump vec3 lvse = vec3(1.0)-(vec3(1.0)-smoothColor)*(vec3(1.0)-centralColor);
|
||||
mediump vec3 bianliang = max(smoothColor, centralColor);
|
||||
mediump vec3 rouguang = 2.0*centralColor*smoothColor + centralColor*centralColor - 2.0*centralColor*centralColor*smoothColor;
|
||||
|
||||
gl_FragColor = vec4(mix(centralColor, lvse, alpha), 1.0);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, bianliang, alpha);
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, rouguang, params.b);
|
||||
|
||||
mediump vec3 satcolor = gl_FragColor.rgb * saturateMatrix;
|
||||
gl_FragColor.rgb = mix(gl_FragColor.rgb, satcolor, params.a);
|
||||
gl_FragColor.rgb = vec3(gl_FragColor.rgb + vec3(brightness));
|
||||
}
|
||||
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation LFGPUImageBeautyFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kLFGPUImageBeautyFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
if (!(self = [super initWithFragmentShaderFromString:kLFGPUImageBeautyFragmentShaderString])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
_toneLevel = 0.5;
|
||||
_beautyLevel = 0.5;
|
||||
_brightLevel = 0.5;
|
||||
@@ -241,27 +237,23 @@ NSString *const kLFGPUImageBeautyFragmentShaderString = SHADER_STRING
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex
|
||||
{
|
||||
CGSize oldInputSize = inputTextureSize;
|
||||
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex {
|
||||
[super setInputSize:newSize atIndex:textureIndex];
|
||||
inputTextureSize = newSize;
|
||||
|
||||
|
||||
CGPoint offset = CGPointMake(2.0f / inputTextureSize.width, 2.0 / inputTextureSize.height);
|
||||
[self setPoint:offset forUniformName:@"singleStepOffset"];
|
||||
}
|
||||
|
||||
- (void)setBeautyLevel:(CGFloat)beautyLevel
|
||||
{
|
||||
- (void)setBeautyLevel:(CGFloat)beautyLevel {
|
||||
_beautyLevel = beautyLevel;
|
||||
[self setParams:_beautyLevel tone:_toneLevel];
|
||||
}
|
||||
|
||||
- (void)setBrightLevel:(CGFloat)brightLevel
|
||||
{
|
||||
- (void)setBrightLevel:(CGFloat)brightLevel {
|
||||
_brightLevel = brightLevel;
|
||||
[self setFloat:0.6 * (-0.5 + brightLevel) forUniformName:@"brightness"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setParams:(CGFloat)beauty tone:(CGFloat)tone {
|
||||
GPUVector4 fBeautyParam;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
#import "GPUImageFilter.h"
|
||||
#if __has_include(<GPUImage/GPUImageFramework.h>)
|
||||
#import <GPUImage/GPUImageFramework.h>
|
||||
#else
|
||||
#import "GPUImage.h"
|
||||
#endif
|
||||
|
||||
@interface LFGPUImageEmptyFilter : GPUImageFilter
|
||||
{
|
||||
|
||||
@@ -2,43 +2,42 @@
|
||||
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
NSString *const kLFGPUImageEmptyFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
(
|
||||
varying highp vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main(){
|
||||
lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
|
||||
gl_FragColor = vec4((textureColor.rgb), textureColor.w);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
);
|
||||
#else
|
||||
NSString *const kGPUImageInvertFragmentShaderString = SHADER_STRING
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((textureColor.rgb), textureColor.w);
|
||||
}
|
||||
);
|
||||
(
|
||||
varying vec2 textureCoordinate;
|
||||
|
||||
uniform sampler2D inputImageTexture;
|
||||
|
||||
void main(){
|
||||
vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
|
||||
|
||||
gl_FragColor = vec4((textureColor.rgb), textureColor.w);
|
||||
}
|
||||
|
||||
);
|
||||
#endif
|
||||
|
||||
@implementation LFGPUImageEmptyFilter
|
||||
|
||||
- (id)init;
|
||||
{
|
||||
if (!(self = [super initWithFragmentShaderFromString:kLFGPUImageEmptyFragmentShaderString]))
|
||||
{
|
||||
return nil;
|
||||
if (!(self = [super initWithFragmentShaderFromString:kLFGPUImageEmptyFragmentShaderString])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFAudioFrame.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFFrame.h"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFAudioFrame.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFAudioFrame.h"
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
// LFFrame.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LFFrame : NSObject
|
||||
|
||||
@property (nonatomic, assign) uint64_t timestamp;
|
||||
@property (nonatomic, assign,) uint64_t timestamp;
|
||||
@property (nonatomic, strong) NSData *data;
|
||||
///< flv或者rtmp包头
|
||||
@property (nonatomic, strong) NSData *header;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFFrame.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFFrame.h"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFLiveDebug.h
|
||||
// LaiFeng
|
||||
//
|
||||
// Created by admin on 16/5/19.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -16,11 +16,15 @@
|
||||
@property (nonatomic, assign) CGSize videoSize; ///< 上传的分辨率
|
||||
@property (nonatomic, assign) BOOL isRtmp; ///< 上传方式(TCP or RTMP)
|
||||
|
||||
@property (nonatomic, assign) CGFloat elapsedMilli; ///< 距离上次统计的时间 单位ms
|
||||
@property (nonatomic, assign) CGFloat timeStamp; ///< 当前的时间戳,从而计算1s内数据
|
||||
@property (nonatomic, assign) CGFloat dataFlow; ///< 总流量
|
||||
@property (nonatomic, assign) CGFloat bandwidth; ///< 1s内总带宽
|
||||
@property (nonatomic, assign) CGFloat currentBandwidth; ///< 上次的带宽
|
||||
|
||||
@property (nonatomic, assign) NSInteger dropFrame; ///< 丢掉的帧数
|
||||
@property (nonatomic, assign) NSInteger totalFrame; ///< 总帧数
|
||||
|
||||
@property (nonatomic, assign) NSInteger capturedAudioCount; ///< 1s内音频捕获个数
|
||||
@property (nonatomic, assign) NSInteger capturedVideoCount; ///< 1s内视频捕获个数
|
||||
@property (nonatomic, assign) NSInteger currentCapturedAudioCount; ///< 上次的音频捕获个数
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFLiveDebug.m
|
||||
// LaiFeng
|
||||
//
|
||||
// Created by admin on 16/5/19.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
// LFLiveStreamInfo.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// 真正的上传地址 token等
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LFLiveAudioConfiguration.h"
|
||||
#import "LFLiveVideoConfiguration.h"
|
||||
|
||||
|
||||
|
||||
/// 流状态
|
||||
typedef NS_ENUM(NSUInteger, LFLiveState){
|
||||
typedef NS_ENUM (NSUInteger, LFLiveState){
|
||||
/// 准备
|
||||
LFLiveReady = 0,
|
||||
/// 连接中
|
||||
@@ -21,15 +23,17 @@ typedef NS_ENUM(NSUInteger, LFLiveState){
|
||||
/// 已断开
|
||||
LFLiveStop = 3,
|
||||
/// 连接出错
|
||||
LFLiveError = 4
|
||||
LFLiveError = 4,
|
||||
/// 正在刷新
|
||||
LFLiveRefresh = 5
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger,LFLiveSocketErrorCode) {
|
||||
LFLiveSocketError_PreView = 201,///< 预览失败
|
||||
LFLiveSocketError_GetStreamInfo = 202,///< 获取流媒体信息失败
|
||||
LFLiveSocketError_ConnectSocket = 203,///< 连接socket失败
|
||||
LFLiveSocketError_Verification = 204,///< 验证服务器失败
|
||||
LFLiveSocketError_ReConnectTimeOut = 205///< 重新连接服务器超时
|
||||
typedef NS_ENUM (NSUInteger, LFLiveSocketErrorCode) {
|
||||
LFLiveSocketError_PreView = 201, ///< 预览失败
|
||||
LFLiveSocketError_GetStreamInfo = 202, ///< 获取流媒体信息失败
|
||||
LFLiveSocketError_ConnectSocket = 203, ///< 连接socket失败
|
||||
LFLiveSocketError_Verification = 204, ///< 验证服务器失败
|
||||
LFLiveSocketError_ReConnectTimeOut = 205 ///< 重新连接服务器超时
|
||||
};
|
||||
|
||||
@interface LFLiveStreamInfo : NSObject
|
||||
@@ -46,5 +50,4 @@ typedef NS_ENUM(NSUInteger,LFLiveSocketErrorCode) {
|
||||
///视频配置
|
||||
@property (nonatomic, strong) LFLiveVideoConfiguration *videoConfiguration;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFLiveStreamInfo.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLiveStreamInfo.h"
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// LFVideoFrame.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFFrame.h"
|
||||
|
||||
|
||||
@interface LFVideoFrame : LFFrame
|
||||
|
||||
@property (nonatomic, assign) BOOL isKeyFrame;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFVideoFrame.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFVideoFrame.h"
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//
|
||||
// LFStreamRtmpSocket.h
|
||||
// LFStreamRTMPSocket.h
|
||||
// LaiFeng
|
||||
//
|
||||
// Created by admin on 16/5/18.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFStreamSocket.h"
|
||||
|
||||
@interface LFStreamRtmpSocket : NSObject<LFStreamSocket>
|
||||
@interface LFStreamRTMPSocket : NSObject<LFStreamSocket>
|
||||
|
||||
#pragma mark - Initializer
|
||||
///=============================================================================
|
||||
@@ -1,32 +1,27 @@
|
||||
//
|
||||
// LFStreamRtmpSocket.m
|
||||
// LFStreamRTMPSocket.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by admin on 16/5/18.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFStreamRtmpSocket.h"
|
||||
#import "LFStreamRTMPSocket.h"
|
||||
#import "rtmp.h"
|
||||
#import "YYDispatchQueuePool.h"
|
||||
|
||||
static const NSInteger RetryTimesBreaken = 20;///< 重连1分钟 3秒一次 一共20次
|
||||
static const NSInteger RetryTimesBreaken = 5; ///< 重连1分钟 3秒一次 一共20次
|
||||
static const NSInteger RetryTimesMargin = 3;
|
||||
|
||||
static dispatch_queue_t YYRtmpSendQueue() {
|
||||
YYDispatchQueuePool *pool = [[YYDispatchQueuePool alloc] initWithName:@"com.youku.laifeng.rtmpsendQueue" queueCount:1 qos:NSQualityOfServiceDefault];
|
||||
dispatch_queue_t queue = [pool queue];
|
||||
return queue;
|
||||
}
|
||||
|
||||
#define RTMP_RECEIVE_TIMEOUT 2
|
||||
#define DATA_ITEMS_MAX_COUNT 100
|
||||
#define RTMP_DATA_RESERVE_SIZE 400
|
||||
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket)+RTMP_MAX_HEADER_SIZE)
|
||||
#define RTMP_HEAD_SIZE (sizeof(RTMPPacket) + RTMP_MAX_HEADER_SIZE)
|
||||
|
||||
#define SAVC(x) static const AVal av_##x = AVC(#x)
|
||||
#define SAVC(x) static const AVal av_ ## x = AVC(#x)
|
||||
|
||||
static const AVal av_setDataFrame = AVC("@setDataFrame");
|
||||
static const AVal av_SDKVersion = AVC("LFLiveKit 1.7.3");
|
||||
static const AVal av_SDKVersion = AVC("LFLiveKit 2.4.0");
|
||||
SAVC(onMetaData);
|
||||
SAVC(duration);
|
||||
SAVC(width);
|
||||
@@ -38,29 +33,30 @@ SAVC(audiocodecid);
|
||||
SAVC(audiodatarate);
|
||||
SAVC(audiosamplerate);
|
||||
SAVC(audiosamplesize);
|
||||
SAVC(audiochannels);
|
||||
//SAVC(audiochannels);
|
||||
SAVC(stereo);
|
||||
SAVC(encoder);
|
||||
SAVC(av_stereo);
|
||||
//SAVC(av_stereo);
|
||||
SAVC(fileSize);
|
||||
SAVC(avc1);
|
||||
SAVC(mp4a);
|
||||
|
||||
@interface LFStreamRtmpSocket ()<LFStreamingBufferDelegate>
|
||||
@interface LFStreamRTMPSocket ()<LFStreamingBufferDelegate>
|
||||
{
|
||||
PILI_RTMP* _rtmp;
|
||||
PILI_RTMP *_rtmp;
|
||||
}
|
||||
@property (nonatomic, weak) id<LFStreamSocketDelegate> delegate;
|
||||
@property (nonatomic, strong) LFLiveStreamInfo *stream;
|
||||
@property (nonatomic, strong) LFStreamingBuffer *buffer;
|
||||
@property (nonatomic, strong) LFLiveDebug *debugInfo;
|
||||
@property (nonatomic, strong) dispatch_queue_t rtmpSendQueue;
|
||||
//错误信息
|
||||
@property (nonatomic, assign) RTMPError error;
|
||||
@property (nonatomic, assign) NSInteger retryTimes4netWorkBreaken;
|
||||
@property (nonatomic, assign) NSInteger reconnectInterval;
|
||||
@property (nonatomic, assign) NSInteger reconnectCount;
|
||||
|
||||
@property (nonatomic, assign) BOOL isSending;
|
||||
@property (atomic, assign) BOOL isSending;
|
||||
@property (nonatomic, assign) BOOL isConnected;
|
||||
@property (nonatomic, assign) BOOL isConnecting;
|
||||
@property (nonatomic, assign) BOOL isReconnecting;
|
||||
@@ -68,123 +64,171 @@ SAVC(mp4a);
|
||||
@property (nonatomic, assign) BOOL sendVideoHead;
|
||||
@property (nonatomic, assign) BOOL sendAudioHead;
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFStreamRtmpSocket
|
||||
@implementation LFStreamRTMPSocket
|
||||
|
||||
#pragma mark -- LFStreamSocket
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo*)stream videoSize:(CGSize)videoSize reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount{
|
||||
if(!stream) @throw [NSException exceptionWithName:@"LFStreamRtmpSocket init error" reason:@"stream is nil" userInfo:nil];
|
||||
if(self = [super init]){
|
||||
- (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;
|
||||
if (reconnectInterval > 0) _reconnectInterval = reconnectInterval;
|
||||
else _reconnectInterval = RetryTimesMargin;
|
||||
|
||||
if(reconnectCount > 0) _reconnectCount = reconnectCount;
|
||||
if (reconnectCount > 0) _reconnectCount = reconnectCount;
|
||||
else _reconnectCount = RetryTimesBreaken;
|
||||
|
||||
[self addObserver:self forKeyPath:@"isSending" options:NSKeyValueObservingOptionNew context:nil];//这里改成observer主要考虑一直到发送出错情况下,可以继续发送
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) start{
|
||||
dispatch_async(YYRtmpSendQueue(), ^{
|
||||
- (void)dealloc{
|
||||
[self removeObserver:self forKeyPath:@"isSending"];
|
||||
}
|
||||
|
||||
- (void)start {
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
[self _start];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)_start{
|
||||
if(!_stream) return;
|
||||
if(_isConnecting) return;
|
||||
if(_rtmp != NULL) return;
|
||||
- (void)_start {
|
||||
if (!_stream) return;
|
||||
if (_isConnecting) return;
|
||||
if (_rtmp != NULL) return;
|
||||
self.debugInfo.streamId = self.stream.streamId;
|
||||
self.debugInfo.uploadUrl = self.stream.url;
|
||||
self.debugInfo.isRtmp = YES;
|
||||
[self clean];
|
||||
[self RTMP264_Connect:(char*)[_stream.url cStringUsingEncoding:NSASCIIStringEncoding]];
|
||||
if (_isConnecting) return;
|
||||
|
||||
_isConnecting = YES;
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]) {
|
||||
[self.delegate socketStatus:self status:LFLivePending];
|
||||
}
|
||||
|
||||
if (_rtmp != NULL) {
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
}
|
||||
[self RTMP264_Connect:(char *)[_stream.url cStringUsingEncoding:NSASCIIStringEncoding]];
|
||||
}
|
||||
|
||||
- (void) stop{
|
||||
dispatch_async(YYRtmpSendQueue(), ^{
|
||||
- (void)stop {
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
[self _stop];
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)_stop{
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
|
||||
- (void)_stop {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]) {
|
||||
[self.delegate socketStatus:self status:LFLiveStop];
|
||||
}
|
||||
if(_rtmp != NULL){
|
||||
if (_rtmp != NULL) {
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
_rtmp = NULL;
|
||||
}
|
||||
[self clean];
|
||||
}
|
||||
|
||||
- (void) sendFrame:(LFFrame*)frame{
|
||||
dispatch_async(YYRtmpSendQueue(), ^{
|
||||
if(!frame) return;
|
||||
[self.buffer appendObject:frame];
|
||||
- (void)sendFrame:(LFFrame *)frame {
|
||||
if (!frame) return;
|
||||
[self.buffer appendObject:frame];
|
||||
|
||||
if(!self.isSending){
|
||||
[self sendFrame];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setDelegate:(id<LFStreamSocketDelegate>)delegate{
|
||||
- (void)setDelegate:(id<LFStreamSocketDelegate>)delegate {
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
#pragma mark -- CustomMethod
|
||||
- (void)sendFrame{
|
||||
if(!self.isSending && self.buffer.list.count > 0){
|
||||
self.isSending = YES;
|
||||
|
||||
if(!_isConnected || _isReconnecting || _isConnecting || !_rtmp) return;
|
||||
|
||||
// 调用发送接口
|
||||
LFFrame *frame = [self.buffer popFirstObject];
|
||||
if([frame isKindOfClass:[LFVideoFrame class]]){
|
||||
if(!self.sendVideoHead){
|
||||
self.sendVideoHead = YES;
|
||||
[self sendVideoHeader:(LFVideoFrame*)frame];
|
||||
}else{
|
||||
[self sendVideo:(LFVideoFrame*)frame];
|
||||
- (void)sendFrame {
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
if (!_self.isSending && _self.buffer.list.count > 0) {
|
||||
_self.isSending = YES;
|
||||
|
||||
if (!_self.isConnected || _self.isReconnecting || _self.isConnecting || !_rtmp){
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
if(!self.sendAudioHead){
|
||||
self.sendAudioHead = YES;
|
||||
[self sendAudioHeader:(LFAudioFrame*)frame];
|
||||
}else{
|
||||
[self sendAudio:frame];
|
||||
|
||||
// 调用发送接口
|
||||
LFFrame *frame = [_self.buffer popFirstObject];
|
||||
if ([frame isKindOfClass:[LFVideoFrame class]]) {
|
||||
if (!_self.sendVideoHead) {
|
||||
_self.sendVideoHead = YES;
|
||||
if(!((LFVideoFrame*)frame).sps || !((LFVideoFrame*)frame).pps){
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
[_self sendVideoHeader:(LFVideoFrame *)frame];
|
||||
} else {
|
||||
[_self sendVideo:(LFVideoFrame *)frame];
|
||||
}
|
||||
} else {
|
||||
if (!_self.sendAudioHead) {
|
||||
_self.sendAudioHead = YES;
|
||||
if(!((LFAudioFrame*)frame).audioInfo){
|
||||
_self.isSending = NO;
|
||||
return;
|
||||
}
|
||||
[_self sendAudioHeader:(LFAudioFrame *)frame];
|
||||
} else {
|
||||
[_self sendAudio:frame];
|
||||
}
|
||||
}
|
||||
|
||||
//debug更新
|
||||
_self.debugInfo.totalFrame++;
|
||||
_self.debugInfo.dropFrame += _self.buffer.lastDropFrames;
|
||||
_self.buffer.lastDropFrames = 0;
|
||||
|
||||
_self.debugInfo.dataFlow += frame.data.length;
|
||||
_self.debugInfo.elapsedMilli = CACurrentMediaTime() * 1000 - _self.debugInfo.timeStamp;
|
||||
if (_self.debugInfo.elapsedMilli < 1000) {
|
||||
_self.debugInfo.bandwidth += frame.data.length;
|
||||
if ([frame isKindOfClass:[LFAudioFrame class]]) {
|
||||
_self.debugInfo.capturedAudioCount++;
|
||||
} else {
|
||||
_self.debugInfo.capturedVideoCount++;
|
||||
}
|
||||
|
||||
_self.debugInfo.unSendCount = _self.buffer.list.count;
|
||||
} else {
|
||||
_self.debugInfo.currentBandwidth = _self.debugInfo.bandwidth;
|
||||
_self.debugInfo.currentCapturedAudioCount = _self.debugInfo.capturedAudioCount;
|
||||
_self.debugInfo.currentCapturedVideoCount = _self.debugInfo.capturedVideoCount;
|
||||
if (_self.delegate && [_self.delegate respondsToSelector:@selector(socketDebug:debugInfo:)]) {
|
||||
[_self.delegate socketDebug:_self debugInfo:_self.debugInfo];
|
||||
}
|
||||
_self.debugInfo.bandwidth = 0;
|
||||
_self.debugInfo.capturedAudioCount = 0;
|
||||
_self.debugInfo.capturedVideoCount = 0;
|
||||
_self.debugInfo.timeStamp = CACurrentMediaTime() * 1000;
|
||||
}
|
||||
|
||||
}
|
||||
self.debugInfo.dataFlow += frame.data.length;
|
||||
if(CACurrentMediaTime()*1000 - self.debugInfo.timeStamp < 1000) {
|
||||
self.debugInfo.bandwidth += frame.data.length;
|
||||
if([frame isKindOfClass:[LFAudioFrame class]]){
|
||||
self.debugInfo.capturedAudioCount ++;
|
||||
}else{
|
||||
self.debugInfo.capturedVideoCount ++;
|
||||
}
|
||||
self.debugInfo.unSendCount = self.buffer.list.count;
|
||||
}else {
|
||||
self.debugInfo.currentBandwidth = self.debugInfo.bandwidth;
|
||||
self.debugInfo.currentCapturedAudioCount = self.debugInfo.capturedAudioCount;
|
||||
self.debugInfo.currentCapturedVideoCount = self.debugInfo.capturedVideoCount;
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketDebug:debugInfo:)]){
|
||||
[self.delegate socketDebug:self debugInfo:self.debugInfo];
|
||||
}
|
||||
//修改发送状态
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
//< 这里只为了不循环调用sendFrame方法 调用栈是保证先出栈再进栈
|
||||
_self.isSending = NO;
|
||||
});
|
||||
|
||||
self.debugInfo.bandwidth = 0;
|
||||
self.debugInfo.capturedAudioCount = 0;
|
||||
self.debugInfo.capturedVideoCount = 0;
|
||||
self.debugInfo.timeStamp = CACurrentMediaTime()*1000;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)clean{
|
||||
- (void)clean {
|
||||
_isConnecting = NO;
|
||||
_isReconnecting = NO;
|
||||
_isSending = NO;
|
||||
@@ -196,71 +240,54 @@ SAVC(mp4a);
|
||||
self.retryTimes4netWorkBreaken = 0;
|
||||
}
|
||||
|
||||
-(NSInteger) RTMP264_Connect:(char *)push_url{
|
||||
- (NSInteger)RTMP264_Connect:(char *)push_url {
|
||||
//由于摄像头的timestamp是一直在累加,需要每次得到相对时间戳
|
||||
//分配与初始化
|
||||
if(_isConnecting) return -1;
|
||||
|
||||
_isConnecting = YES;
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
|
||||
[self.delegate socketStatus:self status:LFLivePending];
|
||||
}
|
||||
|
||||
if(_rtmp != NULL){
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
}
|
||||
|
||||
_rtmp = PILI_RTMP_Alloc();
|
||||
PILI_RTMP_Init(_rtmp);
|
||||
|
||||
|
||||
//设置URL
|
||||
if (PILI_RTMP_SetupURL(_rtmp, push_url, &_error) == FALSE){
|
||||
if (PILI_RTMP_SetupURL(_rtmp, push_url, &_error) == FALSE) {
|
||||
//log(LOG_ERR, "RTMP_SetupURL() failed!");
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
_rtmp->m_errorCallback = RTMPErrorCallback;
|
||||
|
||||
_rtmp->m_errorCallback = RTMPErrorCallback;
|
||||
_rtmp->m_connCallback = ConnectionTimeCallback;
|
||||
_rtmp->m_userData = (__bridge void*)self;
|
||||
_rtmp->m_userData = (__bridge void *)self;
|
||||
_rtmp->m_msgCounter = 1;
|
||||
_rtmp->Link.timeout = RTMP_RECEIVE_TIMEOUT;
|
||||
|
||||
//设置可写,即发布流,这个函数必须在连接前使用,否则无效
|
||||
PILI_RTMP_EnableWrite(_rtmp);
|
||||
|
||||
|
||||
//连接服务器
|
||||
if (PILI_RTMP_Connect(_rtmp, NULL, &_error) == FALSE){
|
||||
if (PILI_RTMP_Connect(_rtmp, NULL, &_error) == FALSE) {
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
|
||||
//连接流
|
||||
if (PILI_RTMP_ConnectStream(_rtmp, 0, &_error) == FALSE) {
|
||||
goto Failed;
|
||||
}
|
||||
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]) {
|
||||
[self.delegate socketStatus:self status:LFLiveStart];
|
||||
}
|
||||
|
||||
|
||||
[self sendMetaData];
|
||||
|
||||
|
||||
_isConnected = YES;
|
||||
_isConnecting = NO;
|
||||
_isReconnecting = NO;
|
||||
_isSending = NO;
|
||||
_retryTimes4netWorkBreaken = 0;
|
||||
return 0;
|
||||
|
||||
|
||||
Failed:
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
_rtmp = NULL;
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketDidError:errorCode:)]){
|
||||
[self.delegate socketDidError:self errorCode:LFLiveSocketError_ConnectSocket];
|
||||
}
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]){
|
||||
[self.delegate socketStatus:self status:LFLiveError];
|
||||
}
|
||||
[self reconnect];
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -268,252 +295,286 @@ Failed:
|
||||
|
||||
- (void)sendMetaData {
|
||||
PILI_RTMPPacket packet;
|
||||
|
||||
char pbuf[2048], *pend = pbuf+sizeof(pbuf);
|
||||
|
||||
packet.m_nChannel = 0x03; // control channel (invoke)
|
||||
|
||||
char pbuf[2048], *pend = pbuf + sizeof(pbuf);
|
||||
|
||||
packet.m_nChannel = 0x03; // control channel (invoke)
|
||||
packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
|
||||
packet.m_packetType = RTMP_PACKET_TYPE_INFO;
|
||||
packet.m_nTimeStamp = 0;
|
||||
packet.m_nInfoField2 = _rtmp->m_stream_id;
|
||||
packet.m_hasAbsTimestamp = TRUE;
|
||||
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
|
||||
|
||||
|
||||
char *enc = packet.m_body;
|
||||
enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
|
||||
enc = AMF_EncodeString(enc, pend, &av_onMetaData);
|
||||
|
||||
|
||||
*enc++ = AMF_OBJECT;
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_duration, 0.0);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_fileSize, 0.0);
|
||||
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_duration, 0.0);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_fileSize, 0.0);
|
||||
|
||||
// videosize
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_width, _stream.videoConfiguration.videoSize.width);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_height, _stream.videoConfiguration.videoSize.height);
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_width, _stream.videoConfiguration.videoSize.width);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_height, _stream.videoConfiguration.videoSize.height);
|
||||
|
||||
// video
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_videocodecid, &av_avc1);
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_videodatarate, _stream.videoConfiguration.videoBitRate / 1000.f);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_framerate, _stream.videoConfiguration.videoFrameRate);
|
||||
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_videocodecid, &av_avc1);
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_videodatarate, _stream.videoConfiguration.videoBitRate / 1000.f);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_framerate, _stream.videoConfiguration.videoFrameRate);
|
||||
|
||||
// audio
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_audiocodecid, &av_mp4a);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiodatarate, _stream.audioConfiguration.audioBitrate);
|
||||
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_audiocodecid, &av_mp4a);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiodatarate, _stream.audioConfiguration.audioBitrate);
|
||||
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplerate, _stream.audioConfiguration.audioSampleRate);
|
||||
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplesize, 16.0);
|
||||
enc = AMF_EncodeNamedBoolean(enc, pend, &av_stereo, _stream.audioConfiguration.numberOfChannels==2);
|
||||
|
||||
enc = AMF_EncodeNamedBoolean(enc, pend, &av_stereo, _stream.audioConfiguration.numberOfChannels == 2);
|
||||
|
||||
// sdk version
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_encoder, &av_SDKVersion);
|
||||
|
||||
enc = AMF_EncodeNamedString(enc, pend, &av_encoder, &av_SDKVersion);
|
||||
|
||||
*enc++ = 0;
|
||||
*enc++ = 0;
|
||||
*enc++ = AMF_OBJECT_END;
|
||||
|
||||
packet.m_nBodySize = enc - packet.m_body;
|
||||
if(!PILI_RTMP_SendPacket(_rtmp, &packet, FALSE, &_error)) {
|
||||
|
||||
packet.m_nBodySize = (uint32_t)(enc - packet.m_body);
|
||||
if (!PILI_RTMP_SendPacket(_rtmp, &packet, FALSE, &_error)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendVideoHeader:(LFVideoFrame*)videoFrame {
|
||||
if(!videoFrame || !videoFrame.sps || !videoFrame.pps) return;
|
||||
|
||||
unsigned char * body=NULL;
|
||||
- (void)sendVideoHeader:(LFVideoFrame *)videoFrame {
|
||||
|
||||
unsigned char *body = NULL;
|
||||
NSInteger iIndex = 0;
|
||||
NSInteger rtmpLength = 1024;
|
||||
const char *sps = videoFrame.sps.bytes;
|
||||
const char *pps = videoFrame.pps.bytes;
|
||||
NSInteger sps_len = videoFrame.sps.length;
|
||||
NSInteger pps_len = videoFrame.pps.length;
|
||||
|
||||
body = (unsigned char*)malloc(rtmpLength);
|
||||
memset(body,0,rtmpLength);
|
||||
|
||||
|
||||
body = (unsigned char *)malloc(rtmpLength);
|
||||
memset(body, 0, rtmpLength);
|
||||
|
||||
body[iIndex++] = 0x17;
|
||||
body[iIndex++] = 0x00;
|
||||
|
||||
|
||||
body[iIndex++] = 0x00;
|
||||
body[iIndex++] = 0x00;
|
||||
body[iIndex++] = 0x00;
|
||||
|
||||
|
||||
body[iIndex++] = 0x01;
|
||||
body[iIndex++] = sps[1];
|
||||
body[iIndex++] = sps[2];
|
||||
body[iIndex++] = sps[3];
|
||||
body[iIndex++] = 0xff;
|
||||
|
||||
|
||||
/*sps*/
|
||||
body[iIndex++] = 0xe1;
|
||||
body[iIndex++] = 0xe1;
|
||||
body[iIndex++] = (sps_len >> 8) & 0xff;
|
||||
body[iIndex++] = sps_len & 0xff;
|
||||
memcpy(&body[iIndex],sps,sps_len);
|
||||
iIndex += sps_len;
|
||||
|
||||
memcpy(&body[iIndex], sps, sps_len);
|
||||
iIndex += sps_len;
|
||||
|
||||
/*pps*/
|
||||
body[iIndex++] = 0x01;
|
||||
body[iIndex++] = 0x01;
|
||||
body[iIndex++] = (pps_len >> 8) & 0xff;
|
||||
body[iIndex++] = (pps_len) & 0xff;
|
||||
memcpy(&body[iIndex], pps, pps_len);
|
||||
iIndex += pps_len;
|
||||
|
||||
iIndex += pps_len;
|
||||
|
||||
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:iIndex nTimestamp:0];
|
||||
free(body);
|
||||
}
|
||||
|
||||
- (void)sendVideo:(LFVideoFrame *)frame {
|
||||
|
||||
- (void)sendVideo:(LFVideoFrame*)frame{
|
||||
if(!frame || !frame.data || frame.data.length < 11) return;
|
||||
|
||||
NSInteger i = 0;
|
||||
NSInteger rtmpLength = frame.data.length+9;
|
||||
unsigned char *body = (unsigned char*)malloc(rtmpLength);
|
||||
memset(body,0,rtmpLength);
|
||||
|
||||
if(frame.isKeyFrame){
|
||||
body[i++] = 0x17;// 1:Iframe 7:AVC
|
||||
} else{
|
||||
body[i++] = 0x27;// 2:Pframe 7:AVC
|
||||
NSInteger rtmpLength = frame.data.length + 9;
|
||||
unsigned char *body = (unsigned char *)malloc(rtmpLength);
|
||||
memset(body, 0, rtmpLength);
|
||||
|
||||
if (frame.isKeyFrame) {
|
||||
body[i++] = 0x17; // 1:Iframe 7:AVC
|
||||
} else {
|
||||
body[i++] = 0x27; // 2:Pframe 7:AVC
|
||||
}
|
||||
body[i++] = 0x01;// AVC NALU
|
||||
body[i++] = 0x01; // AVC NALU
|
||||
body[i++] = 0x00;
|
||||
body[i++] = 0x00;
|
||||
body[i++] = 0x00;
|
||||
body[i++] = (frame.data.length >> 24) & 0xff;
|
||||
body[i++] = (frame.data.length >> 16) & 0xff;
|
||||
body[i++] = (frame.data.length >> 8) & 0xff;
|
||||
body[i++] = (frame.data.length ) & 0xff;
|
||||
memcpy(&body[i],frame.data.bytes,frame.data.length);
|
||||
|
||||
body[i++] = (frame.data.length) & 0xff;
|
||||
memcpy(&body[i], frame.data.bytes, frame.data.length);
|
||||
|
||||
[self sendPacket:RTMP_PACKET_TYPE_VIDEO data:body size:(rtmpLength) nTimestamp:frame.timestamp];
|
||||
free(body);
|
||||
}
|
||||
|
||||
-(NSInteger) sendPacket:(unsigned int)nPacketType data:(unsigned char *)data size:(NSInteger) size nTimestamp:(uint64_t) nTimestamp{
|
||||
- (NSInteger)sendPacket:(unsigned int)nPacketType data:(unsigned char *)data size:(NSInteger)size nTimestamp:(uint64_t)nTimestamp {
|
||||
NSInteger rtmpLength = size;
|
||||
PILI_RTMPPacket rtmp_pack;
|
||||
PILI_RTMPPacket_Reset(&rtmp_pack);
|
||||
PILI_RTMPPacket_Alloc(&rtmp_pack,(uint32_t)rtmpLength);
|
||||
|
||||
PILI_RTMPPacket_Alloc(&rtmp_pack, (uint32_t)rtmpLength);
|
||||
|
||||
rtmp_pack.m_nBodySize = (uint32_t)size;
|
||||
memcpy(rtmp_pack.m_body,data,size);
|
||||
memcpy(rtmp_pack.m_body, data, size);
|
||||
rtmp_pack.m_hasAbsTimestamp = 0;
|
||||
rtmp_pack.m_packetType = nPacketType;
|
||||
if(_rtmp) rtmp_pack.m_nInfoField2 = _rtmp->m_stream_id;
|
||||
if (_rtmp) rtmp_pack.m_nInfoField2 = _rtmp->m_stream_id;
|
||||
rtmp_pack.m_nChannel = 0x04;
|
||||
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_LARGE;
|
||||
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size !=4){
|
||||
if (RTMP_PACKET_TYPE_AUDIO == nPacketType && size != 4) {
|
||||
rtmp_pack.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
|
||||
}
|
||||
rtmp_pack.m_nTimeStamp = (uint32_t)nTimestamp;
|
||||
|
||||
|
||||
NSInteger nRet = [self RtmpPacketSend:&rtmp_pack];
|
||||
|
||||
|
||||
PILI_RTMPPacket_Free(&rtmp_pack);
|
||||
return nRet;
|
||||
}
|
||||
|
||||
- (NSInteger)RtmpPacketSend:(PILI_RTMPPacket*)packet{
|
||||
if (PILI_RTMP_IsConnected(_rtmp)){
|
||||
int success = PILI_RTMP_SendPacket(_rtmp,packet,0,&_error);
|
||||
if(success){
|
||||
self.isSending = NO;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self sendFrame];
|
||||
});
|
||||
|
||||
}
|
||||
- (NSInteger)RtmpPacketSend:(PILI_RTMPPacket *)packet {
|
||||
if (_rtmp && PILI_RTMP_IsConnected(_rtmp)) {
|
||||
int success = PILI_RTMP_SendPacket(_rtmp, packet, 0, &_error);
|
||||
return success;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (void)sendAudioHeader:(LFAudioFrame*)audioFrame{
|
||||
if(!audioFrame || !audioFrame.audioInfo) return;
|
||||
|
||||
NSInteger rtmpLength = audioFrame.audioInfo.length + 2;/*spec data长度,一般是2*/
|
||||
unsigned char * body = (unsigned char*)malloc(rtmpLength);
|
||||
memset(body,0,rtmpLength);
|
||||
|
||||
- (void)sendAudioHeader:(LFAudioFrame *)audioFrame {
|
||||
|
||||
NSInteger rtmpLength = audioFrame.audioInfo.length + 2; /*spec data长度,一般是2*/
|
||||
unsigned char *body = (unsigned char *)malloc(rtmpLength);
|
||||
memset(body, 0, rtmpLength);
|
||||
|
||||
/*AF 00 + AAC RAW data*/
|
||||
body[0] = 0xAF;
|
||||
body[1] = 0x00;
|
||||
memcpy(&body[2],audioFrame.audioInfo.bytes,audioFrame.audioInfo.length); /*spec_buf是AAC sequence header数据*/
|
||||
memcpy(&body[2], audioFrame.audioInfo.bytes, audioFrame.audioInfo.length); /*spec_buf是AAC sequence header数据*/
|
||||
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:0];
|
||||
free(body);
|
||||
}
|
||||
|
||||
- (void)sendAudio:(LFFrame*)frame {
|
||||
if(!frame) return;
|
||||
|
||||
NSInteger rtmpLength = frame.data.length + 2;/*spec data长度,一般是2*/
|
||||
unsigned char * body = (unsigned char*)malloc(rtmpLength);
|
||||
memset(body,0,rtmpLength);
|
||||
|
||||
- (void)sendAudio:(LFFrame *)frame {
|
||||
|
||||
NSInteger rtmpLength = frame.data.length + 2; /*spec data长度,一般是2*/
|
||||
unsigned char *body = (unsigned char *)malloc(rtmpLength);
|
||||
memset(body, 0, rtmpLength);
|
||||
|
||||
/*AF 01 + AAC RAW data*/
|
||||
body[0] = 0xAF;
|
||||
body[1] = 0x01;
|
||||
memcpy(&body[2],frame.data.bytes,frame.data.length);
|
||||
memcpy(&body[2], frame.data.bytes, frame.data.length);
|
||||
[self sendPacket:RTMP_PACKET_TYPE_AUDIO data:body size:rtmpLength nTimestamp:frame.timestamp];
|
||||
free(body);
|
||||
}
|
||||
|
||||
// 断线重连
|
||||
-(void) reconnect {
|
||||
dispatch_async(YYRtmpSendQueue(), ^{
|
||||
_isReconnecting = NO;
|
||||
if(_isConnected) return;
|
||||
|
||||
[self _stop];
|
||||
[self _start];
|
||||
- (void)reconnect {
|
||||
dispatch_async(self.rtmpSendQueue, ^{
|
||||
if (self.retryTimes4netWorkBreaken++ < self.reconnectCount && !self.isReconnecting) {
|
||||
self.isConnected = NO;
|
||||
self.isConnecting = NO;
|
||||
self.isReconnecting = YES;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self performSelector:@selector(_reconnect) withObject:nil afterDelay:self.reconnectInterval];
|
||||
});
|
||||
|
||||
} else if (self.retryTimes4netWorkBreaken >= self.reconnectCount) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]) {
|
||||
[self.delegate socketStatus:self status:LFLiveError];
|
||||
}
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketDidError:errorCode:)]) {
|
||||
[self.delegate socketDidError:self errorCode:LFLiveSocketError_ReConnectTimeOut];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)_reconnect{
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self];
|
||||
|
||||
_isReconnecting = NO;
|
||||
if(_isConnected) return;
|
||||
|
||||
_isReconnecting = NO;
|
||||
if (_isConnected) return;
|
||||
if (_rtmp != NULL) {
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
_rtmp = NULL;
|
||||
}
|
||||
_sendAudioHead = NO;
|
||||
_sendVideoHead = NO;
|
||||
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(socketStatus:status:)]) {
|
||||
[self.delegate socketStatus:self status:LFLiveRefresh];
|
||||
}
|
||||
|
||||
if (_rtmp != NULL) {
|
||||
PILI_RTMP_Close(_rtmp, &_error);
|
||||
PILI_RTMP_Free(_rtmp);
|
||||
}
|
||||
[self RTMP264_Connect:(char *)[_stream.url cStringUsingEncoding:NSASCIIStringEncoding]];
|
||||
}
|
||||
|
||||
#pragma mark -- CallBack
|
||||
void RTMPErrorCallback(RTMPError *error, void *userData){
|
||||
LFStreamRtmpSocket *socket = (__bridge LFStreamRtmpSocket*)userData;
|
||||
if(error->code < 0){
|
||||
if(socket.retryTimes4netWorkBreaken++ < socket.reconnectCount && !socket.isReconnecting){
|
||||
socket.isConnected = NO;
|
||||
socket.isConnecting = NO;
|
||||
socket.isReconnecting = YES;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(socket.reconnectInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[socket reconnect];
|
||||
});
|
||||
}else if(socket.retryTimes4netWorkBreaken >= socket.reconnectCount){
|
||||
if(socket.delegate && [socket.delegate respondsToSelector:@selector(socketStatus:status:)]){
|
||||
[socket.delegate socketStatus:socket status:LFLiveError];
|
||||
}
|
||||
if(socket.delegate && [socket.delegate respondsToSelector:@selector(socketDidError:errorCode:)]){
|
||||
[socket.delegate socketDidError:socket errorCode:LFLiveSocketError_ReConnectTimeOut];
|
||||
}
|
||||
void RTMPErrorCallback(RTMPError *error, void *userData) {
|
||||
LFStreamRTMPSocket *socket = (__bridge LFStreamRTMPSocket *)userData;
|
||||
if (error->code < 0) {
|
||||
[socket reconnect];
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionTimeCallback(PILI_CONNECTION_TIME *conn_time, void *userData) {
|
||||
}
|
||||
|
||||
#pragma mark -- LFStreamingBufferDelegate
|
||||
- (void)streamingBuffer:(nullable LFStreamingBuffer *)buffer bufferState:(LFLiveBuffferState)state{
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(socketBufferStatus:status:)]){
|
||||
[self.delegate socketBufferStatus:self status:state];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- Observer
|
||||
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
|
||||
if([keyPath isEqualToString:@"isSending"]){
|
||||
if(!self.isSending){
|
||||
[self sendFrame];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionTimeCallback(PILI_CONNECTION_TIME* conn_time, void *userData){
|
||||
//LFStreamRtmpSocket *socket = (__bridge LFStreamRtmpSocket*)userData;
|
||||
}
|
||||
|
||||
#pragma mark -- Getter Setter
|
||||
|
||||
- (LFStreamingBuffer*)buffer{
|
||||
if(!_buffer){
|
||||
- (LFStreamingBuffer *)buffer {
|
||||
if (!_buffer) {
|
||||
_buffer = [[LFStreamingBuffer alloc] init];
|
||||
_buffer.delegate = self;
|
||||
|
||||
}
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
- (LFLiveDebug*)debugInfo{
|
||||
if(!_debugInfo){
|
||||
- (LFLiveDebug *)debugInfo {
|
||||
if (!_debugInfo) {
|
||||
_debugInfo = [[LFLiveDebug alloc] init];
|
||||
}
|
||||
return _debugInfo;
|
||||
}
|
||||
|
||||
- (dispatch_queue_t)rtmpSendQueue{
|
||||
if(!_rtmpSendQueue){
|
||||
_rtmpSendQueue = dispatch_queue_create("com.youku.LaiFeng.RtmpSendQueue", NULL);
|
||||
}
|
||||
return _rtmpSendQueue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// LFStreamSocket.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by admin on 16/5/3.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -11,27 +11,28 @@
|
||||
#import "LFStreamingBuffer.h"
|
||||
#import "LFLiveDebug.h"
|
||||
|
||||
@protocol LFStreamSocket ;
|
||||
|
||||
|
||||
@protocol LFStreamSocket;
|
||||
@protocol LFStreamSocketDelegate <NSObject>
|
||||
|
||||
/** callback buffer current status (回调当前缓冲区情况,可实现相关切换帧率 码率等策略)*/
|
||||
- (void)socketBufferStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveBuffferState)status;
|
||||
- (void)socketBufferStatus:(nullable id <LFStreamSocket>)socket status:(LFLiveBuffferState)status;
|
||||
/** callback socket current status (回调当前网络情况) */
|
||||
- (void)socketStatus:(nullable id<LFStreamSocket>)socket status:(LFLiveState)status;
|
||||
- (void)socketStatus:(nullable id <LFStreamSocket>)socket status:(LFLiveState)status;
|
||||
/** callback socket errorcode */
|
||||
- (void)socketDidError:(nullable id<LFStreamSocket>)socket errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
- (void)socketDidError:(nullable id <LFStreamSocket>)socket errorCode:(LFLiveSocketErrorCode)errorCode;
|
||||
@optional
|
||||
/** callback debugInfo */
|
||||
- (void)socketDebug:(nullable id<LFStreamSocket>)socket debugInfo:(nullable LFLiveDebug*)debugInfo;
|
||||
- (void)socketDebug:(nullable id <LFStreamSocket>)socket debugInfo:(nullable LFLiveDebug *)debugInfo;
|
||||
@end
|
||||
|
||||
@protocol LFStreamSocket <NSObject>
|
||||
- (void) start;
|
||||
- (void) stop;
|
||||
- (void) sendFrame:(nullable LFFrame*)frame;
|
||||
- (void) setDelegate:(nullable id<LFStreamSocketDelegate>)delegate;
|
||||
- (void)start;
|
||||
- (void)stop;
|
||||
- (void)sendFrame:(nullable LFFrame *)frame;
|
||||
- (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;
|
||||
- (nullable instancetype)initWithStream:(nullable LFLiveStreamInfo *)stream reconnectInterval:(NSInteger)reconnectInterval reconnectCount:(NSInteger)reconnectCount;
|
||||
@end
|
||||
|
||||
@@ -2,19 +2,20 @@
|
||||
// LFStreamingBuffer.h
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "LFAudioFrame.h"
|
||||
#import "LFVideoFrame.h"
|
||||
|
||||
|
||||
/** current buffer status */
|
||||
typedef NS_ENUM(NSUInteger, LFLiveBuffferState) {
|
||||
typedef NS_ENUM (NSUInteger, LFLiveBuffferState) {
|
||||
LFLiveBuffferUnknown = 0, //< 未知
|
||||
LFLiveBuffferIncrease = 1, //< 缓冲区状态好可以增加码率
|
||||
LFLiveBuffferDecline = 2 //< 缓冲区状态差应该降低码率
|
||||
LFLiveBuffferIncrease = 1, //< 缓冲区状态差应该降低码率
|
||||
LFLiveBuffferDecline = 2 //< 缓冲区状态好应该提升码率
|
||||
};
|
||||
|
||||
@class LFStreamingBuffer;
|
||||
@@ -22,25 +23,29 @@ typedef NS_ENUM(NSUInteger, LFLiveBuffferState) {
|
||||
@protocol LFStreamingBufferDelegate <NSObject>
|
||||
@optional
|
||||
/** 当前buffer变动(增加or减少) 根据buffer中的updateInterval时间回调*/
|
||||
- (void)streamingBuffer:(nullable LFStreamingBuffer * )buffer bufferState:(LFLiveBuffferState)state;
|
||||
- (void)streamingBuffer:(nullable LFStreamingBuffer *)buffer bufferState:(LFLiveBuffferState)state;
|
||||
@end
|
||||
|
||||
@interface LFStreamingBuffer : NSObject
|
||||
|
||||
|
||||
/** The delegate of the buffer. buffer callback */
|
||||
@property (nullable,nonatomic, weak) id <LFStreamingBufferDelegate> delegate;
|
||||
@property (nullable, nonatomic, weak) id <LFStreamingBufferDelegate> delegate;
|
||||
|
||||
/** current frame buffer */
|
||||
@property (nonatomic, strong, readonly) NSMutableArray <LFFrame*>* _Nonnull list;
|
||||
@property (nonatomic, strong, readonly) NSMutableArray <LFFrame *> *_Nonnull list;
|
||||
|
||||
/** buffer count max size default 1000 */
|
||||
@property (nonatomic, assign) NSUInteger maxCount;
|
||||
|
||||
/** count of drop frames in last time */
|
||||
@property (nonatomic, assign) NSInteger lastDropFrames;
|
||||
|
||||
/** add frame to buffer */
|
||||
- (void)appendObject:(nullable LFFrame*)frame;
|
||||
- (void)appendObject:(nullable LFFrame *)frame;
|
||||
|
||||
/** pop the first frome buffer */
|
||||
- (nullable LFFrame*)popFirstObject;
|
||||
- (nullable LFFrame *)popFirstObject;
|
||||
|
||||
/** remove all objects from Buffer */
|
||||
- (void)removeAllObject;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// LFStreamingBuffer.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFStreamingBuffer.h"
|
||||
#import "NSMutableArray+LFAdd.h"
|
||||
|
||||
static const NSUInteger defaultSortBufferMaxCount = 10;///< 排序10个内
|
||||
static const NSUInteger defaultSortBufferMaxCount = 5;///< 排序10个内
|
||||
static const NSUInteger defaultUpdateInterval = 1;///< 更新频率为1s
|
||||
static const NSUInteger defaultCallBackInterval = 5;///< 5s计时一次
|
||||
static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为600
|
||||
@@ -18,8 +18,8 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
dispatch_semaphore_t _lock;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) NSMutableArray <LFFrame*>*sortList;
|
||||
@property (nonatomic, strong, readwrite) NSMutableArray <LFFrame*>*list;
|
||||
@property (nonatomic, strong) NSMutableArray <LFFrame *> *sortList;
|
||||
@property (nonatomic, strong, readwrite) NSMutableArray <LFFrame *> *list;
|
||||
@property (nonatomic, strong) NSMutableArray *thresholdList;
|
||||
|
||||
/** 处理buffer缓冲区情况 */
|
||||
@@ -32,31 +32,34 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
|
||||
@implementation LFStreamingBuffer
|
||||
|
||||
- (instancetype)init{
|
||||
if(self = [super init]){
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
|
||||
_lock = dispatch_semaphore_create(1);
|
||||
self.updateInterval = defaultUpdateInterval;
|
||||
self.callBackInterval = defaultCallBackInterval;
|
||||
self.maxCount = defaultSendBufferMaxCount;
|
||||
self.lastDropFrames = 0;
|
||||
self.startTimer = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
- (void)dealloc {
|
||||
}
|
||||
|
||||
#pragma mark -- Custom
|
||||
- (void)appendObject:(LFFrame*)frame{
|
||||
if(!frame) return;
|
||||
if(!_startTimer){
|
||||
- (void)appendObject:(LFFrame *)frame {
|
||||
if (!frame) return;
|
||||
if (!_startTimer) {
|
||||
_startTimer = YES;
|
||||
[self tick];
|
||||
}
|
||||
|
||||
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
if(self.sortList.count < defaultSortBufferMaxCount){
|
||||
if (self.sortList.count < defaultSortBufferMaxCount) {
|
||||
[self.sortList addObject:frame];
|
||||
}else{
|
||||
} else {
|
||||
///< 排序
|
||||
[self.sortList addObject:frame];
|
||||
NSArray *sortedSendQuery = [self.sortList sortedArrayUsingFunction:frameDataCompare context:NULL];
|
||||
@@ -66,36 +69,38 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
[self removeExpireFrame];
|
||||
/// 添加至缓冲区
|
||||
LFFrame *firstFrame = [self.sortList lfPopFirstObject];
|
||||
|
||||
if(firstFrame) [self.list addObject:firstFrame];
|
||||
|
||||
if (firstFrame) [self.list addObject:firstFrame];
|
||||
}
|
||||
dispatch_semaphore_signal(_lock);
|
||||
}
|
||||
|
||||
- (LFFrame*)popFirstObject{
|
||||
- (LFFrame *)popFirstObject {
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
LFFrame *firstFrame = [self.list lfPopFirstObject];
|
||||
dispatch_semaphore_signal(_lock);
|
||||
return firstFrame;
|
||||
}
|
||||
|
||||
- (void)removeAllObject{
|
||||
- (void)removeAllObject {
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
[self.list removeAllObjects];
|
||||
dispatch_semaphore_signal(_lock);
|
||||
}
|
||||
|
||||
- (void)removeExpireFrame{
|
||||
if(self.list.count < self.maxCount) return;
|
||||
|
||||
- (void)removeExpireFrame {
|
||||
if (self.list.count < self.maxCount) return;
|
||||
|
||||
NSArray *pFrames = [self expirePFrames];///< 第一个P到第一个I之间的p帧
|
||||
if(pFrames && pFrames.count > 0){
|
||||
self.lastDropFrames += [pFrames count];
|
||||
if (pFrames && pFrames.count > 0) {
|
||||
[self.list removeObjectsInArray:pFrames];
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray *iFrames = [self expireIFrames];///< 删除一个I帧(但一个I帧可能对应多个nal)
|
||||
if(iFrames){
|
||||
self.lastDropFrames += [iFrames count];
|
||||
if (iFrames) {
|
||||
[self.list removeObjectsInArray:iFrames];
|
||||
return;
|
||||
}
|
||||
@@ -103,15 +108,15 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
[self.list removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSArray*)expirePFrames{
|
||||
- (NSArray *)expirePFrames {
|
||||
NSMutableArray *pframes = [[NSMutableArray alloc] init];
|
||||
for(NSInteger index = 0;index < self.list.count;index++){
|
||||
for (NSInteger index = 0; index < self.list.count; index++) {
|
||||
LFFrame *frame = [self.list objectAtIndex:index];
|
||||
if([frame isKindOfClass:[LFVideoFrame class]]){
|
||||
LFVideoFrame *videoFrame = (LFVideoFrame*)frame;
|
||||
if(videoFrame.isKeyFrame && pframes.count > 0){
|
||||
if ([frame isKindOfClass:[LFVideoFrame class]]) {
|
||||
LFVideoFrame *videoFrame = (LFVideoFrame *)frame;
|
||||
if (videoFrame.isKeyFrame && pframes.count > 0) {
|
||||
break;
|
||||
}else if(!videoFrame.isKeyFrame){
|
||||
} else if (!videoFrame.isKeyFrame) {
|
||||
[pframes addObject:frame];
|
||||
}
|
||||
}
|
||||
@@ -119,13 +124,13 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
return pframes;
|
||||
}
|
||||
|
||||
- (NSArray*)expireIFrames{
|
||||
- (NSArray *)expireIFrames {
|
||||
NSMutableArray *iframes = [[NSMutableArray alloc] init];
|
||||
uint64_t timeStamp = 0;
|
||||
for(NSInteger index = 0;index < self.list.count;index++){
|
||||
for (NSInteger index = 0; index < self.list.count; index++) {
|
||||
LFFrame *frame = [self.list objectAtIndex:index];
|
||||
if([frame isKindOfClass:[LFVideoFrame class]] && ((LFVideoFrame*)frame).isKeyFrame){
|
||||
if(timeStamp != 0 && timeStamp != frame.timestamp) break;
|
||||
if ([frame isKindOfClass:[LFVideoFrame class]] && ((LFVideoFrame *)frame).isKeyFrame) {
|
||||
if (timeStamp != 0 && timeStamp != frame.timestamp) break;
|
||||
[iframes addObject:frame];
|
||||
timeStamp = frame.timestamp;
|
||||
}
|
||||
@@ -134,35 +139,35 @@ static const NSUInteger defaultSendBufferMaxCount = 600;///< 最大缓冲区为6
|
||||
}
|
||||
|
||||
NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
LFFrame* frame1 = (LFFrame*) obj1;
|
||||
LFFrame *frame2 = (LFFrame*) obj2;
|
||||
|
||||
LFFrame *frame1 = (LFFrame *)obj1;
|
||||
LFFrame *frame2 = (LFFrame *)obj2;
|
||||
|
||||
if (frame1.timestamp == frame2.timestamp)
|
||||
return NSOrderedSame;
|
||||
else if(frame1.timestamp > frame2.timestamp)
|
||||
else if (frame1.timestamp > frame2.timestamp)
|
||||
return NSOrderedDescending;
|
||||
return NSOrderedAscending;
|
||||
}
|
||||
|
||||
- (LFLiveBuffferState)currentBufferState{
|
||||
- (LFLiveBuffferState)currentBufferState {
|
||||
NSInteger currentCount = 0;
|
||||
NSInteger increaseCount = 0;
|
||||
NSInteger decreaseCount = 0;
|
||||
|
||||
for(NSNumber *number in self.thresholdList){
|
||||
if(number.integerValue >= currentCount){
|
||||
increaseCount ++;
|
||||
}else{
|
||||
decreaseCount ++;
|
||||
|
||||
for (NSNumber *number in self.thresholdList) {
|
||||
if (number.integerValue > currentCount) {
|
||||
increaseCount++;
|
||||
} else{
|
||||
decreaseCount++;
|
||||
}
|
||||
currentCount = [number integerValue];
|
||||
}
|
||||
|
||||
if(increaseCount >= self.callBackInterval){
|
||||
|
||||
if (increaseCount >= self.callBackInterval) {
|
||||
return LFLiveBuffferIncrease;
|
||||
}
|
||||
|
||||
if(decreaseCount >= self.callBackInterval){
|
||||
|
||||
if (decreaseCount >= self.callBackInterval) {
|
||||
return LFLiveBuffferDecline;
|
||||
}
|
||||
|
||||
@@ -170,55 +175,54 @@ NSInteger frameDataCompare(id obj1, id obj2, void *context){
|
||||
}
|
||||
|
||||
#pragma mark -- Setter Getter
|
||||
- (NSMutableArray*)list{
|
||||
if(!_list){
|
||||
- (NSMutableArray *)list {
|
||||
if (!_list) {
|
||||
_list = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return _list;
|
||||
}
|
||||
|
||||
- (NSMutableArray*)sortList{
|
||||
if(!_sortList){
|
||||
- (NSMutableArray *)sortList {
|
||||
if (!_sortList) {
|
||||
_sortList = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return _sortList;
|
||||
}
|
||||
|
||||
- (NSMutableArray*)thresholdList{
|
||||
if(!_thresholdList){
|
||||
- (NSMutableArray *)thresholdList {
|
||||
if (!_thresholdList) {
|
||||
_thresholdList = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return _thresholdList;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -- 采样
|
||||
- (void)tick{
|
||||
- (void)tick {
|
||||
/** 采样 3个阶段 如果网络都是好或者都是差给回调 */
|
||||
_currentInterval += self.updateInterval;
|
||||
|
||||
|
||||
dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER);
|
||||
[self.thresholdList addObject:@(self.list.count)];
|
||||
dispatch_semaphore_signal(_lock);
|
||||
|
||||
if(self.currentInterval >= self.callBackInterval){
|
||||
if (self.currentInterval >= self.callBackInterval) {
|
||||
LFLiveBuffferState state = [self currentBufferState];
|
||||
if(state == LFLiveBuffferIncrease){
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]){
|
||||
if (state == LFLiveBuffferIncrease) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]) {
|
||||
[self.delegate streamingBuffer:self bufferState:LFLiveBuffferIncrease];
|
||||
}
|
||||
}else if(state == LFLiveBuffferDecline){
|
||||
if(self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]){
|
||||
} else if (state == LFLiveBuffferDecline) {
|
||||
if (self.delegate && [self.delegate respondsToSelector:@selector(streamingBuffer:bufferState:)]) {
|
||||
[self.delegate streamingBuffer:self bufferState:LFLiveBuffferDecline];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.currentInterval = 0;
|
||||
[self.thresholdList removeAllObjects];
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.updateInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
__weak typeof(_self) self = _self;
|
||||
__strong typeof(_self) self = _self;
|
||||
[self tick];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// NSMutableArray+LFAdd.h
|
||||
// YYKit
|
||||
//
|
||||
// Created by admin on 16/5/20.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -11,10 +11,10 @@
|
||||
@interface NSMutableArray (YYAdd)
|
||||
|
||||
/**
|
||||
Removes and returns the object with the lowest-valued index in the array.
|
||||
If the array is empty, it just returns nil.
|
||||
|
||||
@return The first object, or nil.
|
||||
Removes and returns the object with the lowest-valued index in the array.
|
||||
If the array is empty, it just returns nil.
|
||||
|
||||
@return The first object, or nil.
|
||||
*/
|
||||
- (nullable id)lfPopFirstObject;
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// NSMutableArray+LFAdd.m
|
||||
// YYKit
|
||||
//
|
||||
// Created by admin on 16/5/20.
|
||||
// Copyright © 2016年 倾慕. All rights reserved.
|
||||
// Created by LaiFeng on 16/5/20.
|
||||
// Copyright © 2016年 LaiFeng All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSMutableArray+LFAdd.h"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
#CocoaPods
|
||||
Pods/
|
||||
Podfile.lock
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:LFLiveKitDemo.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,111 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "840763041D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemoTests.xctest"
|
||||
BlueprintName = "LFLiveKitDemoTests"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8407630F1D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemoUITests.xctest"
|
||||
BlueprintName = "LFLiveKitDemoUITests"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "840762EB1D07C7D0000FD0BF"
|
||||
BuildableName = "LFLiveKitDemo.app"
|
||||
BlueprintName = "LFLiveKitDemo"
|
||||
ReferencedContainer = "container:LFLiveKitDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>LFLiveKitDemo.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>840762EB1D07C7D0000FD0BF</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>840763041D07C7D0000FD0BF</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>8407630F1D07C7D0000FD0BF</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:LFLiveKitDemo.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,333 +0,0 @@
|
||||
//
|
||||
// LFLivePreview.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLivePreview.h"
|
||||
#import "UIControl+YYAdd.h"
|
||||
#import "UIView+YYAdd.h"
|
||||
#import "LFLiveSession.h"
|
||||
|
||||
@interface LFLivePreview ()<LFLiveSessionDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIButton *beautyButton;
|
||||
@property (nonatomic, strong) UIButton *cameraButton;
|
||||
@property (nonatomic, strong) UIButton *closeButton;
|
||||
@property (nonatomic, strong) UIButton *startLiveButton;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@property (nonatomic, strong) LFLiveDebug *debugInfo;
|
||||
@property (nonatomic, strong) LFLiveSession *session;
|
||||
@property (nonatomic, strong) UILabel *stateLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFLivePreview
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame{
|
||||
if(self = [super initWithFrame:frame]){
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
[self requestAccessForVideo];
|
||||
[self requestAccessForAudio];
|
||||
[self addSubview:self.containerView];
|
||||
[self.containerView addSubview:self.stateLabel];
|
||||
[self.containerView addSubview:self.closeButton];
|
||||
[self.containerView addSubview:self.cameraButton];
|
||||
[self.containerView addSubview:self.beautyButton];
|
||||
[self.containerView addSubview:self.startLiveButton];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -- Public Method
|
||||
- (void)requestAccessForVideo{
|
||||
__weak typeof(self) _self = self;
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
switch (status) {
|
||||
case AVAuthorizationStatusNotDetermined:{
|
||||
// 许可对话没有出现,发起授权许可
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
if (granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_self.session setRunning:YES];
|
||||
});
|
||||
}
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusAuthorized:{
|
||||
// 已经开启授权,可继续
|
||||
//dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_self.session setRunning:YES];
|
||||
//});
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusDenied:
|
||||
case AVAuthorizationStatusRestricted:
|
||||
// 用户明确地拒绝授权,或者相机设备无法访问
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestAccessForAudio{
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
|
||||
switch (status) {
|
||||
case AVAuthorizationStatusNotDetermined:{
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusAuthorized:{
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusDenied:
|
||||
case AVAuthorizationStatusRestricted:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -- LFStreamingSessionDelegate
|
||||
/** live status changed will callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state{
|
||||
NSLog(@"liveStateDidChange: %ld", state);
|
||||
switch (state) {
|
||||
case LFLiveReady:
|
||||
_stateLabel.text = @"未连接";
|
||||
break;
|
||||
case LFLivePending:
|
||||
_stateLabel.text = @"连接中";
|
||||
break;
|
||||
case LFLiveStart:
|
||||
_stateLabel.text = @"已连接";
|
||||
break;
|
||||
case LFLiveError:
|
||||
_stateLabel.text = @"连接错误";
|
||||
break;
|
||||
case LFLiveStop:
|
||||
_stateLabel.text = @"未连接";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** live debug info callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo{
|
||||
NSLog(@"debugInfo: %lf", debugInfo.dataFlow);
|
||||
}
|
||||
|
||||
/** callback socket errorcode */
|
||||
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode{
|
||||
NSLog(@"errorCode: %ld", errorCode);
|
||||
}
|
||||
|
||||
#pragma mark -- Getter Setter
|
||||
- (LFLiveSession*)session{
|
||||
if(!_session){
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
|
||||
|
||||
|
||||
/*** 默认分辨率368 * 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfigurationForQuality:LFLiveVideoQuality_Medium2 landscape:NO]];
|
||||
|
||||
|
||||
/** 自己定制单声道 */
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 1;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_64Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
*/
|
||||
|
||||
/** 自己定制高质量音频96K */
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
*/
|
||||
|
||||
/** 自己定制高质量音频96K 分辨率设置为540*960 方向竖屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(540, 960);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 24;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 48;
|
||||
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
|
||||
/** 自己定制高质量音频128K 分辨率设置为720*1280 方向竖屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(720, 1280);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
|
||||
/** 自己定制高质量音频128K 分辨率设置为720*1280 方向横屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(1280, 720);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.landscape = YES;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
_session.delegate = self;
|
||||
_session.preView = self;
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (UIView*)containerView{
|
||||
if(!_containerView){
|
||||
_containerView = [UIView new];
|
||||
_containerView.frame = self.bounds;
|
||||
_containerView.backgroundColor = [UIColor clearColor];
|
||||
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (UILabel*)stateLabel{
|
||||
if(!_stateLabel){
|
||||
_stateLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 80, 40)];
|
||||
_stateLabel.text = @"未连接";
|
||||
_stateLabel.textColor = [UIColor whiteColor];
|
||||
_stateLabel.font = [UIFont boldSystemFontOfSize:14.f];
|
||||
}
|
||||
return _stateLabel;
|
||||
}
|
||||
|
||||
- (UIButton*)closeButton{
|
||||
if(!_closeButton){
|
||||
_closeButton = [UIButton new];
|
||||
_closeButton.size = CGSizeMake(44, 44);
|
||||
_closeButton.left = self.width - 10 - _closeButton.width;
|
||||
_closeButton.top = 20;
|
||||
[_closeButton setImage:[UIImage imageNamed:@"close_preview"] forState:UIControlStateNormal];
|
||||
_closeButton.exclusiveTouch = YES;
|
||||
[_closeButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
|
||||
}];
|
||||
}
|
||||
return _closeButton;
|
||||
}
|
||||
|
||||
- (UIButton*)cameraButton{
|
||||
if(!_cameraButton){
|
||||
_cameraButton = [UIButton new];
|
||||
_cameraButton.size = CGSizeMake(44, 44);
|
||||
_cameraButton.origin = CGPointMake(_closeButton.left - 10 - _cameraButton.width, 20);
|
||||
[_cameraButton setImage:[UIImage imageNamed:@"camra_preview"] forState:UIControlStateNormal];
|
||||
_cameraButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_cameraButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
AVCaptureDevicePosition devicePositon = _self.session.captureDevicePosition;
|
||||
_self.session.captureDevicePosition = (devicePositon == AVCaptureDevicePositionBack) ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
|
||||
}];
|
||||
}
|
||||
return _cameraButton;
|
||||
}
|
||||
|
||||
- (UIButton*)beautyButton{
|
||||
if(!_beautyButton){
|
||||
_beautyButton = [UIButton new];
|
||||
_beautyButton.size = CGSizeMake(44, 44);
|
||||
_beautyButton.origin = CGPointMake(_cameraButton.left - 10 - _beautyButton.width,20);
|
||||
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty"] forState:UIControlStateSelected];
|
||||
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty_close"] forState:UIControlStateNormal];
|
||||
_beautyButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_beautyButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
_self.session.beautyFace = !_self.session.beautyFace;
|
||||
_self.beautyButton.selected = !_self.session.beautyFace;
|
||||
}];
|
||||
}
|
||||
return _beautyButton;
|
||||
}
|
||||
|
||||
- (UIButton*)startLiveButton{
|
||||
if(!_startLiveButton){
|
||||
_startLiveButton = [UIButton new];
|
||||
_startLiveButton.size = CGSizeMake(self.width - 60, 44);
|
||||
_startLiveButton.left = 30;
|
||||
_startLiveButton.bottom = self.height - 50;
|
||||
_startLiveButton.layer.cornerRadius = _startLiveButton.height/2;
|
||||
[_startLiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
[_startLiveButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
|
||||
[_startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
|
||||
[_startLiveButton setBackgroundColor:[UIColor colorWithRed:50 green:32 blue:245 alpha:1]];
|
||||
_startLiveButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_startLiveButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
_self.startLiveButton.selected = !_self.startLiveButton.selected;
|
||||
if(_self.startLiveButton.selected){
|
||||
[_self.startLiveButton setTitle:@"结束直播" forState:UIControlStateNormal];
|
||||
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
|
||||
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream789";
|
||||
//stream.url = @"rtmp://daniulive.com:1935/live/stream2399";
|
||||
[_self.session startLive:stream];
|
||||
}else{
|
||||
[_self.startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
|
||||
[_self.session stopLive];
|
||||
}
|
||||
}];
|
||||
}
|
||||
return _startLiveButton;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,8 +0,0 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios,'8.0'
|
||||
|
||||
target "LFLiveKitDemo" do
|
||||
|
||||
pod 'LFLiveKit', '~> 1.5.2'
|
||||
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios,'8.0'
|
||||
|
||||
target "LFLiveKitDemo" do
|
||||
|
||||
pod 'LFLiveKit', '~> 1.7.2'
|
||||
|
||||
end
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// LFLiveKitTests.m
|
||||
// LFLiveKitTests
|
||||
//
|
||||
// Created by admin on 16/6/2.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
@interface LFLiveKitTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFLiveKitTests
|
||||
|
||||
- (void)setUp {
|
||||
[super setUp];
|
||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testExample {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
||||
}
|
||||
|
||||
- (void)testPerformanceExample {
|
||||
// This is an example of a performance test case.
|
||||
[self measureBlock:^{
|
||||
// Put the code you want to measure the time of here.
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,10 +0,0 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios,'8.0'
|
||||
|
||||
target "LFLiveKit" do
|
||||
|
||||
pod 'CocoaAsyncSocket', '~> 7.4.1'
|
||||
pod 'pili-librtmp', '~> 1.0.2'
|
||||
pod 'LMGPUImage', '~> 0.1.9'
|
||||
pod 'YYDispatchQueuePool'
|
||||
end
|
||||
@@ -1,101 +1,143 @@
|
||||
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/)
|
||||

|
||||
|
||||
LFLiveKit
|
||||
|
||||
LFLiveKit IOS mobile phone push code,Default format support RTMP and FLV,At the same time, the structure is very easy to extend.
|
||||
**LFLiveKit is a opensource RTMP streaming SDK for iOS.**
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Background recording
|
||||
- [x] Support horizontal vertical recording
|
||||
- [x] Support Beauty Face With GPUImage
|
||||
- [x] Support H264+AAC Hardware Encoding
|
||||
- [x] Drop frames on bad network
|
||||
- [x] Dynamic switching rate
|
||||
- [x] Audio configuration
|
||||
- [x] Video configuration
|
||||
- [x] RTMP Transport
|
||||
- [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
|
||||
|
||||
#### CocoaPods
|
||||
# To integrate LFLiveKit into your Xcode project using CocoaPods, specify it in your Podfile:
|
||||
|
||||
Podfile
|
||||
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:
|
||||
# Then, run the following command:
|
||||
$ pod install
|
||||
|
||||
|
||||
Functional
|
||||
#### 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\>.
|
||||
|
||||
Background recording
|
||||
Support horizontal vertical recording
|
||||
GPUImage Beauty
|
||||
H264 Hard coding
|
||||
AAC Hard coding
|
||||
Weak network lost frame
|
||||
Dynamic switching rate
|
||||
Audio configuration
|
||||
Video configuration
|
||||
RTMP Transport
|
||||
Switch camera
|
||||
Audio Mute
|
||||
Support Send Buffer
|
||||
FLV package and send
|
||||
|
||||
|
||||
Architecture
|
||||
#### Manually
|
||||
|
||||
capture: LFAudioCapture and LFVideoCapture
|
||||
encode: LFHardwareAudioEncoder and LFHardwareVideoEncoder
|
||||
publish: LFStreamRtmpSocket LFStreamTcpSocket
|
||||
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
|
||||
* libstdc++
|
||||
|
||||
Usage
|
||||
|
||||
- (LFLiveSession*)session{
|
||||
if(!_session){
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration] liveType:LFLiveRTMP];
|
||||
_session.running = YES;
|
||||
_session.preView = self;
|
||||
}
|
||||
return _session;
|
||||
## Usage example
|
||||
|
||||
#### Objective-C
|
||||
```objc
|
||||
- (LFLiveSession*)session {
|
||||
if (!_session) {
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
_session.preView = self;
|
||||
_session.delegate = self;
|
||||
}
|
||||
|
||||
- (LFLiveSession*)session{
|
||||
if(!_session){
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(1280, 720);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.orientation = UIInterfaceOrientationLandscapeLeft;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration liveType:LFLiveRTMP];
|
||||
_session.running = YES;
|
||||
_session.preView = self;
|
||||
}
|
||||
return _session;
|
||||
}
|
||||
|
||||
return _session;
|
||||
}
|
||||
|
||||
- (void)startLive {
|
||||
LFLiveStreamInfo *streamInfo = [LFLiveStreamInfo new];
|
||||
streamInfo.url = @"your server rtmp url";
|
||||
[self.session startLive:streamInfo];
|
||||
}
|
||||
|
||||
- (void)stopLive {
|
||||
[self.session stopLive];
|
||||
|
||||
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;
|
||||
|
||||
License
|
||||
|
||||
LFLiveKit is released under the MIT license. See LICENSE for details.
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//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
|
||||
```swift
|
||||
// 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: - Event
|
||||
func startLive() -> Void {
|
||||
let stream = LFLiveStreamInfo()
|
||||
stream.url = "your server rtmp url";
|
||||
session.startLive(stream)
|
||||
}
|
||||
|
||||
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.
|
||||
* 2.2.4.3
|
||||
* CHANGE: modify bugs,support swift import.
|
||||
|
||||
|
||||
## License
|
||||
**LFLiveKit is released under the MIT license. See LICENSE for details.**
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,174 +7,160 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
57B42059E84CC681C5C99B68 /* libPods-LFLiveKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */; };
|
||||
840762F11D07C7D0000FD0BF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F01D07C7D0000FD0BF /* main.m */; };
|
||||
840762F41D07C7D0000FD0BF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F31D07C7D0000FD0BF /* AppDelegate.m */; };
|
||||
840762F71D07C7D0000FD0BF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 840762F61D07C7D0000FD0BF /* ViewController.m */; };
|
||||
840762FC1D07C7D0000FD0BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 840762FB1D07C7D0000FD0BF /* Assets.xcassets */; };
|
||||
840762FF1D07C7D0000FD0BF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */; };
|
||||
840763291D07C894000FD0BF /* UIControl+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763241D07C894000FD0BF /* UIControl+YYAdd.m */; };
|
||||
8407632A1D07C894000FD0BF /* UIView+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763261D07C894000FD0BF /* UIView+YYAdd.m */; };
|
||||
8407632B1D07C894000FD0BF /* LFLivePreview.m in Sources */ = {isa = PBXBuildFile; fileRef = 840763281D07C894000FD0BF /* LFLivePreview.m */; };
|
||||
840763351D07C899000FD0BF /* camra_beauty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632D1D07C899000FD0BF /* camra_beauty@2x.png */; };
|
||||
840763361D07C899000FD0BF /* camra_beauty@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632E1D07C899000FD0BF /* camra_beauty@3x.png */; };
|
||||
840763371D07C899000FD0BF /* camra_beauty_close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */; };
|
||||
840763381D07C899000FD0BF /* camra_beauty_close@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763301D07C899000FD0BF /* camra_beauty_close@3x.png */; };
|
||||
840763391D07C899000FD0BF /* camra_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763311D07C899000FD0BF /* camra_preview@2x.png */; };
|
||||
8407633A1D07C899000FD0BF /* camra_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763321D07C899000FD0BF /* camra_preview@3x.png */; };
|
||||
8407633B1D07C899000FD0BF /* close_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763331D07C899000FD0BF /* close_preview@2x.png */; };
|
||||
8407633C1D07C899000FD0BF /* close_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 840763341D07C899000FD0BF /* close_preview@3x.png */; };
|
||||
84D8B42B1D75778B00752B56 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B42A1D75778B00752B56 /* main.m */; };
|
||||
84D8B42E1D75778B00752B56 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B42D1D75778B00752B56 /* AppDelegate.m */; };
|
||||
84D8B4311D75778B00752B56 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B4301D75778B00752B56 /* ViewController.m */; };
|
||||
84D8B4341D75778B00752B56 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4321D75778B00752B56 /* Main.storyboard */; };
|
||||
84D8B4361D75778B00752B56 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4351D75778B00752B56 /* Assets.xcassets */; };
|
||||
84D8B4391D75778B00752B56 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4371D75778B00752B56 /* LaunchScreen.storyboard */; };
|
||||
84D8B44B1D75781200752B56 /* LFLivePreview.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B44A1D75781200752B56 /* LFLivePreview.m */; };
|
||||
84D8B45B1D75782700752B56 /* UIControl+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B44E1D75782700752B56 /* UIControl+YYAdd.m */; };
|
||||
84D8B45C1D75782700752B56 /* UIView+YYAdd.m in Sources */ = {isa = PBXBuildFile; fileRef = 84D8B4501D75782700752B56 /* UIView+YYAdd.m */; };
|
||||
84D8B45D1D75782700752B56 /* camra_beauty@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4521D75782700752B56 /* camra_beauty@2x.png */; };
|
||||
84D8B45E1D75782700752B56 /* camra_beauty@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4531D75782700752B56 /* camra_beauty@3x.png */; };
|
||||
84D8B45F1D75782700752B56 /* camra_beauty_close@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4541D75782700752B56 /* camra_beauty_close@2x.png */; };
|
||||
84D8B4601D75782700752B56 /* camra_beauty_close@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4551D75782700752B56 /* camra_beauty_close@3x.png */; };
|
||||
84D8B4611D75782700752B56 /* camra_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4561D75782700752B56 /* camra_preview@2x.png */; };
|
||||
84D8B4621D75782700752B56 /* camra_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4571D75782700752B56 /* camra_preview@3x.png */; };
|
||||
84D8B4631D75782700752B56 /* close_preview@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4581D75782700752B56 /* close_preview@2x.png */; };
|
||||
84D8B4641D75782700752B56 /* close_preview@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B4591D75782700752B56 /* close_preview@3x.png */; };
|
||||
84D8B4651D75782700752B56 /* ios-29x29.png in Resources */ = {isa = PBXBuildFile; fileRef = 84D8B45A1D75782700752B56 /* ios-29x29.png */; };
|
||||
84D8B4CF1D757F0700752B56 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 84D8B4CE1D757F0700752B56 /* libstdc++.tbd */; };
|
||||
BC8B37EEE1CEEF9B5614DC91 /* libPods-LFLiveKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B1CCEEE06FCFAF75D105A51 /* libPods-LFLiveKitDemo.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.release.xcconfig"; sourceTree = "<group>"; };
|
||||
5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LFLiveKitDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LFLiveKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
840762F01D07C7D0000FD0BF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
840762F21D07C7D0000FD0BF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
840762F31D07C7D0000FD0BF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
840762F51D07C7D0000FD0BF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
840762F61D07C7D0000FD0BF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
840762FB1D07C7D0000FD0BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
840762FE1D07C7D0000FD0BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
840763001D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
840763091D07C7D0000FD0BF /* LFLiveKitDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LFLiveKitDemoTests.m; sourceTree = "<group>"; };
|
||||
8407630B1D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
840763141D07C7D0000FD0BF /* LFLiveKitDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LFLiveKitDemoUITests.m; sourceTree = "<group>"; };
|
||||
840763161D07C7D0000FD0BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
840763231D07C894000FD0BF /* UIControl+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+YYAdd.h"; sourceTree = "<group>"; };
|
||||
840763241D07C894000FD0BF /* UIControl+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+YYAdd.m"; sourceTree = "<group>"; };
|
||||
840763251D07C894000FD0BF /* UIView+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+YYAdd.h"; sourceTree = "<group>"; };
|
||||
840763261D07C894000FD0BF /* UIView+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+YYAdd.m"; sourceTree = "<group>"; };
|
||||
840763271D07C894000FD0BF /* LFLivePreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLivePreview.h; sourceTree = "<group>"; };
|
||||
840763281D07C894000FD0BF /* LFLivePreview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLivePreview.m; sourceTree = "<group>"; };
|
||||
8407632D1D07C899000FD0BF /* camra_beauty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@2x.png"; sourceTree = "<group>"; };
|
||||
8407632E1D07C899000FD0BF /* camra_beauty@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@3x.png"; sourceTree = "<group>"; };
|
||||
8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@2x.png"; sourceTree = "<group>"; };
|
||||
840763301D07C899000FD0BF /* camra_beauty_close@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@3x.png"; sourceTree = "<group>"; };
|
||||
840763311D07C899000FD0BF /* camra_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@2x.png"; sourceTree = "<group>"; };
|
||||
840763321D07C899000FD0BF /* camra_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@3x.png"; sourceTree = "<group>"; };
|
||||
840763331D07C899000FD0BF /* close_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@2x.png"; sourceTree = "<group>"; };
|
||||
840763341D07C899000FD0BF /* close_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@3x.png"; sourceTree = "<group>"; };
|
||||
289A9C4510CD7EA6F4CE9897 /* 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>"; };
|
||||
5B1CCEEE06FCFAF75D105A51 /* libPods-LFLiveKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-LFLiveKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84D8B4261D75778B00752B56 /* LFLiveKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LFLiveKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
84D8B42A1D75778B00752B56 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
84D8B42C1D75778B00752B56 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
84D8B42D1D75778B00752B56 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
84D8B42F1D75778B00752B56 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
84D8B4301D75778B00752B56 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
84D8B4331D75778B00752B56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
84D8B4351D75778B00752B56 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
84D8B4381D75778B00752B56 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
84D8B43A1D75778B00752B56 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
84D8B4491D75781200752B56 /* LFLivePreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LFLivePreview.h; sourceTree = "<group>"; };
|
||||
84D8B44A1D75781200752B56 /* LFLivePreview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LFLivePreview.m; sourceTree = "<group>"; };
|
||||
84D8B44D1D75782700752B56 /* UIControl+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIControl+YYAdd.h"; sourceTree = "<group>"; };
|
||||
84D8B44E1D75782700752B56 /* UIControl+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIControl+YYAdd.m"; sourceTree = "<group>"; };
|
||||
84D8B44F1D75782700752B56 /* UIView+YYAdd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+YYAdd.h"; sourceTree = "<group>"; };
|
||||
84D8B4501D75782700752B56 /* UIView+YYAdd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+YYAdd.m"; sourceTree = "<group>"; };
|
||||
84D8B4521D75782700752B56 /* camra_beauty@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@2x.png"; sourceTree = "<group>"; };
|
||||
84D8B4531D75782700752B56 /* camra_beauty@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty@3x.png"; sourceTree = "<group>"; };
|
||||
84D8B4541D75782700752B56 /* camra_beauty_close@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@2x.png"; sourceTree = "<group>"; };
|
||||
84D8B4551D75782700752B56 /* camra_beauty_close@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_beauty_close@3x.png"; sourceTree = "<group>"; };
|
||||
84D8B4561D75782700752B56 /* camra_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@2x.png"; sourceTree = "<group>"; };
|
||||
84D8B4571D75782700752B56 /* camra_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "camra_preview@3x.png"; sourceTree = "<group>"; };
|
||||
84D8B4581D75782700752B56 /* close_preview@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@2x.png"; sourceTree = "<group>"; };
|
||||
84D8B4591D75782700752B56 /* close_preview@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "close_preview@3x.png"; sourceTree = "<group>"; };
|
||||
84D8B45A1D75782700752B56 /* ios-29x29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ios-29x29.png"; sourceTree = "<group>"; };
|
||||
84D8B4CE1D757F0700752B56 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
|
||||
96E1231310083A3881AD2AB6 /* 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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
840762E91D07C7D0000FD0BF /* Frameworks */ = {
|
||||
84D8B4231D75778B00752B56 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
57B42059E84CC681C5C99B68 /* libPods-LFLiveKitDemo.a in Frameworks */,
|
||||
84D8B4CF1D757F0700752B56 /* libstdc++.tbd in Frameworks */,
|
||||
BC8B37EEE1CEEF9B5614DC91 /* libPods-LFLiveKitDemo.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
713DA9EBCA308093C74917F9 /* Frameworks */ = {
|
||||
65E0CF98FF954863E543A0E1 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5D506B5639A1D45519536773 /* libPods-LFLiveKitDemo.a */,
|
||||
5B1CCEEE06FCFAF75D105A51 /* libPods-LFLiveKitDemo.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840762E31D07C7D0000FD0BF = {
|
||||
84D8B41D1D75778B00752B56 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840762EE1D07C7D0000FD0BF /* LFLiveKitDemo */,
|
||||
840763081D07C7D0000FD0BF /* LFLiveKitDemoTests */,
|
||||
840763131D07C7D0000FD0BF /* LFLiveKitDemoUITests */,
|
||||
840762ED1D07C7D0000FD0BF /* Products */,
|
||||
9BA1F10CECEAF692D0035AED /* Pods */,
|
||||
713DA9EBCA308093C74917F9 /* Frameworks */,
|
||||
84D8B4CE1D757F0700752B56 /* libstdc++.tbd */,
|
||||
84D8B4281D75778B00752B56 /* LFLiveKitDemo */,
|
||||
84D8B4271D75778B00752B56 /* Products */,
|
||||
F3E359B8A7561F963C47A62F /* Pods */,
|
||||
65E0CF98FF954863E543A0E1 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840762ED1D07C7D0000FD0BF /* Products */ = {
|
||||
84D8B4271D75778B00752B56 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */,
|
||||
84D8B4261D75778B00752B56 /* LFLiveKitDemo.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840762EE1D07C7D0000FD0BF /* LFLiveKitDemo */ = {
|
||||
84D8B4281D75778B00752B56 /* LFLiveKitDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840763221D07C894000FD0BF /* category */,
|
||||
840763271D07C894000FD0BF /* LFLivePreview.h */,
|
||||
840763281D07C894000FD0BF /* LFLivePreview.m */,
|
||||
840762F21D07C7D0000FD0BF /* AppDelegate.h */,
|
||||
840762F31D07C7D0000FD0BF /* AppDelegate.m */,
|
||||
840762F51D07C7D0000FD0BF /* ViewController.h */,
|
||||
840762F61D07C7D0000FD0BF /* ViewController.m */,
|
||||
840762FB1D07C7D0000FD0BF /* Assets.xcassets */,
|
||||
840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */,
|
||||
840763001D07C7D0000FD0BF /* Info.plist */,
|
||||
840762EF1D07C7D0000FD0BF /* Supporting Files */,
|
||||
84D8B42C1D75778B00752B56 /* AppDelegate.h */,
|
||||
84D8B42D1D75778B00752B56 /* AppDelegate.m */,
|
||||
84D8B42F1D75778B00752B56 /* ViewController.h */,
|
||||
84D8B4301D75778B00752B56 /* ViewController.m */,
|
||||
84D8B4491D75781200752B56 /* LFLivePreview.h */,
|
||||
84D8B44A1D75781200752B56 /* LFLivePreview.m */,
|
||||
84D8B44C1D75782700752B56 /* category */,
|
||||
84D8B4511D75782700752B56 /* images */,
|
||||
84D8B4321D75778B00752B56 /* Main.storyboard */,
|
||||
84D8B4351D75778B00752B56 /* Assets.xcassets */,
|
||||
84D8B4371D75778B00752B56 /* LaunchScreen.storyboard */,
|
||||
84D8B43A1D75778B00752B56 /* Info.plist */,
|
||||
84D8B4291D75778B00752B56 /* Supporting Files */,
|
||||
);
|
||||
path = LFLiveKitDemo;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840762EF1D07C7D0000FD0BF /* Supporting Files */ = {
|
||||
84D8B4291D75778B00752B56 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8407632C1D07C899000FD0BF /* images */,
|
||||
840762F01D07C7D0000FD0BF /* main.m */,
|
||||
84D8B42A1D75778B00752B56 /* main.m */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840763081D07C7D0000FD0BF /* LFLiveKitDemoTests */ = {
|
||||
84D8B44C1D75782700752B56 /* category */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840763091D07C7D0000FD0BF /* LFLiveKitDemoTests.m */,
|
||||
8407630B1D07C7D0000FD0BF /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKitDemoTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840763131D07C7D0000FD0BF /* LFLiveKitDemoUITests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840763141D07C7D0000FD0BF /* LFLiveKitDemoUITests.m */,
|
||||
840763161D07C7D0000FD0BF /* Info.plist */,
|
||||
);
|
||||
path = LFLiveKitDemoUITests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
840763221D07C894000FD0BF /* category */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
840763231D07C894000FD0BF /* UIControl+YYAdd.h */,
|
||||
840763241D07C894000FD0BF /* UIControl+YYAdd.m */,
|
||||
840763251D07C894000FD0BF /* UIView+YYAdd.h */,
|
||||
840763261D07C894000FD0BF /* UIView+YYAdd.m */,
|
||||
84D8B44D1D75782700752B56 /* UIControl+YYAdd.h */,
|
||||
84D8B44E1D75782700752B56 /* UIControl+YYAdd.m */,
|
||||
84D8B44F1D75782700752B56 /* UIView+YYAdd.h */,
|
||||
84D8B4501D75782700752B56 /* UIView+YYAdd.m */,
|
||||
);
|
||||
path = category;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8407632C1D07C899000FD0BF /* images */ = {
|
||||
84D8B4511D75782700752B56 /* images */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8407632D1D07C899000FD0BF /* camra_beauty@2x.png */,
|
||||
8407632E1D07C899000FD0BF /* camra_beauty@3x.png */,
|
||||
8407632F1D07C899000FD0BF /* camra_beauty_close@2x.png */,
|
||||
840763301D07C899000FD0BF /* camra_beauty_close@3x.png */,
|
||||
840763311D07C899000FD0BF /* camra_preview@2x.png */,
|
||||
840763321D07C899000FD0BF /* camra_preview@3x.png */,
|
||||
840763331D07C899000FD0BF /* close_preview@2x.png */,
|
||||
840763341D07C899000FD0BF /* close_preview@3x.png */,
|
||||
84D8B4521D75782700752B56 /* camra_beauty@2x.png */,
|
||||
84D8B4531D75782700752B56 /* camra_beauty@3x.png */,
|
||||
84D8B4541D75782700752B56 /* camra_beauty_close@2x.png */,
|
||||
84D8B4551D75782700752B56 /* camra_beauty_close@3x.png */,
|
||||
84D8B4561D75782700752B56 /* camra_preview@2x.png */,
|
||||
84D8B4571D75782700752B56 /* camra_preview@3x.png */,
|
||||
84D8B4581D75782700752B56 /* close_preview@2x.png */,
|
||||
84D8B4591D75782700752B56 /* close_preview@3x.png */,
|
||||
84D8B45A1D75782700752B56 /* ios-29x29.png */,
|
||||
);
|
||||
path = images;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9BA1F10CECEAF692D0035AED /* Pods */ = {
|
||||
F3E359B8A7561F963C47A62F /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */,
|
||||
195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */,
|
||||
289A9C4510CD7EA6F4CE9897 /* Pods-LFLiveKitDemo.debug.xcconfig */,
|
||||
96E1231310083A3881AD2AB6 /* Pods-LFLiveKitDemo.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
@@ -182,16 +168,16 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
840762EB1D07C7D0000FD0BF /* LFLiveKitDemo */ = {
|
||||
84D8B4251D75778B00752B56 /* LFLiveKitDemo */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 840763191D07C7D0000FD0BF /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
|
||||
buildConfigurationList = 84D8B43D1D75778B00752B56 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */;
|
||||
buildPhases = (
|
||||
7E4C7C5523618A0595228010 /* 📦 Check Pods Manifest.lock */,
|
||||
840762E81D07C7D0000FD0BF /* Sources */,
|
||||
840762E91D07C7D0000FD0BF /* Frameworks */,
|
||||
840762EA1D07C7D0000FD0BF /* Resources */,
|
||||
E4007BB7D4B0E165011BF22F /* 📦 Embed Pods Frameworks */,
|
||||
64FCFF97E6544B1C8F282394 /* 📦 Copy Pods Resources */,
|
||||
A819C09CC049A57DC5C97E12 /* 📦 Check Pods Manifest.lock */,
|
||||
84D8B4221D75778B00752B56 /* Sources */,
|
||||
84D8B4231D75778B00752B56 /* Frameworks */,
|
||||
84D8B4241D75778B00752B56 /* Resources */,
|
||||
883533331BE4DCC0DB5075CF /* 📦 Embed Pods Frameworks */,
|
||||
4CC4C37B93D109913E475307 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -199,29 +185,25 @@
|
||||
);
|
||||
name = LFLiveKitDemo;
|
||||
productName = LFLiveKitDemo;
|
||||
productReference = 840762EC1D07C7D0000FD0BF /* LFLiveKitDemo.app */;
|
||||
productReference = 84D8B4261D75778B00752B56 /* LFLiveKitDemo.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
840762E41D07C7D0000FD0BF /* Project object */ = {
|
||||
84D8B41E1D75778B00752B56 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0730;
|
||||
ORGANIZATIONNAME = admin;
|
||||
TargetAttributes = {
|
||||
840762EB1D07C7D0000FD0BF = {
|
||||
CreatedOnToolsVersion = 7.3;
|
||||
SystemCapabilities = {
|
||||
com.apple.BackgroundModes = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
84D8B4251D75778B00752B56 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = G497YX6CBT;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 840762E71D07C7D0000FD0BF /* Build configuration list for PBXProject "LFLiveKitDemo" */;
|
||||
buildConfigurationList = 84D8B4211D75778B00752B56 /* Build configuration list for PBXProject "LFLiveKitDemo" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
@@ -229,38 +211,40 @@
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 840762E31D07C7D0000FD0BF;
|
||||
productRefGroup = 840762ED1D07C7D0000FD0BF /* Products */;
|
||||
mainGroup = 84D8B41D1D75778B00752B56;
|
||||
productRefGroup = 84D8B4271D75778B00752B56 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
840762EB1D07C7D0000FD0BF /* LFLiveKitDemo */,
|
||||
84D8B4251D75778B00752B56 /* LFLiveKitDemo */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
840762EA1D07C7D0000FD0BF /* Resources */ = {
|
||||
84D8B4241D75778B00752B56 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
840763371D07C899000FD0BF /* camra_beauty_close@2x.png in Resources */,
|
||||
840762FF1D07C7D0000FD0BF /* LaunchScreen.storyboard in Resources */,
|
||||
840763351D07C899000FD0BF /* camra_beauty@2x.png in Resources */,
|
||||
840762FC1D07C7D0000FD0BF /* Assets.xcassets in Resources */,
|
||||
8407633A1D07C899000FD0BF /* camra_preview@3x.png in Resources */,
|
||||
840763381D07C899000FD0BF /* camra_beauty_close@3x.png in Resources */,
|
||||
8407633C1D07C899000FD0BF /* close_preview@3x.png in Resources */,
|
||||
8407633B1D07C899000FD0BF /* close_preview@2x.png in Resources */,
|
||||
840763391D07C899000FD0BF /* camra_preview@2x.png in Resources */,
|
||||
840763361D07C899000FD0BF /* camra_beauty@3x.png in Resources */,
|
||||
84D8B45F1D75782700752B56 /* camra_beauty_close@2x.png in Resources */,
|
||||
84D8B4391D75778B00752B56 /* LaunchScreen.storyboard in Resources */,
|
||||
84D8B45D1D75782700752B56 /* camra_beauty@2x.png in Resources */,
|
||||
84D8B4361D75778B00752B56 /* Assets.xcassets in Resources */,
|
||||
84D8B4621D75782700752B56 /* camra_preview@3x.png in Resources */,
|
||||
84D8B4601D75782700752B56 /* camra_beauty_close@3x.png in Resources */,
|
||||
84D8B4651D75782700752B56 /* ios-29x29.png in Resources */,
|
||||
84D8B4641D75782700752B56 /* close_preview@3x.png in Resources */,
|
||||
84D8B4631D75782700752B56 /* close_preview@2x.png in Resources */,
|
||||
84D8B4341D75778B00752B56 /* Main.storyboard in Resources */,
|
||||
84D8B4611D75782700752B56 /* camra_preview@2x.png in Resources */,
|
||||
84D8B45E1D75782700752B56 /* camra_beauty@3x.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
64FCFF97E6544B1C8F282394 /* 📦 Copy Pods Resources */ = {
|
||||
4CC4C37B93D109913E475307 /* 📦 Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -275,22 +259,7 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
7E4C7C5523618A0595228010 /* 📦 Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
E4007BB7D4B0E165011BF22F /* 📦 Embed Pods Frameworks */ = {
|
||||
883533331BE4DCC0DB5075CF /* 📦 Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
@@ -305,29 +274,52 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-LFLiveKitDemo/Pods-LFLiveKitDemo-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
A819C09CC049A57DC5C97E12 /* 📦 Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "📦 Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
840762E81D07C7D0000FD0BF /* Sources */ = {
|
||||
84D8B4221D75778B00752B56 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8407632B1D07C894000FD0BF /* LFLivePreview.m in Sources */,
|
||||
840762F71D07C7D0000FD0BF /* ViewController.m in Sources */,
|
||||
840763291D07C894000FD0BF /* UIControl+YYAdd.m in Sources */,
|
||||
840762F41D07C7D0000FD0BF /* AppDelegate.m in Sources */,
|
||||
8407632A1D07C894000FD0BF /* UIView+YYAdd.m in Sources */,
|
||||
840762F11D07C7D0000FD0BF /* main.m in Sources */,
|
||||
84D8B45B1D75782700752B56 /* UIControl+YYAdd.m in Sources */,
|
||||
84D8B4311D75778B00752B56 /* ViewController.m in Sources */,
|
||||
84D8B45C1D75782700752B56 /* UIView+YYAdd.m in Sources */,
|
||||
84D8B42E1D75778B00752B56 /* AppDelegate.m in Sources */,
|
||||
84D8B44B1D75781200752B56 /* LFLivePreview.m in Sources */,
|
||||
84D8B42B1D75778B00752B56 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
840762FD1D07C7D0000FD0BF /* LaunchScreen.storyboard */ = {
|
||||
84D8B4321D75778B00752B56 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
840762FE1D07C7D0000FD0BF /* Base */,
|
||||
84D8B4331D75778B00752B56 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
84D8B4371D75778B00752B56 /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
84D8B4381D75778B00752B56 /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
@@ -335,7 +327,7 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
840763171D07C7D0000FD0BF /* Debug */ = {
|
||||
84D8B43B1D75778B00752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
@@ -372,15 +364,14 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
840763181D07C7D0000FD0BF /* Release */ = {
|
||||
84D8B43C1D75778B00752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
@@ -411,38 +402,45 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
8407631A1D07C7D0000FD0BF /* Debug */ = {
|
||||
84D8B43E1D75778B00752B56 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7FAA55DD93CD7AB58E7A977A /* Pods-LFLiveKitDemo.debug.xcconfig */;
|
||||
baseConfigurationReference = 289A9C4510CD7EA6F4CE9897 /* Pods-LFLiveKitDemo.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ENABLE_BITCODE = NO;
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitDemo;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LaiFeng;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
8407631B1D07C7D0000FD0BF /* Release */ = {
|
||||
84D8B43F1D75778B00752B56 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 195672426061368F86F1F4FA /* Pods-LFLiveKitDemo.release.xcconfig */;
|
||||
baseConfigurationReference = 96E1231310083A3881AD2AB6 /* Pods-LFLiveKitDemo.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ENABLE_BITCODE = NO;
|
||||
DEVELOPMENT_TEAM = G497YX6CBT;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = LFLiveKitDemo/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LFLiveKit.LFLiveKitDemo;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.youku.LaiFeng;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
};
|
||||
name = Release;
|
||||
@@ -450,25 +448,25 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
840762E71D07C7D0000FD0BF /* Build configuration list for PBXProject "LFLiveKitDemo" */ = {
|
||||
84D8B4211D75778B00752B56 /* Build configuration list for PBXProject "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
840763171D07C7D0000FD0BF /* Debug */,
|
||||
840763181D07C7D0000FD0BF /* Release */,
|
||||
84D8B43B1D75778B00752B56 /* Debug */,
|
||||
84D8B43C1D75778B00752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
840763191D07C7D0000FD0BF /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */ = {
|
||||
84D8B43D1D75778B00752B56 /* Build configuration list for PBXNativeTarget "LFLiveKitDemo" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
8407631A1D07C7D0000FD0BF /* Debug */,
|
||||
8407631B1D07C7D0000FD0BF /* Release */,
|
||||
84D8B43E1D75778B00752B56 /* Debug */,
|
||||
84D8B43F1D75778B00752B56 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 840762E41D07C7D0000FD0BF /* Project object */;
|
||||
rootObject = 84D8B41E1D75778B00752B56 /* Project object */;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// AppDelegate.h
|
||||
// LFLiveKitDemo
|
||||
//
|
||||
// Created by admin on 16/6/8.
|
||||
// Created by admin on 16/8/30.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// AppDelegate.m
|
||||
// LFLiveKitDemo
|
||||
//
|
||||
// Created by admin on 16/6/8.
|
||||
// Created by admin on 16/8/30.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@interface AppDelegate ()
|
||||
|
||||
@@ -18,17 +17,9 @@
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||
// Override point for customization after application launch.
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
// UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
|
||||
// nav.navigationBarHidden = YES;
|
||||
self.window.rootViewController = [[ViewController alloc] init];
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||
@@ -29,36 +29,6 @@
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "76x76",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>cameraDesciption</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>microphoneDesciption</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -10,5 +10,4 @@
|
||||
|
||||
@interface LFLivePreview : UIView
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,374 @@
|
||||
//
|
||||
// LFLivePreview.m
|
||||
// LFLiveKit
|
||||
//
|
||||
// Created by 倾慕 on 16/5/2.
|
||||
// Copyright © 2016年 live Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "LFLivePreview.h"
|
||||
#import "UIControl+YYAdd.h"
|
||||
#import "UIView+YYAdd.h"
|
||||
#import "LFLiveKit.h"
|
||||
|
||||
inline static NSString *formatedSpeed(float bytes, float elapsed_milli) {
|
||||
if (elapsed_milli <= 0) {
|
||||
return @"N/A";
|
||||
}
|
||||
|
||||
if (bytes <= 0) {
|
||||
return @"0 KB/s";
|
||||
}
|
||||
|
||||
float bytes_per_sec = ((float)bytes) * 1000.f / elapsed_milli;
|
||||
if (bytes_per_sec >= 1000 * 1000) {
|
||||
return [NSString stringWithFormat:@"%.2f MB/s", ((float)bytes_per_sec) / 1000 / 1000];
|
||||
} else if (bytes_per_sec >= 1000) {
|
||||
return [NSString stringWithFormat:@"%.1f KB/s", ((float)bytes_per_sec) / 1000];
|
||||
} else {
|
||||
return [NSString stringWithFormat:@"%ld B/s", (long)bytes_per_sec];
|
||||
}
|
||||
}
|
||||
|
||||
@interface LFLivePreview ()<LFLiveSessionDelegate>
|
||||
|
||||
@property (nonatomic, strong) UIButton *beautyButton;
|
||||
@property (nonatomic, strong) UIButton *cameraButton;
|
||||
@property (nonatomic, strong) UIButton *closeButton;
|
||||
@property (nonatomic, strong) UIButton *startLiveButton;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@property (nonatomic, strong) LFLiveDebug *debugInfo;
|
||||
@property (nonatomic, strong) LFLiveSession *session;
|
||||
@property (nonatomic, strong) UILabel *stateLabel;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LFLivePreview
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
[self requestAccessForVideo];
|
||||
[self requestAccessForAudio];
|
||||
[self addSubview:self.containerView];
|
||||
[self.containerView addSubview:self.stateLabel];
|
||||
[self.containerView addSubview:self.closeButton];
|
||||
[self.containerView addSubview:self.cameraButton];
|
||||
[self.containerView addSubview:self.beautyButton];
|
||||
[self.containerView addSubview:self.startLiveButton];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -- Public Method
|
||||
- (void)requestAccessForVideo {
|
||||
__weak typeof(self) _self = self;
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
|
||||
switch (status) {
|
||||
case AVAuthorizationStatusNotDetermined: {
|
||||
// 许可对话没有出现,发起授权许可
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
if (granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_self.session setRunning:YES];
|
||||
});
|
||||
}
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusAuthorized: {
|
||||
// 已经开启授权,可继续
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_self.session setRunning:YES];
|
||||
});
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusDenied:
|
||||
case AVAuthorizationStatusRestricted:
|
||||
// 用户明确地拒绝授权,或者相机设备无法访问
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestAccessForAudio {
|
||||
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
|
||||
switch (status) {
|
||||
case AVAuthorizationStatusNotDetermined: {
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
|
||||
}];
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusAuthorized: {
|
||||
break;
|
||||
}
|
||||
case AVAuthorizationStatusDenied:
|
||||
case AVAuthorizationStatusRestricted:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -- LFStreamingSessionDelegate
|
||||
/** live status changed will callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state {
|
||||
NSLog(@"liveStateDidChange: %ld", state);
|
||||
switch (state) {
|
||||
case LFLiveReady:
|
||||
_stateLabel.text = @"未连接";
|
||||
break;
|
||||
case LFLivePending:
|
||||
_stateLabel.text = @"连接中";
|
||||
break;
|
||||
case LFLiveStart:
|
||||
_stateLabel.text = @"已连接";
|
||||
break;
|
||||
case LFLiveError:
|
||||
_stateLabel.text = @"连接错误";
|
||||
break;
|
||||
case LFLiveStop:
|
||||
_stateLabel.text = @"未连接";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** live debug info callback */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug *)debugInfo {
|
||||
NSLog(@"debugInfo uploadSpeed: %@", formatedSpeed(debugInfo.currentBandwidth, debugInfo.elapsedMilli));
|
||||
}
|
||||
|
||||
/** callback socket errorcode */
|
||||
- (void)liveSession:(nullable LFLiveSession *)session errorCode:(LFLiveSocketErrorCode)errorCode {
|
||||
NSLog(@"errorCode: %ld", errorCode);
|
||||
}
|
||||
|
||||
#pragma mark -- Getter Setter
|
||||
- (LFLiveSession *)session {
|
||||
if (!_session) {
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
/** 发现大家有不会用横屏的请注意啦,横屏需要在ViewController supportedInterfaceOrientations修改方向 默认竖屏 ****/
|
||||
|
||||
|
||||
/*** 默认分辨率368 * 640 音频:44.1 iphone6以上48 双声道 方向竖屏 ***/
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(640, 360);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 24;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 48;
|
||||
videoConfiguration.outputImageOrientation = UIInterfaceOrientationLandscapeLeft;
|
||||
videoConfiguration.autorotate = NO;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfiguration] videoConfiguration:videoConfiguration captureType:LFLiveCaptureDefaultMask];
|
||||
|
||||
/** 自己定制单声道 */
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 1;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_64Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
*/
|
||||
|
||||
/** 自己定制高质量音频96K */
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:[LFLiveVideoConfiguration defaultConfiguration]];
|
||||
*/
|
||||
|
||||
/** 自己定制高质量音频96K 分辨率设置为540*960 方向竖屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_96Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(540, 960);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 24;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 48;
|
||||
videoConfiguration.orientation = UIInterfaceOrientationPortrait;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset540x960;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
|
||||
/** 自己定制高质量音频128K 分辨率设置为720*1280 方向竖屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(720, 1280);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.landscape = NO;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset360x640;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
|
||||
/** 自己定制高质量音频128K 分辨率设置为720*1280 方向横屏 */
|
||||
|
||||
/*
|
||||
LFLiveAudioConfiguration *audioConfiguration = [LFLiveAudioConfiguration new];
|
||||
audioConfiguration.numberOfChannels = 2;
|
||||
audioConfiguration.audioBitrate = LFLiveAudioBitRate_128Kbps;
|
||||
audioConfiguration.audioSampleRate = LFLiveAudioSampleRate_44100Hz;
|
||||
|
||||
LFLiveVideoConfiguration *videoConfiguration = [LFLiveVideoConfiguration new];
|
||||
videoConfiguration.videoSize = CGSizeMake(1280, 720);
|
||||
videoConfiguration.videoBitRate = 800*1024;
|
||||
videoConfiguration.videoMaxBitRate = 1000*1024;
|
||||
videoConfiguration.videoMinBitRate = 500*1024;
|
||||
videoConfiguration.videoFrameRate = 15;
|
||||
videoConfiguration.videoMaxKeyframeInterval = 30;
|
||||
videoConfiguration.landscape = YES;
|
||||
videoConfiguration.sessionPreset = LFCaptureSessionPreset720x1280;
|
||||
|
||||
_session = [[LFLiveSession alloc] initWithAudioConfiguration:audioConfiguration videoConfiguration:videoConfiguration];
|
||||
*/
|
||||
|
||||
_session.delegate = self;
|
||||
_session.showDebugInfo = NO;
|
||||
_session.preView = self;
|
||||
|
||||
/*本地存储*/
|
||||
// _session.saveLocalVideo = YES;
|
||||
// NSString *pathToMovie = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/Movie.mp4"];
|
||||
// unlink([pathToMovie UTF8String]); // If a file already exists, AVAssetWriter won't let you record new frames, so delete the old movie
|
||||
// NSURL *movieURL = [NSURL fileURLWithPath:pathToMovie];
|
||||
// _session.saveLocalVideoPath = movieURL;
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
- (UIView *)containerView {
|
||||
if (!_containerView) {
|
||||
_containerView = [UIView new];
|
||||
_containerView.frame = self.bounds;
|
||||
_containerView.backgroundColor = [UIColor clearColor];
|
||||
_containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
}
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (UILabel *)stateLabel {
|
||||
if (!_stateLabel) {
|
||||
_stateLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 80, 40)];
|
||||
_stateLabel.text = @"未连接";
|
||||
_stateLabel.textColor = [UIColor whiteColor];
|
||||
_stateLabel.font = [UIFont boldSystemFontOfSize:14.f];
|
||||
}
|
||||
return _stateLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)closeButton {
|
||||
if (!_closeButton) {
|
||||
_closeButton = [UIButton new];
|
||||
_closeButton.size = CGSizeMake(44, 44);
|
||||
_closeButton.left = self.width - 10 - _closeButton.width;
|
||||
_closeButton.top = 20;
|
||||
[_closeButton setImage:[UIImage imageNamed:@"close_preview"] forState:UIControlStateNormal];
|
||||
_closeButton.exclusiveTouch = YES;
|
||||
[_closeButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
|
||||
}];
|
||||
}
|
||||
return _closeButton;
|
||||
}
|
||||
|
||||
- (UIButton *)cameraButton {
|
||||
if (!_cameraButton) {
|
||||
_cameraButton = [UIButton new];
|
||||
_cameraButton.size = CGSizeMake(44, 44);
|
||||
_cameraButton.origin = CGPointMake(_closeButton.left - 10 - _cameraButton.width, 20);
|
||||
[_cameraButton setImage:[UIImage imageNamed:@"camra_preview"] forState:UIControlStateNormal];
|
||||
_cameraButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_cameraButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
AVCaptureDevicePosition devicePositon = _self.session.captureDevicePosition;
|
||||
_self.session.captureDevicePosition = (devicePositon == AVCaptureDevicePositionBack) ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
|
||||
}];
|
||||
}
|
||||
return _cameraButton;
|
||||
}
|
||||
|
||||
- (UIButton *)beautyButton {
|
||||
if (!_beautyButton) {
|
||||
_beautyButton = [UIButton new];
|
||||
_beautyButton.size = CGSizeMake(44, 44);
|
||||
_beautyButton.origin = CGPointMake(_cameraButton.left - 10 - _beautyButton.width, 20);
|
||||
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty"] forState:UIControlStateNormal];
|
||||
[_beautyButton setImage:[UIImage imageNamed:@"camra_beauty_close"] forState:UIControlStateSelected];
|
||||
_beautyButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_beautyButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
_self.session.beautyFace = !_self.session.beautyFace;
|
||||
_self.beautyButton.selected = !_self.session.beautyFace;
|
||||
}];
|
||||
}
|
||||
return _beautyButton;
|
||||
}
|
||||
|
||||
- (UIButton *)startLiveButton {
|
||||
if (!_startLiveButton) {
|
||||
_startLiveButton = [UIButton new];
|
||||
_startLiveButton.size = CGSizeMake(self.width - 60, 44);
|
||||
_startLiveButton.left = 30;
|
||||
_startLiveButton.bottom = self.height - 50;
|
||||
_startLiveButton.layer.cornerRadius = _startLiveButton.height/2;
|
||||
[_startLiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||
[_startLiveButton.titleLabel setFont:[UIFont systemFontOfSize:16]];
|
||||
[_startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
|
||||
[_startLiveButton setBackgroundColor:[UIColor colorWithRed:50 green:32 blue:245 alpha:1]];
|
||||
_startLiveButton.exclusiveTouch = YES;
|
||||
__weak typeof(self) _self = self;
|
||||
[_startLiveButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {
|
||||
_self.startLiveButton.selected = !_self.startLiveButton.selected;
|
||||
if (_self.startLiveButton.selected) {
|
||||
[_self.startLiveButton setTitle:@"结束直播" forState:UIControlStateNormal];
|
||||
LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
|
||||
stream.url = @"rtmp://live.hkstv.hk.lxdns.com:1935/live/stream153";
|
||||
[_self.session startLive:stream];
|
||||
} else {
|
||||
[_self.startLiveButton setTitle:@"开始直播" forState:UIControlStateNormal];
|
||||
[_self.session stopLive];
|
||||
}
|
||||
}];
|
||||
}
|
||||
return _startLiveButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ViewController.h
|
||||
// LFLiveKitDemo
|
||||
//
|
||||
// Created by admin on 16/6/8.
|
||||
// Created by admin on 16/8/30.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// LFLiveKitDemo
|
||||
//
|
||||
// Created by admin on 16/8/30.
|
||||
// Copyright © 2016年 admin. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "LFLivePreview.h"
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view, typically from a nib.
|
||||
[self.view addSubview:[[LFLivePreview alloc] initWithFrame:self.view.bounds]];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskLandscape;
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -17,13 +17,13 @@
|
||||
Create a snapshot image of the complete view hierarchy.
|
||||
This method should be called in main thread.
|
||||
*/
|
||||
- (UIImage *)snapshotImage;
|
||||
- (nullable UIImage *)snapshotImage;
|
||||
|
||||
/**
|
||||
Create a snapshot PDF of the complete view hierarchy.
|
||||
This method should be called in main thread.
|
||||
*/
|
||||
- (NSData *)snapshotPDF;
|
||||
- (nullable NSData *)snapshotPDF;
|
||||
|
||||
/**
|
||||
Shortcut to set the view.layer's shadow
|
||||
@@ -32,13 +32,13 @@
|
||||
@param offset Shadow offset
|
||||
@param radius Shadow radius
|
||||
*/
|
||||
- (void)setLayerShadow:(UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
|
||||
- (void)setLayerShadow:(nullable UIColor*)color offset:(CGSize)offset radius:(CGFloat)radius;
|
||||
/**
|
||||
* 设置阴影 郭liyuan+
|
||||
*/
|
||||
- (void) makeInsetShadow;
|
||||
- (void) makeInsetShadowWithRadius:(float)radius Alpha:(float)alpha;
|
||||
- (void) makeInsetShadowWithRadius:(float)radius Color:(UIColor *)color Directions:(NSArray *)directions;
|
||||
- (void) makeInsetShadowWithRadius:(float)radius Color:(nullable UIColor *)color Directions:(nullable NSArray *)directions;
|
||||
|
||||
/**
|
||||
Remove all subviews.
|
||||
@@ -50,7 +50,7 @@
|
||||
/**
|
||||
Returns the view's view controller (may be nil).
|
||||
*/
|
||||
@property (nonatomic, readonly) UIViewController *viewController;
|
||||
@property (nonatomic, readonly,nullable) UIViewController *viewController;
|
||||
|
||||
@property (nonatomic) CGFloat left; ///< Shortcut for frame.origin.x.
|
||||
@property (nonatomic) CGFloat top; ///< Shortcut for frame.origin.y
|
||||
@@ -78,7 +78,7 @@
|
||||
If view is nil, this method instead converts to window base coordinates.
|
||||
@return The point converted to the coordinate system of view.
|
||||
*/
|
||||
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(UIView *)view;
|
||||
- (CGPoint)convertPoint:(CGPoint)point toViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a point from the coordinate system of a given view or window to that of the receiver.
|
||||
@@ -88,7 +88,7 @@
|
||||
If view is nil, this method instead converts from window base coordinates.
|
||||
@return The point converted to the local coordinate system (bounds) of the receiver.
|
||||
*/
|
||||
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(UIView *)view;
|
||||
- (CGPoint)convertPoint:(CGPoint)point fromViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a rectangle from the receiver's coordinate system to that of another view or window.
|
||||
@@ -97,7 +97,7 @@
|
||||
@param view The view or window that is the target of the conversion operation. If view is nil, this method instead converts to window base coordinates.
|
||||
@return The converted rectangle.
|
||||
*/
|
||||
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(UIView *)view;
|
||||
- (CGRect)convertRect:(CGRect)rect toViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
Converts a rectangle from the coordinate system of another view or window to that of the receiver.
|
||||
@@ -107,7 +107,7 @@
|
||||
If view is nil, this method instead converts from window base coordinates.
|
||||
@return The converted rectangle.
|
||||
*/
|
||||
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(UIView *)view;
|
||||
- (CGRect)convertRect:(CGRect)rect fromViewOrWindow:(nullable UIView *)view;
|
||||
|
||||
/**
|
||||
* 返回响应者链上的任意Objc
|
||||
@@ -128,5 +128,5 @@
|
||||
- (void)removeAllGesturesWithSubViews;
|
||||
|
||||
/// 在 block 内禁用动画
|
||||
+ (void)disableAnimationWithBlock:(void (^)(void))block;
|
||||
+ (void)disableAnimationWithBlock:(nullable void (^)(void))block;
|
||||
@end
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |